C語言實現連結串列【一】(無頭單向非迴圈連結串列)
無頭單向非迴圈連結串列
看到這個標題,是不是有小夥伴已經懵了呢?
只學過連結串列,怎麼還有個無頭和有頭呢?怎麼還有個迴圈和非迴圈呢?怎麼還有個單向和雙向呢?一連串的疑問。。。
其實這些都是連結串列的表示形式,只不過大部分人只接觸了最簡單的單鏈表,也就是我們這裡提到的無頭單向非迴圈連結串列,最簡單的連結串列結構表示形式
話不多說,直接上圖更直觀一些
-
單鏈表結構定義:
熟悉了單鏈表的結構,下面來考慮如何在連結串列中實現資料儲存呢?
連結串列是由多個節點按照一定的邏輯順序連線形成的,每一個節點都由兩部分組成,一部分儲存資料,一部分存放下一節點的地址
程式碼實現結構如下:
typedef int LDatatype; //單個節點資料結構 typedef struct listNode { LDatatype data; struct listNode* next; }listNode;
此處我們需要區分單鏈表和雙鏈表:
單鏈表只能在前驅節點中存放後繼節點的地址,而雙鏈表不僅能夠在前驅節點存放後繼節點地址,還可以在後繼節點中存放前驅節點的地址
區分不帶頭單鏈表和帶頭帶頭單鏈表
帶不帶頭不是說看有沒有head,而是看head節點是否存放資料
對此,即便是無頭的單鏈表在構建連結串列結構的過程中,依然在頭結點存放第一個節點的地址,但頭結點僅僅放地址,而不存放資料
typedef struct linklist {
//儲存第一個節點的地址
listNode* head;
}linklist;
-
單鏈表介面宣告:
單鏈表主要也是實現資料管理儲存功能,即增刪查改的操作,包括在頭節點插入,尾結點插入,頭結點刪除,尾結點刪除,指定節點後刪除插入操作等
void linklistInit(linklist* lst); void linklistPushBack(linklist* lst,LDatatype val); listNode* createNode(LDatatype val); void linklistPopBack(linklist* lst); void linklistPushFront(linklist* lst,LDatatype val); void linklistPopFront(linklist* lst); void linkInsertAfter(listNode* node, LDatatype val); void linkPopAfter(listNode* node); listNode* linkFind(linklist* lst, LDatatype val); void linkDestory(linklist* lst); void linkPrint(linklist* lst);
-
單鏈表介面實現
-
連結串列初始化:
(1)初始化連結串列結構:
由於連結串列結構中有頭結點,初始化只需要將頭結點存放地址置為空
void linklistInit(linklist* lst)
{
if (lst == NULL)
return;
lst->head = NULL;
}
(2)建立節點
當執行插入操作的過程中,根據節點結構需要先構造出一個可以存放資料的節點
listNode* createNode(LDatatype val)
{
listNode* node = (listNode*)malloc(sizeof(listNode));
if (node != NULL)
{
node->data = val;
node->next = NULL;
}
return node;
}
注意到在建立節點中,將該節點存放下一節點地址給NULL,如果尾插,將不需在尾部節點置NULL,其餘位置插入,更新地址即可
-
單鏈表尾插
void linklistPushBack(linklist* lst, LDatatype val)
{
//空 建立節點 賦值+next置空
if (lst == NULL || lst->head == NULL)
{
lst->head = createNode(val);
}
//非空 遍歷找到尾結點 在其後插入
else
{
listNode* tail=lst->head;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = createNode(val);
}
}
-
單鏈表尾刪
只有一個頭結點情況:
遍歷找最後一個節點:
程式碼如下:
void linklistPopBack(linklist* lst)
{
if (lst == NULL || lst->head == NULL)
return;
//只有一個頭結點
if (lst->head->next == NULL)
{
lst->head = NULL;
}
//否則,遍歷找到最後一個節點
listNode* prev = NULL;
listNode* tail = lst->head;
//兩個指標同時後移查詢
while (tail->next!=NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;
}
-
單鏈表頭插
void linklistPushFront(linklist* lst,LDatatype val)
{
if (lst == NULL || lst->head == NULL)
return;
listNode* node = createNode(val);
node->next = lst->head;
lst->head = node;
}
- 單鏈表頭刪
void linklistPopFront(linklist* lst)
{
if (lst == NULL||lst->head==NULL)
return;
listNode* next= lst->head->next;
free(lst->head);
lst->head = next;
}
- 單鏈表指定節點後插入
void linkInsertAfter(listNode* node, LDatatype val)
{
if (node == NULL)
return;
listNode* newnode = createNode(val);
listNode* next = node->next;
node->next = newnode;
newnode->next = next;
}
- 單鏈表指定節點後刪除
void linkPopAfter(listNode* node)
{
if (node == NULL)
return;
//listNode* newnode = createNode(val);
listNode* next = node->next;
listNode* newnext = next->next;
free(next);
node->next = newnext;
}
- 單鏈表遍歷
listNode* linkFind(linklist* lst, LDatatype val)
{
if (lst == NULL || lst->head == NULL)
{
return NULL;
}
listNode* cur = lst->head;
while (cur)
{
if (cur->data == val)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
- 單鏈表銷燬(刪除所有節點,但需要從頭開始刪除,並儲存後續節點)
void linkDestory(linklist* lst)
{
if (lst == NULL || lst->head == NULL)
{
return;
}
listNode* cur = lst->head;
//listNode* next = cur->next;
while (cur)
{
listNode* next = cur->next;
free(cur);
cur = next;
/*lst->head = next;
cur = lst->head;
next = next->next;*/
}
lst->head = NULL;
}
- 單鏈表某一指定節點刪除
listNode* linkErase(linklist* lst,listNode* node)
{
if (node == NULL)
return;
//listNode* newnode = createNode(val);
listNode* tmp = (listNode*)malloc(sizeof(listNode));
tmp->next = lst->head;
listNode* prev = tmp;
listNode* tail = lst->head;
//兩個指標同時後移查詢
while (tail)
{
if (tail == node)
{
prev->next = tail->next;
tail = tail->next;
}
else
{
prev = prev->next;
tail = tail->next;
}
}
lst->head = tmp->next;
free(tmp);
return lst->head;
}
正所謂千言萬語的解釋,不如一張圖解釋的清楚,不理解的小夥伴可以根據圖示來理解連結串列的指向變化,
今天分享就到這,下一次分享帶頭雙向迴圈連結串列的增刪改查實現!