俗話說得好,不懂鏈表的程序員,不配稱爲C/C++程序員。
爲什麼呢?
鏈表的存儲主要依據指針來實現,而指針又是C/C++獨有的特性,是其他語言沒有的。
今天,你點進來看了這篇博客,說明你還是不懂C/C++當中鏈表的算法。
不懂沒關係,看了這篇博客,只要是懂得指針的小夥伴,都會學會使用單向鏈表。
鏈表是什麼?
鏈表是線性表的鏈式存儲方式,邏輯上相鄰的數據在計算機內的存儲位置不必須相鄰,那麼,怎麼表示邏輯上的相鄰關係呢?可以給每個元素附加一個指針域,指向下一個元素的存儲位置。
如圖:
從圖中可以看出,每個結點包含兩個域:數據域和指針域,指針域存儲下一個結點的地址,因此指針指向的類型也是結點類型。
鏈表的核心要素:
- 每個節點由數據域和指針域組成
- 指針域指向下一個節點的內存地址
鏈表分爲三種:
- 單向鏈表
- 循環鏈表
- 雙向鏈表
今天這篇文章講的是單向鏈表。
單向鏈表其結構體定義:
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
} LinkList, LinkNode;
單向鏈表的概念
如上圖就是一條單向鏈表。鏈表的節點均單向指向下一個節點,形成一條單向訪問的數據鏈。
鏈表我們把他分爲頭節點和節點,頭節點默認是鏈表的頭部,不存儲數據,節點則存儲所有數據。
如圖就是一個典型的單向鏈表。頭節點不存儲數據,但是他的指針指向節點1的地址,所以頭節點和節點1鏈接起來了。然後節點1的指針又指向了節點2的地址,使節點1和節點2也鏈接起來了…最後,節點i的指針指向節點n,最後一個節點,最後一個節點n的指針指向了NULL。至此,一條鏈條誕生了。
就好比如,頭節點知道了節點1的地址,頭節點就可以根據地址找到節點1;
就好比如,張三知道了李四家的地址,張三就可以根據地址找到李四。
因爲他是單向鏈表,只能從頭節點開始,一直到尾節點,不存在節點1的指針指向頭節點,就好比如不存在李四能找到張三,只能張三找到李四。
講到這裏,可能還有很多朋友還是不懂鏈表,不過沒關係,通過下面的例子,你就能完全掌握鏈表的用法。
單向鏈表的定義與初始化
// 定義鏈表
typedef struct Link {
int date; // 鏈表中的數據
struct Link* next; // 下一個節點地址
}LinkNode, LinkList; // LinkNode:節點 LinkList:頭節點
// 初始化鏈表
bool initLink(LinkList* &L) { // 參數一:單鏈表的頭節點指針的引用
L = new LinkNode; // 分配內存
if (!L) { // 是否分配失敗
cout << "生成頭節點失敗!" << endl;
return false; // 生成節點失敗
}
L->next = NULL; // 因爲是初始化,所以頭節點指向NULL
return true;
}
定義鏈表中,可以看到,他是一個結構體,date是該鏈表的數據,也可以是其他數據類型;struct Link* next;
該條語句是必須的,定義自己結構體的指針,用於存儲下一個節點的地址,這也是上面說的指針。
LinkNode, LinkList;
,該兩條語句是用於定義結構體變量的,兩個用法都是一個的,只是取不同的名字,用於區分定義的結構體變量的含義。
我們再來看一下鏈表的初始化:
它就是要給函數接口,裏面爲結構體的變量分配內存,因爲是初始化,裏面沒有存儲數據,他的指針也就指向了NULL。
鏈表的初始化就是這麼簡單,因爲我們定義的鏈表是指針類型的變量,所以獲取裏面的數據是需要使用”->
“來獲取。
鏈表初始化後,鏈表僅只有一個頭節點,沒有其他節點(如上圖)。
頭插法
好了,鏈表初始化好後,我們就可以給他插入數據了。現在我們來學習一下頭插法,就是在頭部插入數據。
注意:他並不是在頭節點的位置插入數據,而是在頭節點的下一個節點,也就是節點1的位置插入數據。
頭插法有兩種情況:
情況一:鏈表中沒有其他節點,只有頭節點。
如圖,它需要在頭節點的後面插入節點。
情況二:鏈表中已有其他節點。
鏈表中有其他節點,頭插法也一樣還是在頭節點的後面插入,插入後,新的節點就成爲節點1,而原有的節點位置不變,節點名字加1.
雖然有兩種情況,但是他們實現的代碼都是一樣的:
// 頭插法
bool LinkInsert_front(LinkList*& List, LinkNode* Node) { // 參數一:鏈表的頭節點指針的引用;參數二:待插入的新節點
if (!List || !Node) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
Node->next = List->next; // 新插入節點的next指向頭節點的下一個節點
List->next = Node; // 頭節點的next指向新插入的節點
return true;
}
如上圖就是他的連接過程。
我們需要將新插入的節點的指針next指向頭節點的指針next原指向的節點,然後再將頭節點的指針next指向新節點,就完成了插入。
尾插法
顧名思義,尾插法就是在鏈表的最後面插入節點。
在鏈表尾部插入,必須得先找到尾節點。
他也有兩種情況:
情況一:鏈表中沒有其他節點,只有頭節點。
因爲只有頭節點,所以頭節點也就是最後一個節點,可以直接插入。
情況二:鏈表中已有其他節點。
我們需要找到尾節點,纔可以插入。
雖然有兩種情況,但是他們實現的代碼都是一樣的:
// 尾插法
bool LinkInsert_back(LinkList*& List, LinkNode* Node) { // 參數一:鏈表的頭節點指針的引用;參數二:待插入的新節點
if (!List || !Node) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkNode* p = List; // 定義臨時節點指向頭節點,用於找到尾節點
while (p->next) p = p->next; // 找到尾節點
Node->next = p->next; // 新插入節點的next指向NULL,因爲尾節點的下一個節點必須是NULL值(也可以寫成這樣:Node->next = NULL;)
p->next = Node; // 舊尾節點的next指向新尾節點
return true;
}
我們需要定義臨時節點,然後遍歷指向最後一個節點的位置,就可以利用它插入新的節點了。
p = p->next
的意思是:假如p是代表節點1,那麼p->next就是節點2,p = p->next
就是p要代表節點2了。
while(p->next)
,當p的下一個節點不爲NULL的話,則行循環。當p->next
爲NULL時,說明p已經在鏈表最後一個節點的位置了。
任意位置插入
顧名思義,就是可以在鏈表的任何位置插入節點。
我們必須得找到插入位置節點的前一個節點,纔可以進行插入。
// 任意位置插入
bool LinkInsert(LinkList*& List, int i, int& e) { // 參數一:鏈表的頭節點指針的引用;參數二:插入的位置;參數三:插入的元素
if (!List) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p, * s; // p用於尋找插入位置的前一個節點,s用於創建新節點待插入
p = List; // 將頭節點賦值給p,用作下面循環查找
int j = 0; // 循環條件;因爲從頭節點開始,所以賦值0
while (p && j < i - 1) { // 查找位置爲i-1的節點,p指向該節點
p = p->next;
j++;
}
// 假如i大於鏈表的個數,則p爲NULL,返回false;假如i爲負數或者爲零,則返回false
if (!p || j > i - 1) return false; // i值不合法的情況:i > n || i <= 0
s = new LinkNode; // 分配新節點內存
s->date = e; // 將元素賦值給新節點
s->next = p->next; // 新插入的節點指向插入位置後的下一個節點
p->next = s; // 插入位置的前一個節點指向新插入的節點
return true;
}
任意位置插入的算法難度在於如何找到插入位置的前一個節點。
代碼中我們使用while循環進行查找,其中j < i-1,就是找到節點的關鍵條件。
獲取鏈表中指定節點位置的值
到了這裏,如果上面的鏈表代碼都搞懂了的話,至此下面所講的所有鏈表的用法都不難了。
獲取任意位置節點的值和任意位置插入節點 代碼實現都時差不多的,只是指定位置獲取節點的值,只需要找到該節點就行了。而任意位置插入節點就是找到節點的上一個節點。
// 獲取鏈表中指定節點位置的值
bool Link_GetElem(LinkList*& List, int i, int& e) { // 參數一:鏈表的頭節點指針的引用;參數二:查找的位置;參數三:獲取它的值
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p = List->next; // 定義臨時節點,用於尋找要獲取的節點的值處
int j = 1; // 循環條件;因爲是從第一個節點開始循環查找,所以賦值1
while (p && j < i) { // 尋找到i的節點位置,p指向它
p = p->next;
j++;
}
// i>n,則p爲NULL,所以返回false;i<=0,則j肯定是大於i的,所以返回false
if (!p || j > i) return false; // i值不合法的情況:i > n || i <= 0
e = p->date; // 將尋找到鏈表中的值賦值給引用變量e返回
return true;
}
此代碼難點也是如何找到該節點位置。
查找該值在鏈表中節點的位置
就是通過一個值,去遍歷整個鏈表,判斷鏈表中是否有節點存儲該值,有則返回該節點的位置。
// 查找該值在鏈表中節點的位置
bool LinkFindElem(LinkList*& List, int e, int& i) { // 參數一:鏈表的頭節點指針的引用;參數二:鏈表中查找的值;參數三:返回查找到的節點位置
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p = List->next; // 定義臨時節點,用於尋找要查找的節點的值處
int j = 1; // 記錄節點;因爲是從第一個節點開始循環查找,所以賦值1
while (p && p->date != e) { // 當前節點p不爲NULL,而且當前節點的值不等於e時,執行循環,還未找到e
p = p->next;
j++;
}
if (!p) { // 假如while循環沒有找到,那麼p爲NULL,查無此值
i = 0; // 將i賦值零,查無此值
return false;
}
i = j; // 則行到這一步,說明找到了,將節點的位置賦值給i值返回
return true;
}
都是和上面差不多的代碼,只是將位置條件判斷換成了值的判斷。
修改指定位置節點的值
修改鏈表中節點的值。
代碼就是和 ’獲取鏈表中指定節點位置的值‘ 當中的代碼一模一樣,只是找到後,就將節點的值修改掉。
// 修改指定位置節點的值
bool LinkAlterValue(LinkList*& List, int i, int e) { // 參數二:節點的位置;參數三:修改的值
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p = List->next; // 定義臨時節點指向頭節點的下一個節點
int j = 1; // 用於找到節點位置
while (p && j < i) { // 找到節點位置,p指向它
p = p->next;
j++;
}
// i>n,觸發條件一;i<=0,觸發條件二
if (!p || j > i) return false; // i值不合法的情況:i > n || i <= 0
// 執行到這一步說明已經找到了需要修改值的節點,p指向它
p->date = e; // 將e值賦值給p的date
return true;
}
刪除鏈表中的一個節點
它也有兩種情況:
情況一:根據節點的位置刪除
// 刪除鏈表中的一個節點:1.根據節點的位置刪除
bool LinkDelete_1(LinkList*& List, int i) { // 參數一:鏈表的頭節點指針的引用;參數二:待刪除節點的位置
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p, * q; // p用於尋找刪除位置的前一個節點,q用於輔助刪除和釋放被刪除節點的內存
p = List; // 將頭節點賦值給p,用作下面循環查找
int j = 0; // 循環條件;因爲從頭節點開始,所以賦值0
while (p->next && j < i - 1) { // 尋找到待刪除節點的前一個節點位置,p指向它
p = p->next;
j++;
} // 循環結束時,p指向最後一個節點
// 當i>n || i<1,p的下一個節點爲NULL,返回flase;當i<1,則爲不合法,不可能刪除頭節點和負數位置的節點,返回false
if (!(p->next) || j > i - 1) return false; // 當i>n || i<1時,刪除位置不合理
q = p->next; // 將待刪除節點賦值給q
p->next = q->next; // 待刪除節點的前一個節點指向待刪除節點的後一個節點位置
delete q; // 釋放掉待刪除節點的內存
return true;
}
找到待刪除節點的前一個節點,就可以刪除了。
定義臨時節點指向節點1,然後將節點1的next指向節點3,就完成了節點2的刪除,最後定義臨時節點指向節點2,將節點2的內存釋放掉就行了。
情況二:根據節點的值刪除
都一樣的代碼,找到待刪除節點的前一個節點根據值判斷尋找。就可以進行刪除操作了。
// 刪除鏈表中的一個節點:2.根據節點的值刪除
bool LinkDelete_2(LinkList*& List, int e) { // 參數一:鏈表的頭節點指針的引用;參數二:待刪除節點的值
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p, * q; // p用於尋找刪除位置的前一個節點,p用於輔助刪除和釋放被刪除節點的內存
p = List; // 將頭節點賦值給p,用作下面循環查找
while (p->next && ((p->next)->date) != e) { // 尋找到待刪除節點的前一個節點位置,p指向它
p = p->next;
} // 循環結束時,p指向最後一個節點
if (!(p->next)) return false; // 如果p的下一個節點爲NULL,則沒有找到該值對應的節點
q = p->next; // 將待刪除節點賦值給q
p->next = q->next; // 待刪除節點的前一個節點指向待刪除節點的後一個節點位置
delete q; // 釋放掉待刪除節點的內存
return true;
}
銷燬單鏈表
既然你使用了鏈表,那麼就涉及到從堆棧非配內存的相關問題,當程序結束時,需要將鏈表的內存釋放掉。
// 銷燬單鏈表
void LinkDestroy(LinkList*& List) {
if (!List) { // 合法性檢查
cout << "鏈表爲NULL!" << endl;
return;
}
cout << "鏈表銷燬!" << endl;
LinkList* p = List; // 定義臨時節點指向頭節點,用於釋放節點的內存
while (p) { // 如果p爲真,則繼續則行循環,直到鏈表全部釋放掉爲止
cout << "刪除節點:" << p->date << endl;
List = List->next; // 向下一個節點
delete p; // 釋放掉當前節點的內存
p = List; // p移動到下一個節點
}
}
定義臨時節點指向頭節點,當臨時節點不爲NULL時,先將頭節點指向下一個節點,然後釋放掉臨時節點指向的節點內存,再將頭節點指向的下一個節點賦值給臨時節點。如此循環釋放,就可以將鏈表完整的釋放掉了。
鏈表輸出
輸出鏈表中的元素。
// 鏈表輸出
void LinkPrint(LinkList*& List) { // 鏈表
if (!List) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return;
}
LinkNode* p = List->next; // 定義臨時鏈表指向頭節點的下一個節點
while (p) { // 如果不爲空,執行
cout << p->date << "\t";
p = p->next; // p指向己的下一個節點
}
}
完整測試代碼:
#include <iostream>
#include <Windows.h>
using namespace std;
// 定義鏈表
typedef struct Link {
int date; // 鏈表中的數據
struct Link* next; // 下一個節點地址
}LinkNode, LinkList; // LinkNode:節點 LinkList:頭節點
// 初始化鏈表
bool initLink(LinkList* &L) { // 參數一:單鏈表的頭節點指針的引用
L = new LinkNode; // 分配內存
if (!L) { // 是否分配失敗
cout << "生成頭節點失敗!" << endl;
return false; // 生成節點失敗
}
L->next = NULL; // 因爲是初始化,所以頭節點指向NULL
return true;
}
// 頭插法
bool LinkInsert_front(LinkList*& List, LinkNode* Node) { // 參數一:鏈表的頭節點指針的引用;參數二:待插入的新節點
if (!List || !Node) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
Node->next = List->next; // 新插入節點的next指向頭節點的下一個節點
List->next = Node; // 頭節點的next指向新插入的節點
return true;
}
// 尾插法
bool LinkInsert_back(LinkList*& List, LinkNode* Node) { // 參數一:鏈表的頭節點指針的引用;參數二:待插入的新節點
if (!List || !Node) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkNode* p = List; // 定義臨時節點指向頭節點,用於找到尾節點
while (p->next) p = p->next; // 找到尾節點
Node->next = p->next; // 新插入節點的next指向NULL,因爲尾節點的下一個節點必須是NULL值(也可以寫成這樣:Node->next = NULL;)
p->next = Node; // 舊尾節點的next指向新尾節點
return true;
}
// 任意位置插入
bool LinkInsert(LinkList*& List, int i, int& e) { // 參數一:鏈表的頭節點指針的引用;參數二:插入的位置;參數三:插入的元素
if (!List) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p, * s; // p用於尋找插入位置的前一個節點,s用於創建新節點待插入
p = List; // 將頭節點賦值給p,用作下面循環查找
int j = 0; // 循環條件;因爲從頭節點開始,所以賦值0
while (p && j < i - 1) { // 查找位置爲i-1的節點,p指向該節點
p = p->next;
j++;
}
// 假如i大於鏈表的個數,則p爲NULL,返回false;假如i爲負數或者爲零,則返回false
if (!p || j > i - 1) return false; // i值不合法的情況:i > n || i <= 0
s = new LinkNode; // 分配新節點內存
s->date = e; // 將元素賦值給新節點
s->next = p->next; // 新插入的節點指向插入位置後的下一個節點
p->next = s; // 插入位置的前一個節點指向新插入的節點
return true;
}
// 獲取鏈表中指定節點位置的值
bool Link_GetElem(LinkList*& List, int i, int& e) { // 參數一:鏈表的頭節點指針的引用;參數二:查找的位置;參數三:獲取它的值
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p = List->next; // 定義臨時節點,用於尋找要獲取的節點的值處
int j = 1; // 循環條件;因爲是從第一個節點開始循環查找,所以賦值1
while (p && j < i) { // 尋找到i的節點位置,p指向它
p = p->next;
j++;
}
// i>n,則p爲NULL,所以返回false;i<=0,則j肯定是大於i的,所以返回false
if (!p || j > i) return false; // i值不合法的情況:i > n || i <= 0
e = p->date; // 將尋找到鏈表中的值賦值給引用變量e返回
return true;
}
// 查找該值在鏈表中節點的位置
bool LinkFindElem(LinkList*& List, int e, int& i) { // 參數一:鏈表的頭節點指針的引用;參數二:鏈表中查找的值;參數三:返回查找到的節點位置
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p = List->next; // 定義臨時節點,用於尋找要查找的節點的值處
int j = 1; // 記錄節點;因爲是從第一個節點開始循環查找,所以賦值1
while (p && p->date != e) { // 當前節點p不爲NULL,而且當前節點的值不等於e時,執行循環,還未找到e
p = p->next;
j++;
}
if (!p) { // 假如while循環沒有找到,那麼p爲NULL,查無此值
i = 0; // 將i賦值零,查無此值
return false;
}
i = j; // 則行到這一步,說明找到了,將節點的位置賦值給i值返回
return true;
}
// 修改指定位置節點的值
bool LinkAlterValue(LinkList*& List, int i, int e) { // 參數二:節點的位置;參數三:修改的值
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p = List->next; // 定義臨時節點指向頭節點的下一個節點
int j = 1; // 用於找到節點位置
while (p && j < i) { // 找到節點位置,p指向它
p = p->next;
j++;
}
// i>n,觸發條件一;i<=0,觸發條件二
if (!p || j > i) return false; // i值不合法的情況:i > n || i <= 0
// 執行到這一步說明已經找到了需要修改值的節點,p指向它
p->date = e; // 將e值賦值給p的date
return true;
}
// 刪除鏈表中的一個節點:1.根據節點的位置刪除
bool LinkDelete_1(LinkList*& List, int i) { // 參數一:鏈表的頭節點指針的引用;參數二:待刪除節點的位置
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p, * q; // p用於尋找刪除位置的前一個節點,q用於輔助刪除和釋放被刪除節點的內存
p = List; // 將頭節點賦值給p,用作下面循環查找
int j = 0; // 循環條件;因爲從頭節點開始,所以賦值0
while (p->next && j < i - 1) { // 尋找到待刪除節點的前一個節點位置,p指向它
p = p->next;
j++;
} // 循環結束時,p指向最後一個節點
// 當i>n || i<1,p的下一個節點爲NULL,返回flase;當i<1,則爲不合法,不可能刪除頭節點和負數位置的節點,返回false
if (!(p->next) || j > i - 1) return false; // 當i>n || i<1時,刪除位置不合理
q = p->next; // 將待刪除節點賦值給q
p->next = q->next; // 待刪除節點的前一個節點指向待刪除節點的後一個節點位置
delete q; // 釋放掉待刪除節點的內存
return true;
}
// 刪除鏈表中的一個節點:2.根據節點的值刪除
bool LinkDelete_2(LinkList*& List, int e) { // 參數一:鏈表的頭節點指針的引用;參數二:待刪除節點的值
if (!List || !List->next) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return false;
}
LinkList* p, * q; // p用於尋找刪除位置的前一個節點,p用於輔助刪除和釋放被刪除節點的內存
p = List; // 將頭節點賦值給p,用作下面循環查找
while (p->next && ((p->next)->date) != e) { // 尋找到待刪除節點的前一個節點位置,p指向它
p = p->next;
} // 循環結束時,p指向最後一個節點
if (!(p->next)) return false; // 如果p的下一個節點爲NULL,則沒有找到該值對應的節點
q = p->next; // 將待刪除節點賦值給q
p->next = q->next; // 待刪除節點的前一個節點指向待刪除節點的後一個節點位置
delete q; // 釋放掉待刪除節點的內存
return true;
}
// 銷燬單鏈表
void LinkDestroy(LinkList*& List) {
if (!List) { // 合法性檢查
cout << "鏈表爲NULL!" << endl;
return;
}
cout << "鏈表銷燬!" << endl;
LinkList* p = List; // 定義臨時節點指向頭節點,用於釋放節點的內存
while (p) { // 如果p爲真,則繼續則行循環,直到鏈表全部釋放掉爲止
cout << "刪除節點:" << p->date << endl;
List = List->next; // 向下一個節點
delete p; // 釋放掉當前節點的內存
p = List; // p移動到下一個節點
}
}
// 鏈表輸出
void LinkPrint(LinkList*& List) { // 鏈表
if (!List) { // 合法性檢查
cout << "鏈表爲空!" << endl;
return;
}
LinkNode* p = List->next; // 定義臨時鏈表指向頭節點的下一個節點
while (p) { // 如果不爲空,執行
cout << p->date << "\t";
p = p->next; // p指向己的下一個節點
}
}
int main(void) {
LinkList* list = NULL; // 鏈表頭節點
LinkNode* node = NULL; // 新節點
// 初始化鏈表
if (initLink(list)) {
cout << "初始化成功!" << endl;
} else {
cout << "初始化失敗!" << endl;
}
// 頭插法
int n = 0;
cout << "請輸入頭插法需要插入的個數n:";
cin >> n;
while (n > 0) {
node = new LinkNode; // 分配一個節點內存
cin >> node->date;
LinkInsert_front(list, node); // 插入
n--;
}
// 尾插法
int nn = 0;
cout << "請輸入尾插法需要插入的個數nn:";
cin >> nn;
while(nn > 0) {
node = new LinkNode; // 分配新節點內存
cin >> node->date;
LinkInsert_back(list, node);
nn--;
}
LinkPrint(list);
cout << endl;
// 任意位置插入
int nnn;
int i, date;
cout << "請輸入任意位置需要插入的元素個數nnn:";
cin >> nnn;
while (nnn > 0) {
cout << "請輸入插入位置和插入的元素:";
cin >> i >> date;
if (LinkInsert(list, i, date)) {
cout << "插入成功!" << endl;
} else {
cout << "插入失敗!" << endl;
}
LinkPrint(list);
cout << endl;
nnn--;
}
// 獲取鏈表中指定節點的值
int e = 0;
if (Link_GetElem(list, 3, e)) {
cout << "獲取節點3成功,值爲:" << e << endl;
} else {
cout << "獲取節點3失敗!" << endl;
}
// 查找鏈表中的值
if (LinkFindElem(list, 5, e)) {
cout << "查找值爲5成功,節點位置爲:" << e << endl;
} else {
cout << "查找值爲5失敗,節點位置返回:" << e << endl;
}
// 刪除鏈表中的一個節點:1.根據節點的位置刪除
if (LinkDelete_1(list, 3)) {
cout << "刪除節點位置3成功!" << endl;
} else {
cout << "刪除節點位置3失敗!" << endl;
}
LinkPrint(list);
cout << endl;
// 刪除鏈表中的一個節點:2.根據節點的值刪除
if (LinkDelete_2(list, 1)) {
cout << "刪除值爲1的節點成功!" << endl;
} else {
cout << "刪除值爲1的節點失敗!" << endl;
}
LinkPrint(list);
cout << endl;
// 修改指定位置節點的值
if (LinkAlterValue(list, 1, 44)) {
cout << "修改第一個節點的值成功!" << endl;
LinkPrint(list);
} else {
cout << "修改第一個節點的值失敗!" << endl;
LinkPrint(list);
}
// 銷燬單鏈表
LinkDestroy(list);
system("pause");
return 0;
}
總結:
鏈表其實不難,只需要認真學好我前面所講的那幾個操作,後面的那些都時融匯貫通的。