c 指標教程 用簡單鍊錶練習指標

2022-04-12 02:44:39 字數 3898 閱讀 3707

鍊錶模板題,本題目下\(list\)的教學已經很多了,我來講點更加基礎的\(\rightarrow\)

寫在前面:本教程假設讀者基本了解指標的定義以及使用,能會用指標寫a+b就行

寫主席樹,平衡樹時我們會發現陣列套陣列的寫法十分難受

...

int sub=nd[nd[y].ls].sum-nd[nd[x].ls].sum;

...ch[old_root][opr]=ch[x][opr^1];

f[ch[old_root][opr]]=old_root;

...

我願稱其為"後 置 性 定 語 從 句"

這種樣子寫起來很不舒服,實際上,指標才是最適合寫這種資料結構的"法寶",

本題是極其簡單的鍊錶的模板題,正好方便我們練習用指標處理資料結構.

我們首先需要知道結構體本身的一些性質:

在結構體\(node\)中:

struct node

...};

我們知道前兩行是定義了結構體內的\(int\)變數和兩個\(node\)型別的指標,所要指向的便是該元素的前乙個元素\(pre\)和後乙個元素\(next\)(這裡就是乙個簡單的定義,不用管)

第三行則是乙個簡單的"建構函式",格式如下(同樣以結構體\(node\)為例,故函式名為\(node\)):

struct node

};

意思是把結構體內的變數\(a,b,c\)與函式傳入的引數\(a,b,c\)一一對應賦值,再執行函式內的操作

若是以結構體\(node\)定義了結構體變數,但是並沒用函式對該變數進行賦值,只是單單定義了該變數,則該變數內對應變數就是我們自己定義的預設值,也就是自己在函式傳參時初始化的那許多"乙個數"

同時我們需要知道,這個建構函式返回的是乙個\(node\)型別的結構體變數,也就是說,這個函式寫出來就可以當做變數使了,同時我們知道:

int *a=new int;
這個操作可以使得新定義的指標得到了乙個新的\(int\)位址,進一步的,我們去了解這樣一種操作:

node *root=new node(a,b,c);
這種操作的結果是讓\(root\)指標指向乙個內容為\(a,b,c\)的結構體,這個結構體正是剛剛我們用在\(new\)後面的那個函式造出來的,我們可以用這種操作完成新變數的指標連線

對於已經存在的變數,它們的指標連線就更加簡單,因為我們知道指標之間可以直接賦值,即:

node *a,*b;

...//中間的一些步驟,使他們分別指向不同的目標

a=b;//這樣他們就指向了同乙個目標

這樣一來我們就能夠直接使指標指向我們所希望它指向的目標了.

以上是結構體指標的宣告與基本賦值(連線)

一般結構體變數內元素的呼叫都需要形如"\(nd.a\)或者\(b\)或者\(c\)"的格式,加入現有一指標\(rt\)指向乙個內容為\(a,b,c\)的結構體變數,那麼我們在用指標呼叫時就需要這樣寫:

rt->a;
對於結構體內的函式(成員函式),需要這樣寫:

rt->function();
就是由點變成了箭頭,不要認為兩種形式都可以,必須對應起來,不然會ce

另外,在結構體內寫成員函式的時候,我們可以省去變數名等字首,

很人性化的是,在結構體中,\(this\)表示當前結構體的位址,這樣就方便了我們在結構體內捯飭指標的時候無法處理"自己"的問題,

當然,沒有人想要在結構體裡用\(this\)來訪問自己的元素,因為能訪問\(this\)的時候可以直接呼叫該結構體內元素值,\(this\)只是用來讓別人指向自己的

來看下結構體內成員函式有什麼變化:

//結構體node[a,b,*c]外,結構體變數名nd,指標c指向其他node結構體:

inline void insert()

//結構體內:

struct node

}nd(或者*nd);

需要注意的是,要達到第乙個函式的效果,第二個函式必須搭配著這樣寫:

//nd是結構體變數的情況下:

nd.insert();

//nd是指標的的情況下:

nd->insert();

這樣寫意味著我們需要把已有的結構體變數(或指標)作為物件進行操作,也就是我們可以指定函式操作的物件,從而去指定我們用成員函式呼叫誰體內的元素.

也許這樣看著寫起來很麻煩,讀起來很難受,但是實際上這是很符合中國人語言習慣的寫法,這一點寫的資料結構多了,就自然會明白,就自然會感嘆指標的妙處.

鍊錶,用結構體偽**表示的話,大概需要以下變數:

struct node;
下面我們就指標寫法做詳細討論

鍊錶本身並不複雜,畢竟操作就只有元素之間的插入,刪除,牽扯元素最多的怕就是鍊錶的遍歷,此時只要記錄好鍊錶的第乙個元素的位址,跟著指標的指引,按照指標遍歷就好了;

對於"前插"與"後插"進行區分,下面給出前插的**及詳解,注意這裡是結構體內成員函式:

inline void insert0(ci u)
這是基本前插的思想,對於後插請獨立思考得出結論慫什麼,還有後面的總**呢

單靠上面的條件比較噁心,題目所給出的,是被刪去同學的序號,此時我們新建乙個指標陣列\(nd\),指向對應編號的元素,\(nd[i]\)指向的是\(i\)號同學,

我們這樣一種指標的新增可以理解為為鍊錶提供了直接的指向,比如樣例輸出資料中的:

2 4 1
實際上就是

->元素[4,前乙個是元素2的位址,後乙個是元素1的位址]

->元素[1,前乙個是元素4的位址,後乙個空]

//另外的*nd陣列,可以直接通過*nd陣列找到對應元素的位置進而訪問對應元素

nd[1]=元素1的位址,nd[2]=元素2的位址, nd[3]=早刪了,nd[4]=元素4的位址

其中我們利用\(nd[4]->pre\)呼叫的指標,實際上就是\(nd[2]\)裡存放的指標

由此,我們可以方便地訪問到資料給出的元素,

inline void remove()
我們還需要乙個指標\(^*rt\)來儲存鍊錶的第乙個元素,這樣才能輸出整個鍊錶

我們在結構體之前這樣寫:

struct node *nd[n],*rt;

struct node;

這樣我們就可以在結構體中的成員函式中用這些指標了

對於本題目,我們注意到它的操作是預設\(1\)已經在佇列中了,所以我們需要在主函式中先建立元素\(1\),並且把第乙個元素設定為\(1\)

nd[1]=new node(1); rt=nd[1];
另外的插入刪除操作及一些改動會在完整**中給出注釋,

完整**:

#include#include#define ci const int &

using namespace std;

const int n=100005;

int n,m;

struct node *nd[n],*rt;

struct node

inline void insert0(ci u)

inline void insert1(ci u)

inline void remove()

};int main()scanf("%d",&m);

for(int i=1;i<=m;++i)

while(rt)return 0;

}

希望我的講解能夠給讀者帶來些什麼,總之感謝你的閱讀

用指標處理鍊錶

用指標處理鍊錶 建立乙個簡單的鍊錶,它由3個學生資料的結點組成,要求輸出各結點中的資料 include struct student int main while p null 輸出完c結點後p的值為null,迴圈終止 return 0 寫一函式建立乙個有3名學生資料的單向動態鍊錶 include ...

用指標處理鍊錶

鍊錶概述 鍊錶是一種常見的重要的資料結構。它是動態地進行儲存分配的一種結構。鍊錶有乙個 頭指標 變數,它存放乙個位址,該位址指向乙個元素,鍊錶中每乙個元素稱為 結點,每個結點都應包括兩個部分,一為使用者需要用的實際資料,二為下乙個結點的位址。可以看出,頭指標 head 指向第乙個元素,第乙個元素又指...

用指標處理鍊錶

鍊錶是一種常見的重要資料結構。它是動態地進行儲蓄分類的一種結構。鍊錶有一系列節點構成,節點在執行時動態生成,每個節點包括資料域,資料域儲存當前節點的資訊,指標域儲存下乙個節點的手位址。記憶體隨著時間的增加會找不到大塊的順序空間 陣列的大小只能是固定的,增加或刪除都會移動大量資料 鏈式儲存大小可以伸縮...