这篇博客整理带头结点的双向循环链表。带头结点的双向循环链表在进行操作的时候是要比单链表更方便的,比如说在尾删的时候,不需要遍历整个链表,头结点的上一个结点就是尾结点。凡是涉及到寻找尾结点的操作,都会比单链表方便很多。
如上图所示,相比于单链表多了头结点head,每个结点里面有两个指针,分别指向前一个结点和后一个结点。
typedef int SLDataType;
typedef struct DListNode
{
struct DListNode* prev; // 指向前一个结点的指针
struct DListNode* next; // 指向后一个结点的指针
SLDataType data; // 结点中的数据
}DListNode;
(1)创建结点
// 创建一个结点(没有指向,只有值)
DListNode* BuyListNode(SLDataType x)
{
DListNode* node = (DListNode*)malloc(sizeof(DListNode));
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
(2)初始化
// 创建返回链表的头结点
DListNode* ListCreate()
{
DListNode* head = BuyListNode(0);
head->next = head;
head->prev = head;
return head;
}
和单链表不同的是,带头结点的双向循环链表需要进行初始化,创建一个头结点。初始的时候,头结点的两个指针都是指向自身的。
(3)链表销毁
// 双向链表销毁
void ListDestory(DListNode* phead)
{
assert(phead);
DListNode* cur = phead->next;
while (cur != phead)
{
DListNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
注意:
phead==NULL
是因为我们传入的是一级指针,即传入的是phead的一份拷贝,就算写了这一句代码也不能真的修改phead,所以就需要自己在外面写这句代码。(4)打印链表
// 双向链表打印
void ListPrint(DListNode* phead)
{
assert(phead);
DListNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
(5)尾插
// 双向链表尾插
void ListPushBack(DListNode* phead, SLDataType x)
{
assert(phead);
DListNode* newnode = BuyListNode(x);
DListNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
这就比单链表要好多了,不需要通过遍历来寻找尾结点。
(6)尾删
// 双向链表尾删
void ListPopBack(DListNode* phead)
{
assert(phead);
DListNode* tail = phead->prev;
if (tail == phead)
{
printf("链表已空!\n");
return;
}
tail->prev->next = phead;
phead->prev = tail->prev;
free(tail);
}
(7)头插
// 双向链表头插
void ListPushFront(DListNode* phead, SLDataType x)
{
assert(phead);
DListNode* first = phead->next;
DListNode* newnode = BuyListNode(x);
newnode->next = first;
newnode->prev = phead;
phead->next = newnode;
first->prev = newnode;
}
(8)头删
// 双向链表头删
void ListPopFront(DListNode* phead)
{
assert(phead);
if (phead->next == phead)
{
printf("链表已空!\n");
return;
}
DListNode* first = phead->next;
phead->next = first->next;
first->next->prev = phead;
free(first);
}
(9)查找
// 双向链表查找
DListNode* ListFind(DListNode* phead, SLDataType x)
{
assert(phead);
DListNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
(10)在pos位置插入
// 双向链表在pos的前面进行插入
void ListInsert(DListNode* pos, SLDataType x)
{
assert(pos);
DListNode* newnode = BuyListNode(x);
DListNode* prev = pos->prev;
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
跟单链表相比,这里也省去了遍历的步骤,pos->prev
直接就能找到上一个结点。
(11)删除pos位置的节点
// 双向链表删除pos位置的节点
void ListErase(DListNode* pos)
{
assert(pos);
DListNode* prev = pos->prev;
DListNode* next = pos->next;
free(pos);
prev->next = next;
next->prev = prev;
}
一共三个程序
DList.h
头文件DList.c
接口函数实现Test_DList.c
测试程序#pragma once
#include
#include
#include
typedef int SLDataType;
typedef struct DListNode
{
struct DListNode* prev;
struct DListNode* next;
SLDataType data;
}DListNode;
// 创建返回链表的头结点.
DListNode* ListCreate();
// 双向链表销毁
void ListDestory(DListNode* phead);
// 双向链表打印
void ListPrint(DListNode* phead);
// 双向链表尾插
void ListPushBack(DListNode* phead, SLDataType x);
// 双向链表尾删
void ListPopBack(DListNode* phead);
// 双向链表头插
void ListPushFront(DListNode* phead, SLDataType x);
// 双向链表头删
void ListPopFront(DListNode* phead);
// 双向链表查找
DListNode* ListFind(DListNode* phead, SLDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(DListNode* pos, SLDataType x);
// 双向链表删除pos位置的节点
void ListErase(DListNode* pos);
#include "DList.h"
// 创建一个结点(没有指向,只有值)
DListNode* BuyListNode(SLDataType x)
{
DListNode* node = (DListNode*)malloc(sizeof(DListNode));
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
// 创建返回链表的头结点
DListNode* ListCreate()
{
DListNode* head = BuyListNode(0);
head->next = head;
head->prev = head;
return head;
}
// 双向链表销毁
void ListDestory(DListNode* phead)
{
assert(phead);
DListNode* cur = phead->next;
while (cur != phead)
{
DListNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
// 双向链表打印
void ListPrint(DListNode* phead)
{
assert(phead);
DListNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
// 双向链表尾插
void ListPushBack(DListNode* phead, SLDataType x)
{
assert(phead);
DListNode* newnode = BuyListNode(x);
DListNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
// 双向链表尾删
void ListPopBack(DListNode* phead)
{
assert(phead);
DListNode* tail = phead->prev;
if (tail == phead)
{
printf("链表已空!\n");
return;
}
tail->prev->next = phead;
phead->prev = tail->prev;
free(tail);
}
// 双向链表头插
void ListPushFront(DListNode* phead, SLDataType x)
{
assert(phead);
DListNode* first = phead->next;
DListNode* newnode = BuyListNode(x);
newnode->next = first;
newnode->prev = phead;
phead->next = newnode;
first->prev = newnode;
}
// 双向链表头删
void ListPopFront(DListNode* phead)
{
assert(phead);
if (phead->next == phead)
{
printf("链表已空!\n");
return;
}
DListNode* first = phead->next;
phead->next = first->next;
first->next->prev = phead;
free(first);
}
// 双向链表查找
DListNode* ListFind(DListNode* phead, SLDataType x)
{
assert(phead);
DListNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(DListNode* pos, SLDataType x)
{
assert(pos);
DListNode* newnode = BuyListNode(x);
DListNode* prev = pos->prev;
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
// 双向链表删除pos位置的节点
void ListErase(DListNode* pos)
{
assert(pos);
DListNode* prev = pos->prev;
DListNode* next = pos->next;
free(pos);
prev->next = next;
next->prev = prev;
}
#include "DList.h"
void Test()
{
DListNode* plist = ListCreate();
ListPushBack(plist, 3);
ListPushBack(plist, 4);
ListPushBack(plist, 5);
printf("尾插3,4,5的结果:");
ListPrint(plist);
ListPopBack(plist);
ListPopBack(plist);
printf("尾删2次的结果:");
ListPrint(plist);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPushFront(plist, 0);
printf("头插2,1,0的结果:");
ListPrint(plist);
ListPopFront(plist);
ListPopFront(plist);
printf("头删2次的结果:");
ListPrint(plist);
DListNode* pos = ListFind(plist, 3);
ListInsert(pos, 7);
printf("找到3,在3前面插入7的结果:");
ListPrint(plist);
pos = ListFind(plist, 7);
ListErase(pos);
printf("找到7,删除7的结果:");
ListPrint(plist);
ListDestory(plist);
plist = NULL;
}
int main()
{
Test();
return 0;
}