本篇文章的代碼大多使用無頭結點的單鏈表:
相關定義:
#include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int DataType; typedef struct Linklist{ LDataType data; struct Linklist *next; }Linklist,*pLinklist;
相關函數的定義:
pLinklist BuyNewNode(LDataType data); //創建一個數據域為data的新結點
void InitLinklist(pLinklist *pL); //初始化單鏈表
void PushBackLinklist(pLinklist* pL,LDataType data); //尾插
void PushFrontLinklist(pLinklist *pL,LDataType data); //頭插
void PopBackLinklist(pLinklist *pL); //尾刪
void PopFrontLinklist(pLinklist *pL); //頭刪
void PrintLinklist(pLinklist pL); //打印出鏈表
pLinklist FindLinklist(Linklist *pL,LDataType data); //找到數據域為data的第一個結點
void InsertLinklist(pLinklist *pL,pLinklist p,LDataType data); //指定位置插入
void RemoveLinklist(pLinklist *pL,LDataType data); //刪除第一個數據為data的結點
void RemoveAllLinklist(pLinklist *pL,LDataType data); //刪除數據為data的全部結點
int IsEmpty(pLinklist pL); //判斷單鏈表是否為空
void DestoryLinklist(pLinklist *pL); //刪除整個鏈表,釋放內存
由上面可以看出,只要是涉及到頭指針發生改變的,我們在函數中都是傳入指向頭指針的指針。就像我們在swap函數中要交換a和b的值,我們是傳入地址,而現在我們要改變頭指針的值,也必須要傳入指向頭指針的一個指針來進行相關的操作。
此處借鑒了c語言函數傳遞參數的問題。
下面是對函數的展開,我會比較詳細的分析一下函數實現:
0.動態生成新結點
pLinklist BuyNewNode(LDataType data){
pLinklist NewNode = (pLinklist)malloc(sizeof(Linklist));
if(pLinklist == NULL){
printf("空間開辟失敗");
return NULL;
}
NewNode->data = data;
NewNode->next = NULL;
return NewNode;
}
1.初始化操作
void InitLinklist(pLinklist *pL){
assert(pL != NULL);
(*pL) = NULL;
}
2.尾插一個數據為data的結點
void PushBackLinklist(pLinklist *pL,LDataType data){
assert(pL != NULL); //大多數中都有這個,是為了防止使用空指針,書中經常會說,千萬不要使用空指針,你應該有印象
pLinklist NewNode = BuyNewNode(data);
if(*pL == NULL){ //判斷這個是否為空鏈表
*pL = NewNode;
return ;
}
pLinklist cur = *pL;
while(cur->next != NULL){ //其實這里也可以用cur != NULL,但是上面已經把把空鏈表大情況寫出來了,如果再這樣寫會重復,不會錯,但是復雜一點點
cur = cur->next;
}
cur->next = NewNode;
}
3.頭插一個數據為data的結點
void PushFrontLinklist(pLinklsit *pL,LDataType data){
assert(pL != NULL);
pLinklist NewNode = BuyNewNode(data);
if(*pL == NULL){
*pL = NewNode;
return ;
}
NewNode->next = *pL;
*pL = NewNode;
}
4.判斷無頭鏈表是否為空
int IsEmptyLinklist(pLinklist pL){
//這里的pL是一個指向鏈表的指針,而不是一個指向鏈表指針的指針
return (pL == NULL);
}
5.尾刪
void PopBackLinklist(pLinklist *pL){
assert(pL != NULL);
if(IsEmptyLinklist(*pL)){
//*pL是一個指向鏈表的指針
printf("鏈表為空");
return ;
}
//尾刪需要找到前面那一個結點
pLinklist cur = *pL;
pLinklist pre;
if(cur->next == NULL){
*pL = NULL;
free(cur);
cur = NULL;
return ;
}
while(cur->next){
pre = cur;
cur = cur->next;
}
pre->next = NULL;
free(cur);
cur = NULL;
}
6.頭刪
void PopFrontLinklist(pLinklist *pL){
assert(pL != NULL);
if(*pL == NULL){
printf("鏈表為空");
return ;
}
pLinklist p = *pL;
*pL = p->next;
free(p);
p = NULL;
}
7.找到第一個數據為data的結點
pLinklist FindLinklist(pLinklist *pL,LDataType data){
assert(pL != NULL);
plinklist cur = *pL;
while(cur != NULL){
if(cur->data == data){
return cur;
}
cur = cur->next;
}
return NULL;
}
8.在給出的結點之前插入一個數據為data的結點
void InsertLinklist(pLinklist *pL,pLinklist p,LDataType data){
assert(pL != NULL);
pLinklist NewNode = BuyNewNode(data);
pLinklist cur = *pL;
while(cur->next != p){
cur = cur->next;
}
NewNode->next = cur->next;
cur->next = NewNode;
}
9.刪除第一個數據為data的結點
void RemoveLinklist(pLinklist *pL,LDataType data){
assert(pL != NULL);
pLinklist cur = FindLinklist(pL,data);
if(cur == NULL){
printf("沒找到");
return ;
}
if(cur == *pL){
//剛好在第一個結點
*pL = cur->next;
free(cur);
cur = NULL;
return ;
}
pLinklist p = *pL;
while(p->next != cur){
p = p->next;
}
p->next = cur->next;
free(cur);
cur = NULL;
}
10.刪除每一個數據都是data的結點
void RemoveAllLinklist(pLinklist *pL,LDataType data){
assert(pL != NULL); //刪除每一個數據域都是data的結點
pLinklist cur = NULL;
pLinklist p = *pL; //pre保存要刪除結點的前一個結點
pLinklist pre = *pL;
while(p){
if (p->data == data && (*pL) == p){
//第一個結點是
pre = p;
p = p->next;
*pL = p;
free(pre);
pre = NULL;
}
else if(p->data == data){
//后續結點是
cur = p;
p = p->next;
pre->next = p;
free(cur);
cur = NULL;
}
else{
//此結點不是
pre = p;
p = p->next;
}
}
}
11.打印出鏈表
void PrintLinklist(Linklist *pL){ pLinklist cur = pL; //打印鏈表 while(cur){ printf("%d--->",cur->data); cur = cur->next; } printf("NULL\n"); }
12.摧毀鏈表
void DestoryLinklist(pLinklist *pL){ assert(pL != NULL); //摧毀鏈表 pLinklist cur = *pL; pLinklist pre = NULL; if (*pL == NULL){ printf("鏈表為空"); return ; } if (cur->next = NULL){ *pL = NULL; free(cur); cur = NULL; return ; } while(cur){ pre = cur; cur = cur->next; free(pre); pre = NULL; } }