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)較為復(fù)雜,一般用在單獨存儲數(shù)據(jù)。實際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表,雖然它的結(jié)構(gòu)復(fù)雜但是因為結(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

