當前位置:
首頁 >
链表的结构
發布時間:2023/12/31
34
豆豆
文章目錄
- 1.1 鏈表的概念及結構
- 1.2 鏈表的分類
- 1.3 鏈表的實現
- 1.4 雙向鏈表的實現
1.1 鏈表的概念及結構
概念:鏈表是一種物理存儲結構上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的
假設在32位系統上,節點中 值位int類型,則一個節點的大小為8個字節,則也有可能有下述鏈表:
1.2 鏈表的分類
實際中鏈表的結構非常多樣,以下情況組合起來就有8種鏈表結構:
循環或者非循環
雖然有這么多的鏈表的結構,但是我們實際中最常用還是兩種結構 :
無頭單向非循環鏈表
帶頭雙向循環鏈表
1.3 鏈表的實現
sList.h:
typedef int SLT;typedef struct SListNode {SLT data;struct SListNode* next; }s;//打印鏈表 void SListPrint(s* plist);// 動態申請一個節點 s* BuySListNode(SLT x);//單鏈表尾插 void SListPushBack(s** pplist, SLT x);//單鏈表頭插 void SListPushFront(s** pplist, SLT x);//單鏈表尾刪 void SListPopBack(s** pplist);//單鏈表頭刪 void SListPopFront(s** pplist);sList.c:
//創建新節點 s* BuySListNode(SLT x) {s* NewNode = (s*)malloc(sizeof(s));NewNode->data = x;NewNode->next = NULL;return NewNode; }//打印鏈表 void SListPrint(s *plist) {assert(plist);s* tail = plist;while (tail != NULL){printf("%d ", tail->data);tail = tail->next;}printf("\n");}//尾插 void SListPushBack(s** pplist, SLT x) {s *new = BuySListNode(x);if (*pplist == NULL){*pplist = new;}else{s* tail = *pplist;while (tail->next != NULL){tail = tail->next;}tail->next = new;} }//頭插 void SListPushFront(s** pplist, SLT x) {s *NewNode = BuySListNode(x);NewNode->next = *pplist;*pplist = NewNode;}//尾刪 void SListPopBack(s** pplist) {assert(*pplist);if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}else{s* tail = *pplist;s* prev = NULL;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;} }//頭刪 void SListPopFront(s** pplist) {assert(*pplist);s* tmp = *pplist;*pplist = (*pplist)->next;free(tmp);tmp = NULL;1.4 雙向鏈表的實現
List.h:
typedef int tp;typedef struct Listnode {struct Listnode* prev;struct Listnode* next;tp data;}List; //創建新節點 List* BuyListNode(tp x); // 創建返回鏈表的頭結點. List* ListInit(void); // 雙向鏈表打印 void ListPrint(List* phead); // 雙向鏈表尾插 void ListPushBack(List* phead, tp x); // 雙向鏈表尾刪 void ListPopBack(List* phead); // 雙向鏈表頭插 void ListPushFront(List* phead, tp x); // 雙向鏈表頭刪 void ListPopFront(List* phead); // 雙向鏈表查找 List* ListSearch(List* phead, tp x); // 雙向鏈表在pos的前面進行插入 List* ListInsert(List*phead, tp y, tp x); // 雙向鏈表刪除pos位置的節點List.c:
對于帶頭雙向循環鏈表,中間插入適用于頭插與尾插,中間刪除適用于頭刪與尾刪
看代碼即可知道
//創建新節點 List* BuyListNode(tp x) {List* newnode = (List*)malloc(sizeof(List));newnode->data = x;return newnode;}//初始化鏈表 List* ListInit(void) {List* phead = BuyListNode(0);phead->next = phead;phead->prev = phead; }//尾插 void ListPushBack(List* phead, tp x) {assert(phead != NULL);List* newnode = BuyListNode(x);List* tail = phead->prev;//原來的尾節點tail->next = newnode;//尾節點指向新的節點//新節點鏈接原來的尾節點和頭節點newnode->prev = tail;newnode->next = phead;//頭節點鏈接新節點phead->prev = newnode; }//打印鏈表 void ListPrint(List* phead) {assert(phead != NULL);assert(phead->next != phead);List* cur = phead->next;while (cur != phead){printf("%d ", cur->data);cur = cur->next;}printf("\n");}//頭插 void ListPushFront(List* phead, tp x) {assert(phead != NULL);List* newnode = BuyListNode(x);List* first = phead->next;//原來的首節點phead->next = newnode;newnode->prev = phead;newnode->next = first;first->prev = newnode;}//尾刪 void ListPopBack(List* phead) {assert(phead != NULL);assert(phead->next != phead);ListErase(phead,phead->prev->data); }//頭刪 void ListPopFront(List* phead) {assert(phead != NULL);assert(phead->next != phead);ListErase(phead, phead->next->data); }//暫時只考慮找到的情況 List* ListSearch(List* phead, tp x) {assert(phead != NULL);assert(phead->next != phead);List* cur = phead->next;List* pos = NULL;while (cur != phead){if (cur->data == x){pos = cur;return pos;}cur = cur->next;} }//插在pos之前 List* ListInsert(List*phead, tp y, tp x) {List* pos = ListSearch(phead, y);List* newnode = BuyListNode(x);List* posfront = pos->prev;posfront->next = newnode;newnode->prev = posfront;newnode->next = pos;pos->prev = newnode; }//刪除pos位置的結點 void ListErase(List* phead, tp y) {assert(phead != NULL);List* pos = ListSearch(phead, y);(pos->prev)->next = (pos->next);(pos->next)->prev = pos->prev;free(pos); }關于鏈表的一些題目,可以關注作者的下一篇博客一些鏈表OJ題
光講概念畢竟是枯燥的,做更多的題目我們才能加深對鏈表的理解
總結
- 上一篇: 手写LinKedList双向链表 终于
- 下一篇: 伺服电机的选型计算方法