接可變陣列
但如果我們可以使用block,將其都拼接在一起,並不是用上面的方法複製貼上。每乙個block會有乙個單元指向的是下乙個block的位址,這樣就不會有上述的問題了
所以對於乙個單元,它裡面應該分成兩部分:
1.資料
2.下乙個單元的位址(指標)
這樣指向的下乙個資料結構也應是如此。
直到最後乙個單元,儲存的是資料,位址用乙個標記標誌它已經沒有指向下乙個地方了
當然最開始,還需要乙個指標指向第乙個單元的位址,俗稱head
這樣的東西就叫做鍊錶(linklist),每乙個單元叫做節點
定義:
typedef struct _node node;
對於往煉表內加入資料,**實現如下:
#include #include "node.h"
#include using namespace std;
//typedef struct _node node;
int main(int argc, char** argv)
//找到目前鍊錶的末尾,讓其指向p
last->next = p;
} else
} } while(number != -1);
return 0;
}
2.鍊錶的函式在上述do-while函式內的**,實質上就是乙個對鍊錶進行賦值的功能,那麼我們可以將其封裝成乙個函式,這樣更易使用,如:
#include #include "node.h"
#include using namespace std;
//typedef struct _node node;
void add(node* head, int number);
int main(int argc, char** argv)
} while(number != -1);
return 0;
}void add(node* head,int number)
//找到目前鍊錶的末尾,讓其指向p
last->next = p;
} else
}
但這樣有非常嚴重的問題,在add函式中,我的head是乙個傳參,在函式中的head = p;
這個操作實質上並沒有任何用,add函式用完後的傳參被釋放,head永遠是null
解決方法
1.將node *head設為全域性變數
缺陷:全域性變數是有害的,是一次性的,這個head只對乙個鍊錶起作用,如果乙個程式有多個鍊錶,全設為全域性變數很危險
2.將add函式設定乙個返回值head,執行完畢後將head的值返回回去
head = add(head, number);
這方法看似不錯,但是在使用的時候感覺會很奇怪(尤其是給他人使用這個方法的時候)——只不過想add值進去,為什麼要返回值呢?要返回也是返回add成功與否吧?
3.傳head的指標回去
那這樣,函式的應該為
void add(node **phead, int number);
但是用到**的時候就要注意,指標的指標是乙個非常複雜的東西,一不小心會產生難以想象的錯誤,且指向指標的指標**也不易於閱讀
4.建立乙個結構體list,裡面存的是node *head,再對其進行使用
函式呼叫的時候是呼叫list的位址,實質上其實是和3是一樣的,但是換了乙個更易閱讀的方式。也就是通過自己定義的資料結構來代表整個list,**:
#include #include "node.h"
#include using namespace std;
//typedef struct _node node;
typedef struct _list list;
void add(list *plist, int number);
int main(int argc, char** argv)
} while(number != -1);
return 0;
}void add(list *plist, int number)
//找到目前鍊錶的末尾,讓其指向p
last->next = p;
} else
}
鍊錶的搜尋遍歷:乙個指標,拿到head,輸出value
變到下乙個位址
當沒有下乙個位址(最後指向的是null)迴圈結束
可以用for,也可以用while,for迴圈更加易懂:
node *p;//開始遍歷
for( p = list.head; p; p = p->next)
cout同樣的,可以封裝成函式,取名為print,我們需要的只是head
void print(list *plist)
cout既然能遍歷了,那麼我想尋找鍊錶中某乙個特定的數那也很方便了
cin>>number;
node *p;
int isfound = 0;
for(p = list.head; p; p->next)
}
但是這樣有乙個問題,q初始值是null,對於如果第乙個單元就是要去掉的,此時我們要修改的是head所指的地方,而不是對q有什麼操作。
在如此情況下,上述**中的q->next是非法、無意義的
所以我們需要通過語句將其保護起來(讓**更加嚴謹)
**實現:
node *q;
for(q = null,p = list.head; p; q=p,p = p->next) else
free(p);
break;
} }
鍊錶的清除每次遍歷到乙個,先有乙個臨時變數儲存next,然後free(),接著到下乙個節點,繼續free,直到p=null結束
for( p = list.head; p; p=q)
程式設計入門-鍊錶到此為止,至此將此課的**全部奉上:
node.h:
#ifndef _node_h_
#define _node_h_
typedef struct _node node;
#endif
main.cpp:
#include #include "node.h"
#include using namespace std;
//typedef struct _node node;
typedef struct _list list;
void add(list *plist, int number);
void print(list *plist);
int main(int argc, char** argv)
} while(number != -1);
// print(&list);
cin>>number;//尋找值
node *p;
int isfound = 0;
for(p = list.head; p; p->next) else
free(p);
break;
} }for( p = list.head; p; p=q)
return 0;
}void add(list *plist, int number)
//找到目前鍊錶的末尾,讓其指向p
last->next = p;
} else
} void print(list *plist)
cout<
}
C語言學習筆記 鍊錶
鍊錶是一種常見的重要的資料結構。它是動態地進行儲存分配的一種結構。它可以根據需要開闢記憶體單元。鍊錶有乙個 頭指標 變數,以head表示,它存放乙個位址。該位址指向乙個元素。鍊錶中每乙個元素稱為 結點 每個結點都應包括兩個部分 一為使用者需要用的實際資料,二為下乙個結點的位址。因此,head指向第乙...
C語言學習筆記 24鍊錶
一 鍊錶和陣列的比較 二 鍊錶中的術語 三 演算法 四 鍊錶結構示意圖 五 示例 include include include 定義乙個鍊錶結構 struct node 函式宣告 struct node createlist void void ergodiclist struct node in...
C語言學習筆記 鍊錶(三)鍊錶的插入
從指定節點後方插入新節點 假設我們已有五個節點,我們要把乙個新節點new插入到3後邊。需要三個步驟 找到 3 這個節點。把新節點指向3這個節點的下乙個節點 3 next new next 把3指向新節點。3 next new 定義結構體 struct test 輸出鍊錶資料 void printli...