带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个链表虽然结构复杂,但是使用代码实现以后会发现能带来很多优势.
Lish.h中部分声明
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* prev;
struct ListNode* next;
LTDataType data;
}ListNode;
prev为结点中的指向前一个结点的指针 , next 为指针中的指向后一个结点的指针 , data为结点中的数据
动态申请一个大小为sizeof(ListNode)的结点
// 动态申请一个结点
ListNode*BuyListNode(LTDataType x)
{
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if(newNode == NULL)
{
printf("分配内存失败\n");
exit(-1);
}
newNode->prev = newNode->next = NULL;
newNode->data = x;
return newNode;
}
因为为带头的双向循环链表,因此初始化头结点时,头结点的prev,next指针都指向自已
// 创建头结点进行初始化
ListNode* ListInit()
{
ListNode* plist = BuyListNode(0); // 头结点中的数据初始化为 0
plist->prev = plist->next = plist;
return plist;
}
通过头结点的prev指针可以找到尾结点tail,tail->next指向待插入的结点,待插入结点的prev指针指向tail,头结点的prev指针指向待插入结点,待插入结点的next指向头结点
// 尾插
void ListPushBack(ListNode* plist,LTDataType x)
{
assert(plist);
ListNode* newNode = BuyListNode(x);
ListNode* tail = plist->prev;
tail->next = newNode;
newNode->prev = tail;
newNode->next = plist;
plist->prev = newNode;
}
通过头结点的prev指针找到尾结点tail,通过tail的prev指针找到 tailPrev结点
要使tailPrev成为尾结点,将tailPrev结点和plist头结点连接到一起
// 尾删
void ListPopBack(ListNode* plist)
{
assert(plist);
assert(plist->next != plist);
ListNode* tail = plist->prev;
ListNode* tailPrev = tail->prev;
tailPrev->next = plist;
plsit->prev = tailPrev;
free(tail);
tail = NULL;
}
动态申请一个结点newNode,通过plist->next找到当前的第一个结点(first),newNode结点要插入到plist头结点和first结点之间
// 头插
void ListPushFront(ListNode* plist,LTDataType x)
{
assert(plist);
ListNode* newNode = BuyListNode(x);
ListNode* first = plist->next;
plist->next = newNode;
newNode->prev = plist;
newNode->next = first;
first->prev = newNode;
}
通过plist->next找到第一个结点(first),first->next找到第二个结点(second),将plist头结点和second结点连接到一起,释放掉第一个结点(first)
// 头删
void ListPopFront(ListNode* plist)
{
assert(plist);
assert(plist->next != plist);
ListNode* first = plist->next;
ListNode* second = first->next;
plist->next = second;
second->prev = plist;
free(first);
first = NULL;
}
遍历一次链表,终止条件为 cur != plist ,因为 cur = plist 说明已经循环了一遍
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* cur = plist->next;
while (cur != plist)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
动态申请一个结点 ,找到pos位置的前一个结点(posPrev),将pos,posPrev,newNode结点连接到一起
// 在pos位置前插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* newNode = BuyListNode(x);
ListNode* posPrev = pos->prev;
posPrev->next = newNode;
newNode->prev = posPrev;
newNode->next = pos;
pos->prev = newNode;
}
找到pos的前一个结点(posPrev)和后一个结点(posNext),将posPrev,posNext结点连接到一起,删除掉pos结点
// 删除pos位置的结点
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* PosPrev = pos->prev;
ListNode* PosNext = pos->next;
PosPrev->next = PosNext;
PosNext->prev = PosPrev;
free(pos);
pos = NULL;
}
遍历一次链表,终止条件为 cur != plist ,因为 cur = plist 说明已经循环了一遍
// 打印
void Listprint(ListNode* plist)
{
assert(plist);
ListNode* cur = plist->next;
while (cur != plist)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
List.h文件
#pragma once
#include
#include
#include
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* prev;
struct ListNode* next;
LTDataType data;
}ListNode;
// 初始化创建头结点
ListNode* ListInit();
// 动态申请一个结点
ListNode* BuyListNode(LTDataType x);
// 打印
void Listprint(ListNode* plist);
// 尾插
void ListPushBack(ListNode* plist, LTDataType x);
// 尾删
void ListPopBack(ListNode* plist);
// 头插
void ListPushFront(ListNode* plist, LTDataType x);
// 头删
void ListPopFront(ListNode* plist);
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x);
// 在pos前插入
void ListInsert(ListNode* pos, LTDataType x);
// 删除pos位置的结点
void ListErase(ListNode* pos);
Lish.c文件
#include"List.h"
// 初始化创建头结点
ListNode* ListInit()
{
ListNode* phead = BuyListNode(0);
phead->next = phead;
phead->prev = phead;
return phead;
}
// 动态申请一个结点
ListNode* BuyListNode(LTDataType x)
{
ListNode* NewNode = (ListNode*)malloc(sizeof(ListNode));
if (NewNode == NULL)
{
printf("分配内存失败\n");
exit(-1);
}
NewNode->prev = NewNode->next = NULL;
NewNode->data = x;
return NewNode;
}
// 打印
void Listprint(ListNode* plist)
{
assert(plist);
ListNode* cur = plist->next;
while (cur != plist)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
// 尾插
void ListPushBack(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* NewNode = BuyListNode(x);
ListNode* tail = plist->prev;
tail->next = NewNode;
NewNode->prev = tail;
plist->prev = NewNode;
NewNode->next = plist;
}
// 尾删
void ListPopBack(ListNode* plist)
{
assert(plist);
assert(plist->next != plist);
ListNode* tail = plist->prev;
ListNode* tail_prev = tail->prev;
tail_prev->next = plist;
plist->prev = tail_prev;
free(tail);
tail = NULL;
}
// 头插
void ListPushFront(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* NewNode = BuyListNode(x);
ListNode* first = plist->next;
plist->next = NewNode;
NewNode->prev = plist;
NewNode->next = first;
first->prev = NewNode;
}
// 头删
void ListPopFront(ListNode* plist)
{
assert(plist);
assert(plist->next != plist);
ListNode* first = plist->next;
ListNode* second = first->next;
plist->next = second;
second->prev = plist;
free(first);
first = NULL;
}
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* cur = plist->next;
while (cur != plist)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
// 在pos位置前插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* NewNode = BuyListNode(x);
ListNode* PosPrev = pos->prev;
PosPrev->next = NewNode;
NewNode->prev = PosPrev;
NewNode->next = pos;
pos->prev = NewNode;
}
// 删除pos位置的结点
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* PosPrev = pos->prev;
ListNode* PosNext = pos->next;
PosPrev->next = PosNext;
PosNext->prev = PosPrev;
free(pos);
pos = NULL;
}
TestLish.c文件
#include"List.h"
void TestList01()
{
ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushBack(plist, 4);
Listprint(plist);
ListPopBack(plist);
ListPopBack(plist);
ListPopBack(plist);
ListPopBack(plist);
// ListPopBack(plist);
Listprint(plist);
ListPushFront(plist, 1);
ListPushFront(plist, 2);
ListPushFront(plist, 3);
ListPushFront(plist, 4);
Listprint(plist);
ListPopFront(plist);
ListPopFront(plist);
ListPopFront(plist);
ListPopFront(plist);
// ListPopFront(plist);
Listprint(plist);
}
void TestList02()
{
ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushBack(plist, 4);
ListNode* pos = ListFind(plist, 3);
ListInsert(pos, 30);
Listprint(plist);
ListErase(pos);
Listprint(plist);
}
int main()
{
TestList01();
TestList02();
}