C語言中帶頭雙向循環(huán)鏈表基本操作的實現(xiàn)詳解
一、概念與結(jié)構(gòu)
無頭單向非循環(huán)鏈表結(jié)構(gòu)簡單,一般不會單獨用來存數(shù)據(jù)。實際中更多的是作為其他數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),如哈希桶、圖的鄰接表等等。而帶頭雙向循環(huán)鏈表的結(jié)構(gòu)較為復雜,一般用在單獨存儲數(shù)據(jù)。實際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表,雖然它的結(jié)構(gòu)復雜但是因為結(jié)構(gòu)優(yōu)勢用代碼實現(xiàn)起來會變得簡單。
二、基本操作的實現(xiàn)
1.創(chuàng)建結(jié)點
LTNode* BuyListNode(ListDataType x) { LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); if (newnode == NULL) { perror("malloc"); exit(-1); } newnode->val = x; newnode->prev = NULL; newnode->next = NULL; return newnode; }
2.初始化鏈表
void ListInit(LTNode** pphead)//初始化 { *pphead = (LTNode*)malloc(sizeof(LTNode)); *pphead = BuyListNode(-1); (*pphead)->next = *pphead; (*pphead)->prev = *pphead; } //LTNode* ListInit()//初始化 //{ // LTNode* phead = BuyListNode(-1);//初始化時將頭結(jié)點置為-1; // phead->next = phead; // phead->prev = phead; // return phead; //}
初始化鏈表有兩種方式,一種是有返回類型(注釋部分),另一種是在初始化函數(shù)中給結(jié)構(gòu)體開辟空間(不過注意參數(shù)要為二級指針)。因為是帶頭結(jié)點的循環(huán)鏈表,所以prev和next指針都指向自己。
3.打印鏈表
void ListPrint(LTNode* phead)//打印 { assert(phead); LTNode* cur = phead->next; while (cur != phead) { printf("%d ", cur->val); cur = cur->next; } printf("\n"); }
注意while循環(huán)的結(jié)束條件,保證能夠打印鏈表中的所有有效值。要對頭結(jié)點進行assert判斷,不能為空。
4.尾插
void ListPushBack(LTNode* phead, ListDataType x)//尾插 { assert(phead); LTNode* newnode = BuyListNode(x); LTNode* tail = phead->prev; newnode->next = tail->next; phead->prev = newnode; newnode->prev = tail; tail->next = newnode; //ListInsert(phead, x); }
5.尾刪
void ListPopBack(LTNode* phead)//尾刪 { assert(phead); assert(phead->next != phead); LTNode* prevnode = phead->prev; prevnode->prev->next = phead; phead->prev = prevnode->prev; free(prevnode); //ListErase(phead->prev); }
尾刪時要注意判斷phead->next != phead,不能刪除頭結(jié)點,同時記得要free(prevnode)釋放刪除后的空間。
6.頭插
void ListPushFront(LTNode* phead, ListDataType x)//頭插 { assert(phead); LTNode* tail = phead->next; LTNode* newnode = BuyListNode(x); tail->prev = newnode; newnode->next = tail; newnode->prev = phead; phead->next = newnode; //ListInsert(phead->next,x); }
7.頭刪
void ListPopFront(LTNode* phead)//頭刪 { assert(phead); assert(phead->next != phead); LTNode* tail = phead->next; phead->next = tail->next; tail->next->prev = phead; //ListErase(phead->next); }
8.查找某個數(shù)并返回其指針
LTNode* ListFind(LTNode* phead, ListDataType x)//找某個數(shù)返回其指針 { assert(phead); LTNode* cur = phead->next; while (cur != phead) { if (cur->val == x) { return cur; } cur = cur->next; } return NULL; }
9.在某個位置之前插入
void ListInsert(LTNode* pos, ListDataType x)//在pos之前插入 { assert(pos); LTNode* newnode = BuyListNode(x); LTNode* tail = pos->prev; tail->next = newnode; newnode->prev = tail; newnode->next = pos; pos->prev = newnode; }
10.刪除某個位置
void ListErase(LTNode* pos)//刪除pos位置 { assert(pos); LTNode* prevnode = pos->prev; LTNode* nextnode = pos->next; free(pos); prevnode->next = nextnode; nextnode->prev = prevnode; /*pos->next->prev = pos->prev; pos->prev->next = pos->next; free(pos);*/ }
11.判斷鏈表是否為空
bool ListEmpty(LTNode* phead)//判斷是否為空,如果是空,返回true { assert(phead); return phead->next == phead; }
12.計算鏈表中有效值的個數(shù)
size_t ListSize(LTNode* phead)//計算鏈表中有效值的個數(shù) { assert(phead); size_t size = 0; LTNode* tail = phead->next; while (tail != phead) { size++; tail = tail->next; } return size; }
13.銷毀鏈表
void ListDestroy(LTNode* phead)//銷毀鏈表 { assert(phead); LTNode* tail = phead->next; while (tail != phead) { LTNode* nextnode = tail->next; free(tail); tail = nextnode; } free(phead); }
銷毀鏈表時要注意要保證每個結(jié)點都釋放,同時最后也要將頭結(jié)點釋放free(phead)。
三、測試代碼
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <assert.h> typedef int ListDataType; typedef struct ListNode { ListDataType val; struct ListNode* prev; struct ListNode* next; }LTNode; LTNode* BuyListNode(ListDataType x) { LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); if (newnode == NULL) { perror("malloc"); exit(-1); } newnode->val = x; newnode->prev = NULL; newnode->next = NULL; return newnode; } void ListInit(LTNode** pphead)//初始化 { *pphead = (LTNode*)malloc(sizeof(LTNode)); *pphead = BuyListNode(-1); (*pphead)->next = *pphead; (*pphead)->prev = *pphead; } //LTNode* ListInit()//初始化 //{ // LTNode* phead = BuyListNode(-1);//初始化時將頭結(jié)點置為-1; // phead->next = phead; // phead->prev = phead; // return phead; //} void ListPrint(LTNode* phead)//打印 { assert(phead); LTNode* cur = phead->next; while (cur != phead) { printf("%d ", cur->val); cur = cur->next; } printf("\n"); } void ListPushBack(LTNode* phead, ListDataType x)//尾插 { assert(phead); LTNode* newnode = BuyListNode(x); LTNode* tail = phead->prev; newnode->next = tail->next; phead->prev = newnode; newnode->prev = tail; tail->next = newnode; //ListInsert(phead, x); } void ListPopBack(LTNode* phead)//尾刪 { assert(phead); assert(phead->next != phead); LTNode* prevnode = phead->prev; prevnode->prev->next = phead; phead->prev = prevnode->prev; free(prevnode); //ListErase(phead->prev); } void ListPushFront(LTNode* phead, ListDataType x)//頭插 { assert(phead); LTNode* tail = phead->next; LTNode* newnode = BuyListNode(x); tail->prev = newnode; newnode->next = tail; newnode->prev = phead; phead->next = newnode; //ListInsert(phead->next,x); } void ListPopFront(LTNode* phead)//頭刪 { assert(phead); assert(phead->next != phead); LTNode* tail = phead->next; phead->next = tail->next; tail->next->prev = phead; //ListErase(phead->next); } LTNode* ListFind(LTNode* phead, ListDataType x)//找某個數(shù)返回其指針 { assert(phead); LTNode* cur = phead->next; while (cur != phead) { if (cur->val == x) { return cur; } cur = cur->next; } return NULL; } void ListInsert(LTNode* pos, ListDataType x)//在pos之前插入 { assert(pos); LTNode* newnode = BuyListNode(x); LTNode* tail = pos->prev; tail->next = newnode; newnode->prev = tail; newnode->next = pos; pos->prev = newnode; } void ListErase(LTNode* pos)//刪除pos位置 { assert(pos); LTNode* prevnode = pos->prev; LTNode* nextnode = pos->next; free(pos); prevnode->next = nextnode; nextnode->prev = prevnode; /*pos->next->prev = pos->prev; pos->prev->next = pos->next; free(pos);*/ } bool ListEmpty(LTNode* phead)//判斷是否為空,如果是空,返回true { assert(phead); return phead->next == phead; } size_t ListSize(LTNode* phead)//計算鏈表中有效值的個數(shù) { assert(phead); size_t size = 0; LTNode* tail = phead->next; while (tail != phead) { size++; tail = tail->next; } return size; } void ListDestroy(LTNode* phead)//銷毀鏈表 { assert(phead); LTNode* tail = phead->next; while (tail != phead) { LTNode* nextnode = tail->next; free(tail); tail = nextnode; } free(phead); } void TestList() { //LTNode* plist = ListInit(&plist); LTNode* plist = NULL; ListInit(&plist); ListPushBack(plist, 100); ListPushBack(plist, 200); ListPushBack(plist, 300); ListPushBack(plist, 400); ListPushBack(plist, 500); ListPopBack(plist); ListPopBack(plist); ListPopBack(plist); ListPrint(plist); ListPushFront(plist, 1000); ListPushFront(plist, 2000); ListPushFront(plist, 3000); ListPopFront(plist); ListPopFront(plist); ListPrint(plist); LTNode* pos = ListFind(plist, 1000); if (pos != NULL) { ListInsert(pos, 500); ListErase(pos); } ListPrint(plist); if (!ListEmpty(plist)) printf("%d\n", ListSize(plist)); } int main() { TestList(); return 0; }
以上就是C語言中帶頭雙向循環(huán)鏈表基本操作的實現(xiàn)詳解的詳細內(nèi)容,更多關(guān)于C語言 帶頭雙向循環(huán)鏈表的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c語言中十六進制轉(zhuǎn)二進制顯示的實現(xiàn)方法
本篇文章對c語言中十六進制轉(zhuǎn)二進制顯示的實現(xiàn)方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05