您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關C語言鏈表是怎么樣的,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
概念:鏈表是一種物理存儲結構上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的 。
實際中鏈表的結構非常多樣,以下情況組合起來就有8種鏈表結構
單向或者雙向
帶頭或者不帶頭
循環或者非循環
雖然有這么多的鏈表的結構,但是我們實際中最常用還是兩種結構
無頭單向非循環鏈表:結構簡單,一般不會單獨用來存數據。實際中更多是作為其他數據結構的子結構,如哈希桶、圖的鄰接表等等。另外這種結構在筆試面試中出現很多。
帶頭雙向循環鏈表:結構最復雜,一般用在單獨存儲數據。實際中使用的鏈表數據結構,都是帶頭雙向循環鏈表。另外這個結構雖然結構復雜,但是使用代碼實現以后會發現結構會帶來很多優勢,實現反而簡單了,后面我們代碼實現了就知道了
單向鏈表結構
#pragma once #include<stdio.h> #include<string.h> #include<stdlib.h> #include<assert.h> typedef int SLTDataType; typedef struct SListNode { int data;//數據 struct SListNode* next;//下一個節點的地址 }SListNode; void SListPrint(SListNode* phead);//打印 SListNode* BuySListNode(SLTDataType x);//搞出一個新節點 void SListPushBack(SListNode** pphead, SLTDataType x);//尾插 void SListPushFront(SListNode** pphead, SLTDataType x);//頭插 void SListPopBack(SListNode** pphead);//尾刪 void SListPopFront(SListNode** pphead);//頭刪 SListNode* SListFind(SListNode* phead, SLTDataType x);//查找 void SListInsert(SListNode** pphead, SListNode* pos, SLTDataType x);//在pos位置之前插入 void SListInsertAfter(SListNode* pos, SLTDataType x);//在pos位置之后插入 void SListErase(SListNode** pphead, SListNode* pos);//刪除pos位置 void SListEraseAfter(SListNode* pos);//刪除pos之后位置 void SListDestroy(SListNode** pphead);//銷毀
//打印 void SListPrint(SListNode* phead) { //assert(phead);//沒必要斷言,空鏈表也能打印 SListNode* cur = phead; while (cur != NULL) { printf("%d->", cur->data); cur = cur->next; } printf("NULL\n"); }
//test.c void TestSList1() { SListNode* slist;//結構體指針,用于存節點的地址 SListNode* n1 = (SListNode *)malloc(sizeof(SListNode)); SListNode* n2 = (SListNode*)malloc(sizeof(SListNode)); SListNode* n3 = (SListNode*)malloc(sizeof(SListNode)); n1->data = 1; n2->data = 2; n3->data = 3; n1->next = n2; n2->next = n3; n3->next = NULL; slist = n1; SListPrint(slist); }
//搞出一個新節點 SListNode* BuySListNode(SLTDataType x) { SListNode* newnode = (SListNode*)malloc(sizeof(SListNode)); if (newnode == NULL) { printf("malloc fail\n"); exit(-1); } else { newnode->data = x; newnode->next = NULL; } return newnode; }
//尾插 void SListPushBack(SListNode** pphead,SLTDataType x)//會改變實參slist,要傳二級指針 { assert(pphead);//就算鏈表是空,它的二級指針也不為空 SListNode* newnode = BuySListNode(x); if (*pphead == NULL) { *pphead = newnode; } else { //遍歷找尾 SListNode* tail = *pphead; while (tail->next != NULL) { tail = tail->next; } tail->next = newnode; } }
void TestSList2() { SListNode* slist = NULL; for (int i = 0; i < 6; i++) { SListPushBack(&slist,i); } SListPrint(slist); }
//頭插 void SListPushFront(SListNode** pphead, SLTDataType x) { assert(pphead);//就算鏈表是空,它的二級指針也不為空 SListNode* newnode = BuySListNode(x); newnode->next = *pphead; *pphead = newnode; }
void TestSList2() { SListNode* slist = NULL; for (int i = 0; i < 6; i++) { SListPushFront(&slist,i); } SListPrint(slist); }
方法1(用兩個指針,分別找最后一個和倒數第二個):
方法2(直接找倒數第二個):
//尾刪 void SListPopBack(SListNode** pphead)//如果只有一個節點但還要尾刪,就會改變實參slist,建議傳二級指針 { assert(pphead);//就算鏈表是空,它的二級指針也不為空 //三種情況: //1.空 //2.一個節點 //3.多個節點 if (*pphead == NULL) { return; } else if ((*pphead)->next == NULL)//優先級,記得加括號 { free(*pphead); *pphead = NULL; } //第一種寫法(用兩個指針,分別找最后一個和倒數第二個) else { SListNode* prev = NULL;//找倒數第二個元素,用于將它指向NULL SListNode* tail = *pphead;//找尾 while (tail->next != NULL) { prev = tail; tail = tail->next; } free(tail); tail = NULL;//習慣性free掉就將其置空 prev->next = NULL; } //方法二(直接找倒數第二個) //else //{ //SListNode* tail = *pphead;//找尾 //while (tail->next->next != NULL) //{ // tail = tail->next; //} //free(tail->next); //tail->next = NULL; //} }
//頭刪 void SListPopFront(SListNode** pphead) { assert(pphead); //1.空 //2.非空 if (*pphead == NULL) { return; } else { SListNode* next = (*pphead)->next; free(*pphead); *pphead = next; } }
//查找 SListNode* SListFind(SListNode* phead, SLTDataType x) { SListNode* cur = phead; while (phead != NULL) { if (cur->data == x) { return cur; } cur = cur->next; } return NULL; }
//在pos位置之前插入(一般跟find配合使用) void SListInsert(SListNode** pphead, SListNode* pos, SLTDataType x) { assert(pphead); assert(pos);//間接檢測鏈表是否為空,因為空鏈表找不到pos //1.pos是第一個節點(頭插) //2.pos不是第一個節點 if (pos == *pphead) { SListPushFront(pphead, x); } else { SListNode* prev = *pphead; while (prev->next != pos) { prev = prev->next; } SListNode* newnode = BuySListNode(x); prev->next = newnode; newnode->next = pos; } }
方法1:兩個指針,先連接pos和newnode還是先連接newnode和next都行
方法2:只有一個指針,一定要先通過pos連接newnode和下一個,再連接pos和newnode,否則會找不到下一個的地址。
//在pos位置之后插入 void SListInsertAfter(SListNode* pos, SLTDataType x) { assert(pos); SListNode* newnode = BuySListNode(x); SListNode* next = pos->next; newnode->next = next;//順序無所謂 pos->next = newnode; //或者不定義next //newnode->next = pos->next; //pos->next = newnode;//順序要定好,否則會找不到 }
//刪除pos位置 void SListErase(SListNode** pphead, SListNode* pos) { assert(pphead); assert(pos); if (pos == *pphead) { SListPopFront(pphead); } else { SListNode* prev = *pphead; while (prev->next != pos) { prev = prev->next; } prev->next = pos->next; free(pos); pos = NULL;//好習慣 } }
//刪除pos之后位置 void SListEraseAfter(SListNode* pos) { assert(pos); SListNode* next = pos->next; if (next)//防止pos是最后一個元素 { pos->next = next->next; free(next); next = NULL; } }
一個個找,一個個銷毀,最終將slist置空。
//銷毀 void SListDestroy(SListNode** pphead) { assert(pphead); SListNode* cur = *pphead; while (cur) { SListNode* next = cur->next; free(cur); cur = next; } *pphead = NULL; }
關于“C語言鏈表是怎么樣的”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。