一文弄懂C語言如何實現單鏈表
一、單鏈表與順序表的區別:
一、順序表:
1、內存中地址連續
2、長度可以實時變化
3、不支持隨機查找
4、適用於訪問大量元素的,而少量需要增添/刪除的元素的程序
5、中間插入或者刪除比較方便,內存命中率較高
二、鏈表
1、內存中地址不連續(邏輯上連續,物理上不連續)
2、長度可以實時變化(避免浪費空間)
3、不支持隨機查找,查找的時間復雜度為o(1),
4、適用於訪問大量元素的,對訪問元素無要求的程序
5、中間插入或者刪除比較方便,效率高
二、關於鏈表中的一些函數接口的作用及實現
1、創建接口,開辟空間
2、尾插尾刪
3、頭插頭刪
4、查找並修改
5、中插中刪
ps:我看瞭許多的單鏈表文章,在插刪的接口實現上大多數是往前進行插刪,這裡寫的則是往後進行插刪
1、頭文件裡的結構體和函數聲明等等
#pragma once #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<assert.h> typedef int SListDataType; //節點 typedef struct SListNode { SListDataType data; struct SListNode* next; }SListNode; //struct SList //{ // SListNode* head; // SListNode* tail; //}; //尾插尾刪 void SListPushBack(SListNode** pphead, SListDataType x); void SListPopBack(SListNode** pphead); //頭插頭刪 void SListPushFront(SListNode** pphead, SListDataType x); void SListPopFront(SListNode** pphaed); void SListPrint(SListNode* phead); //查找並修改 SListNode* SListFind(SListNode* phead, SListDataType x); //中插中刪 void SListInserAfter(SListNode**pphead,SListNode* pos, SListDataType x); void SListEraseAfter(SListNode* pos); //從頭到尾打印鏈表 void PrintTailToHead(SListNode* pList);
2、創建接口空間
//開辟的下一個空間 SListNode* BuySListNode(SListDataType x) { SListNode* newNode = (SListNode*)malloc(sizeof(SListNode)); if (newNode == NULL) { printf("申請結點失敗\n"); exit(-1); } newNode->data = x; newNode->next = NULL; return newNode; }
3.尾插尾刪
//尾插 void SListPushBack(SListNode** pphead, SListDataType x) { SListNode* newNode = BuySListNode(x);//我們指向頭指針的那個結點是**pphead,*pphead就是頭指針的地址 //如果頭指針的地址為空,我們就把新開辟的這個空間指針(已經傳入值)再賦給頭指針,也就是下面的這個if循環 if (*pphead == NULL) { *pphead = newNode; } else { //找尾巴,判斷尾巴是不是空地址,這個函數實現的是尾插,我們找到尾巴後,如果尾巴是空地址,我們將插入的newNode賦給尾巴,此時 //實現瞭尾插,在下面的代碼中,我們首先把頭指針當成尾巴,從頭指針開始依次往後找,如果下一個不是空指針,我們就令 //tail=tail->next,此時指向下一個結點,進入循環繼續判斷,當找到後,我們再令尾巴=newNode,在上面我們也判斷瞭頭指針為空的情況 SListNode* tail = *pphead; while (tail->next!= NULL) { tail = tail -> next; } tail->next = newNode; } } void SListPopBack(SListNode** pphead) { //1、空 //2、一個結點 //3、一個以上 if (*pphead == NULL) { return; } else if ((*pphead)->next == NULL) { free(*pphead); *pphead = NULL; } else { SListNode* prev = NULL; SListNode* tail = *pphead; while (tail->next != NULL) { prev = tail; tail = tail->next; } free(tail); //tail = NULL;//這個無所謂,因為我們釋放後,出瞭這個作用域,tail和prev都被銷毀,沒人能拿到,所以不會被再找到 prev->next = NULL; } }
4、頭插頭刪
//頭插頭刪 void SListPushFront(SListNode** pphead, SListDataType x) { SListNode* newnode = BuySListNode(x); newnode->next = *pphead; *pphead = newnode; } void SListPopFront(SListNode** pphead) { //1、空 //2、一個結點+3、一個以上 if (*pphead == NULL) { return; } //(*phead)->next:*和>都是解引用,同一優先級,我們需要給*pphead帶括號,(*pphead)->next才是下一個結點 else{ //我們頭刪也會遇到情況,我們刪除第一個的話,第一個裡面還存有第二個結點的地址,我們必須在刪除前,保存第二個結點的地址 SListNode* next = (*pphead)->next; free(*pphead);//通過調試我們發現:free前後,*pphead的地址不變,但是*pphead裡的值被置為隨機值,free不僅僅把這塊空間還給操作系統 //而且還把這塊空間存的值和地址都置為隨機值 *pphead = next; } }
5、單鏈表查找
//單鏈表查找 SListNode* SListFind(SListNode* phead, SListDataType x) { SListNode* cur = phead; while (cur) { if (cur->data == x) { return cur; } cur = cur->next; } return NULL; }
6、中間插入(在pos後面進行插入)
void SListInserAfter(SListNode** pphead,SListNode* pos, SListDataType x) { assert(pos && pphead); if (*pphead == pos) { SListPushFront(pphead, x); } else { SListNode* newnode = BuySListNode(x); SListNode* tmp = *pphead; while (tmp->next != pos) { tmp = tmp->next; } tmp->next = pos; pos->next = newnode; } }
7、中間刪除(在pos後面進行刪除)
void SListEraseAfter(SListNode* pos) { //刪除pos後面的 assert(pos); if (pos->next) { //pos->next=pos->next->next//不推薦 SListNode* next = pos->next; SListNode* nextnext = next->next; pos->next = nextnext; free(next); } }
8、單獨打印鏈表和從頭到尾打印鏈表
void SListPrint(SListNode* phead) { SListNode* cur = phead; while (cur != NULL) { printf("%d->", cur->data); cur = cur->next; } printf("NULL\n"); } void PrintTailToHead(SListNode* pList) { if (pList == NULL) { return; } PrintTailToHead(pList->next); printf("%d->",pList->data); }
9、test.c
#include"SList.h" TestSList1() { SListNode* pList = NULL;//這個結構體指針指向開辟的空間,頭指針指向鏈表的開頭 SListPushBack(&pList, 1); SListPushBack(&pList, 2); SListPushBack(&pList, 3); SListPushBack(&pList, 4); SListPrint(pList); SListPopBack(&pList); SListPopBack(&pList); SListPopBack(&pList); SListPopBack(&pList); SListPopBack(&pList); SListPrint(pList); SListPushFront(&pList, 1); SListPushFront(&pList, 2); SListPushFront(&pList, 6); SListPushFront(&pList, 4); SListPushFront(&pList, 5); SListPrint(pList); SListPopFront(&pList); SListPopFront(&pList); SListPopFront(&pList); SListPopFront(&pList); SListPopFront(&pList); SListPopFront(&pList); SListPrint(pList); } TestSList2() { SListNode* pos1; SListNode* pList = NULL;//這個結構體指針指向開辟的空間,頭指針指向鏈表的開頭 SListPushBack(&pList, 1); SListPushBack(&pList, 2); SListPushBack(&pList, 3); SListPushBack(&pList, 4); SListPrint(pList); SListNode* pos = SListFind(pList, 3); if (pos) { pos->data = 30;//這裡將cur-data改為pos->data,然後再將pos-data原來的值改為30 } SListPrint(pList); pos1 = SListFind(pList, 30);//我們先去找到這個pos1的位置,然後再去插入 SListInserAfter(&pList,pos1,50);//函數傳參要對應起來,我們用指針傳用指針接收,不能在pos1位置直接寫個數字 SListPrint(pList); SListEraseAfter(pos1);//pList指向第一個結點,pList->next指向第二個結點,那麼我們刪除的是目標節點後面 SListPrint(pList); //PrintTailToHead(&pList); } int main() { TestSList1(); TestSList2(); return 0; }
總結
到此這篇關於C語言如何實現單鏈表的文章就介紹到這瞭,更多相關C語言實現單鏈表內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!