带头双向循环链表
什么是带头双向循环链表?
有一个哨兵位的头节点做链表的头,数据与数据之间相互链接,使得数据之间的增删查改操作更加方便
带头双向循环链表实现—Leading bidirectional circular linked list
链表的定义
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}BCL;
我们用next指向链接的下一个节点,用prev指向链接的上一个节点
链表接口定义
// 创建返回链表的头节点
BCL* ListCreate();
// 双向链表销毁
void ListDestory(BCL* phead);
// 双向链表打印
void ListPrint(BCL* phead);
//申请一个节点
BCL* BuyListNode(LTDataType x);
//判断链表是否为空
bool ListEmpty(BCL* phead);
// 双向链表尾插
void ListPushBack(BCL* phead, LTDataType x);
// 双向链表尾删
void ListPopBack(BCL* phead);
// 双向链表头插
void ListPushFront(BCL* phead, LTDataType x);
// 双向链表头删
void ListPopFront(BCL* phead);
// 双向链表查找
BCL* ListFind(BCL* phead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(BCL* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(BCL* pos);
链表增加与删除
哨兵节点
我们首先先申请一块空间用来存放哨兵位的头节点,这个哨兵节点不存储数据
在没有存储数据之前,将哨兵节点指向自己这样构成循环
// 创建返回链表的头节点
BCL* ListCreate()
{
BCL* guard = (BCL*)malloc(sizeof(BCL));
if (guard == NULL)
{
perror("malloc fail");
exit(-1);
}
guard->next = guard;
guard->prev = guard;
return guard;
}
申请新节点
//申请一个节点
BCL* BuyListNode(LTDataType x)
{
BCL* newnode = (BCL*)malloc(sizeof(BCL));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->next = NULL;
newnode->prev = NULL;
newnode->data = x;
return newnode;
}
头插头删
// 双向链表头插
void ListPushFront(BCL* phead, LTDataType x)
{
assert(phead);
BCL* newnode = BuyListNode(x);
BCL* first = phead->next;
phead->next = newnode;
newnode->prev = phead;
newnode->next = first;
first->prev = newnode;
}
// 双向链表头删
void ListPopFront(BCL* phead)
{
assert(phead);
assert(!ListEmpty(phead));
BCL* first = phead->next;
phead->next = first->next;
first->next->prev = phead;
free(first);
first = NULL;
}
尾插尾删
// 双向链表尾插
void ListPushBack(BCL * phead, LTDataType x)
{
assert(phead);
BCL* newnode = BuyListNode(x);
BCL* Tail = phead->prev;
Tail->next = newnode;
newnode->prev = Tail;
newnode->next = phead;
phead->prev = newnode;
}
// 双向链表尾删
void ListPopBack(BCL* phead)
{
assert(phead);
assert(!ListEmpty(phead));
BCL* tail = phead->prev;
BCL* prev = tail->prev;
prev->next = phead;
phead->prev = prev;
free(tail);
tail = NULL;
}
链表查找
// 双向链表查找
BCL* ListFind(BCL* phead, LTDataType x)
{
assert(phead);
BCL* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
链表更改
POS之前插入节点
// 双向链表在pos的前面进行插入
void ListInsert(BCL* pos, LTDataType x)
{
assert(pos);
BCL* newnode = BuyListNode(x);
BCL* cur = pos->prev;
cur->next = newnode;
newnode->prev = cur;
newnode->next = pos;
pos->prev = newnode;
}
删除POS位置节点
// 双向链表删除pos位置的节点
void ListErase(BCL* pos)
{
assert(pos);
BCL* prev = pos->prev;
prev->next = pos->next;
pos->next->prev = prev;
free(pos);
pos = NULL;
}
头文件代码
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}BCL;
// 创建返回链表的头节点
BCL* ListCreate();
// 双向链表销毁
void ListDestory(BCL* phead);
// 双向链表打印
void ListPrint(BCL* phead);
//申请一个节点
BCL* BuyListNode(LTDataType x);
//判断链表是否为空
bool ListEmpty(BCL* phead);
// 双向链表尾插
void ListPushBack(BCL* phead, LTDataType x);
// 双向链表尾删
void ListPopBack(BCL* phead);
// 双向链表头插
void ListPushFront(BCL* phead, LTDataType x);
// 双向链表头删
void ListPopFront(BCL* phead);
// 双向链表查找
BCL* ListFind(BCL* phead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(BCL* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(BCL* pos);
接口实现代码
#include "List.h"
// 创建返回链表的头节点
BCL* ListCreate()
{
BCL* guard = (BCL*)malloc(sizeof(BCL));
if (guard == NULL)
{
perror("malloc fail");
exit(-1);
}
guard->next = guard;
guard->prev = guard;
return guard;
}
// 双向链表销毁
void ListDestory(BCL* phead)
{
assert(phead);
BCL* cur = phead->next;
while (cur != phead)
{
BCL* next = cur->next;
free(cur);
cur = NULL;
cur = next;
}
free(phead);
//phead是形参,形参改变外面的实参无变化,要么使用二级指针要么在外面再置NULL
//phead=NULL 这样做没有效果
}
// 双向链表打印
void ListPrint(BCL* phead)
{
assert(phead);
BCL* cur = phead->next;
while (cur != phead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
//申请一个节点
BCL* BuyListNode(LTDataType x)
{
BCL* newnode = (BCL*)malloc(sizeof(BCL));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->next = NULL;
newnode->prev = NULL;
newnode->data = x;
return newnode;
}
//判断链表是否为空
bool ListEmpty(BCL* phead)
{
assert(phead);
return phead->next == phead;
}
// 双向链表尾插
void ListPushBack(BCL * phead, LTDataType x)
{
//第一种方法
//assert(phead);
//BCL* newnode = BuyListNode(x);
//BCL* Tail = phead->prev;
//Tail->next = newnode;
//newnode->prev = Tail;
//newnode->next = phead;
//phead->prev = newnode;
//第二种方法
ListInsert(phead, x);
}
// 双向链表尾删
void ListPopBack(BCL* phead)
{
assert(phead);
assert(!ListEmpty(phead));
//1.
//BCL* Tail = phead->prev;
//Tail->prev->next = phead;
//phead->prev = Tail->prev;
//free(Tail);
//Tail = NULL;
//2.
//BCL* tail = phead->prev;
//BCL* prev = tail->prev;
//prev->next = phead;
//phead->prev = prev;
//free(tail);
//tail = NULL;
//3.
ListErase(phead->prev);
}
// 双向链表头插
void ListPushFront(BCL* phead, LTDataType x)
{
//1.
//assert(phead);
//BCL* newnode = BuyListNode(x);
//BCL* first = phead->next;
//phead->next = newnode;
//newnode->prev = phead;
//newnode->next = first;
//first->prev = newnode;
//2.
ListInsert(phead->next, x);
}
// 双向链表头删
void ListPopFront(BCL* phead)
{
//1.
//assert(phead);
//assert(!ListEmpty(phead));
//BCL* first = phead->next;
//phead->next = first->next;
//first->next->prev = phead;
//free(first);
//first = NULL;
//2.
ListErase(phead->next);
}
// 双向链表查找
BCL* ListFind(BCL* phead, LTDataType x)
{
assert(phead);
BCL* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(BCL* pos, LTDataType x)
{
assert(pos);
BCL* newnode = BuyListNode(x);
BCL* cur = pos->prev;
cur->next = newnode;
newnode->prev = cur;
newnode->next = pos;
pos->prev = newnode;
}
// 双向链表删除pos位置的节点
void ListErase(BCL* pos)
{
assert(pos);
BCL* prev = pos->prev;
prev->next = pos->next;
pos->next->prev = prev;
free(pos);
pos = NULL;
}
结果演示
void TestList()
{
BCL* phead = ListCreate();
ListPushBack(phead, 1); //尾插
ListPushBack(phead, 2); //尾插
ListPushBack(phead, 3); //尾插
ListPushBack(phead, 4); //尾插
ListPrint(phead); //打印
ListPopBack(phead); //尾删
ListPrint(phead); //打印
ListPushFront(phead, 10); //头插
ListPrint(phead); //打印
ListPopFront(phead); //头删
ListPrint(phead); //打印
}
int main()
{
TestList();
return 0;
}
第二个
void TestList()
{
BCL* phead = ListCreate();
ListPushBack(phead, 1); //尾插
ListPushBack(phead, 2); //尾插
ListPushBack(phead, 3); //尾插
ListPushBack(phead, 4); //尾插
ListPrint(phead);
BCL* ret = ListFind(phead, 2); //找数据2
printf("%d\n", ret->data);
ListInsert(phead->next, 10); //pos之前插入 (相当与头插)
ListPrint(phead);
ListInsert(phead, 20); //pos之前插入 (相当于尾插)
ListPrint(phead);
ListErase(phead->next); // 删除pos位置
ListPrint(phead);
}
int main()
{
TestList();
return 0;
}
如果发现错误欢迎大佬们指出😸😸