在上兩篇文章中,我們介紹了基於靜態陣列和動態陣列的順序表,順序表頻繁查詢而插入刪除動作少的情況下,順序表也適用於進行尾插的時候,因為相對於鍊錶而言,順序表在進行尾插時,順序表不需要通過遍歷來找到最後乙個插入點,比較而言,順序表尾插效率高。
但是,在進行頭插和中插時,順序表需要將插入元素位置之後的元素整體後移才能插入資料,這樣做在有大量插入刪除場景下即為麻煩且效率低,因此,提出了鍊錶的思想。而鍊錶在頭插或者中插時,只需要建立乙個新節點,然後將節點鏈入所插入位置即可。
鍊錶概述
鍊錶是一種常見的資料結構。陣列可以存放資料,但是陣列存放資料時必須提前指定陣列包含元素個數,即陣列長度。但是陣列儲存資料的缺點在於如果要儲存元素大於陣列大小時,則不能將所有內容儲存入陣列,而當要儲存元素遠小於陣列大小時,又造成了空間的浪費。而鍊錶其儲存元素個數不受限定,當進行新增元素時,儲存個數隨之增加。
鍊錶是一種鏈式儲存的線性表,用一組位址任意的儲存單元存放線性表的資料元素,稱儲存單元為乙個節點。
typedef
int datatype;
typedef
int datatype;
typedef
struct linknode
node;
如下圖,為鍊錶結構示意圖:
在鍊錶中有乙個頭指標變數,圖中head表示的就是頭指標,這個指標變數儲存乙個位址。從圖中的箭頭可以看到該位址為乙個變數的位址,也就是說頭指標指向乙個變數。這個變數稱為元素,在鍊錶中每乙個元素包括兩個部分:資料部分和指標部分。資料部分用來存放元素所包含的資料,而指標部分用來指向下乙個元素。最後乙個元素指標指向null,表示指向的位址為空。
從圖可以看到,head頭結點指向第乙個元素,第乙個元素中的指標又指向第二個元素,第二個元素的指標又指向第三個元素的位址,第三個元素的指標指向第四個元素,第四個元素的指標就指向為空。
鍊錶的分類
需要注意的是,上述三種鍊錶都有兩種形式,分別為帶頭結點和不帶頭結點。
c語言實現不帶頭節點的單鏈表
具體**實現如下:
#pragma once
#include
#include
#include
/***************************************/
//鍊錶的定義
typedef int datatype;
typedef struct linknode
node;
/***************************************/
//鍊錶的初始化
void linklistinit(node** phead);
//建立新結點
node* linklistcreatnode(datatype data);
//銷毀結點
void linklistidestroynode(node** phead);
//遍歷列印鍊錶
void linklistprint(node** phead);
//尾插元素
void linklistpushback(node** phead, datatype data);
//尾刪元素
void linklistpopback(node** phead);
//頭插元素
void linklistpushfront(node** phead, datatype data);
//頭刪元素
void linklistpopfront(node** phead);
//查詢元素
size_t linklistfind(node** phead, datatype data);
//任意位置的插入
void linklistinsert(node** phead, datatype data, node* pos);
//任意位置的刪除
void linklisterase(node** phead, node* pos);
//求單鏈表長度
size_t linklistsize(node** phead);
//銷毀乙個單鏈表
void linklistdestroy(node** phead);
//判空
size_t linklistempty(node** phead);
/***************************************/
//鍊錶的初始化
void linklistinit(node** phead)
//建立新結點
node* linklistcreatnode(datatype data)
//銷毀結點
void linklistidestroynode(node** phead)
//遍歷列印鍊錶
void linklistprint(node** phead)
printf("null\n");
}//尾插元素
void linklistpushback(node** phead, datatype data)
//否則從頭開始遍歷鍊錶,直到當前節點的指標域指向null,然後讓當前節
//點的指標域指向新申請的節點即可
node* ptail =
*phead;
while (ptail->_pnext)
ptail->_pnext = newnode;
}//尾刪元素
void linklistpopback(node** phead)
//如果當前只有乙個結點,則釋放該結點,
//並將頭指標指向null,防止出現野指標--相當於銷毀結點
if ((*phead)->_pnext ==
null)
//定義兩個指標,依次向後走
//ptail不為空時,將其前乙個結點指標ppretail賦給ptail
//當ptail為空時,釋放ptail,ppretail指向null
node* ptail =
*phead;
node* ppretail =
null;
while (ptail->_pnext)
free(ptail);
ppretail->_pnext =
null;
}//頭插元素
void linklistpushfront(node** phead, datatype data)
//頭刪元素
void linklistpopfront(node** phead)
pdel =
*phead;
*phead = pdel->_pnext;
free(pdel);
}//查詢元素
size_t linklistfind(node** phead, datatype data)
node* pfind =
*phead;
while (pfind && pfind->_data !=
data)
pfind = pfind->_pnext;
if (pfind !=
null)
else
printf("沒有找到資料%d\n",data);
return-1;
}//任意位置的插入
void linklistinsert(node** phead, node* pos, datatype data)
if (pos ==
null)
if (pos ==
*phead)
node* pcur =
*phead;
while (pcur->_pnext !=
null)
pcur = pcur->_pnext;
}return;
}//任意位置的刪除
void linklisterase(node** phead, node* pos)
if (pos == (*phead))
node* pe =
*phead;
while ( pe !=
null)
pe = pe->_pnext;
}return;
}//求單鏈表長度
size_t linklistsize(node** phead)
printf("鍊錶長度為%d\n",count);
return count;
}//銷毀乙個單鏈表
void linklistdestroy(node** phead)
//切記將頭指標指向空,不然將變成野指標
*phead =
null;
}//判空
size_t linklistempty(node** phead)
/***************************************/
//測試部分
void linklisttest()
C語言實現單鏈表的節點插入(帶頭結點)
我在之前一篇部落格 c語言實現單鏈表 不帶頭結點 節點的插入 中詳細實現了如何在乙個不帶頭結點的單鏈表中進行節點的插入。但是在實際應用中,帶頭結點的鍊錶更為常用,更為方便。今天我們就要來使用帶頭結點的單鏈表進行節點的插入。示例 上傳至 核心 如下 node insertnode node pnode...
C語言實現單鏈表節點的刪除(帶頭結點)
我在之前一篇部落格 c語言實現單鏈表節點的刪除 不帶頭結點 中具體實現了怎樣在乙個不帶頭結點的單鏈表的刪除乙個節點,在這一篇部落格中我改成了帶頭結點的單鏈表。演示樣例上傳至 刪除型別有兩種 1 刪除某個位置pos的節點 2 推斷x值是否在鍊錶中,若存在則刪除該節點 核心 例如以下 刪除某個位置pos...
實驗2 不帶頭節點的單鏈表
編寫函式slnklist delx linklist head,datatype x 刪除不帶頭結點單鏈表head中第乙個值為x 的結點。並構造測試用例進行測試。include slnklist.h 請將本函式補充完整,並進行測試 linklist delx linklist head,dataty...