一、带头双向循环链表的定义和结构
1、定义
带头双向循环链表,有一个数据域和两个指针域。一个是前驱指针,指向其前一个节点;一个是后继指针,指向其后一个节点。
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
2、结构
带头双向循环链表:在所有的链表当中 结构最复杂,一般用在 单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多 优势,实现反而简单了。
二、带头双向循环链表接口的实现
1、创建文件
test.c(主函数、测试链表各个接口)
List.c(带头双向循环链表接口函数的实现)
List.h(带头双向循环链表的类型定义、接口函数声明、引用的头文件)
2、List.h头文件代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
//动态申请一个新结点
LTNode * BuyLTNode(LTDataType x);
//双链表初始化
LTNode *LTInit();
//双链表打印
void LTPrint(LTNode* phead);
//双链表判空
bool LTEmpty(LTNode* phead);
//双链表尾插
void LTPushBack(LTNode* phead,LTDataType x);
//双链表头插
void LTPushFront(LTNode* phead,LTDataType x);
//双链表尾删
void LTPopBack(LTNode* phead,LTDataType x);
//双链表头删
void LTPopFront(LTNode* phead,LTDataType x);
//双链表查找
LTNode *LTFind(LTNode* phead,LTDataType x);
//双链表在pos位之前插入
void LTInsert(LTNode* pos,LTDataType x);
//双链表在pos位删除结点
void LTErase(LTNode* pos);
//双链表销毁
void LTDestroy(LTNode* phead);
// 获取双向链表的元素个数
size_t ListSize(LTNode* phead);
三、在List.c上实现各个接口函数
1、动态申请一个新结点
LTNode * BuyLTNode(LTDataType x)
{
LTNode* newnode=(LTNode *)malloc(sizeof(LTNode));
if(newnode==NULL)
{
perror("malloc fail");
return NULL;
}
newnode->data=x;
newnode->next=NULL;
newnode->prev=NULL;
return newnode;
}
2、初始化双向链表
LTNode *LTInit()
{
LTNode *phead= BuyLTNode(0);//动态申请一个头结点
phead->prev=phead;//前指针指向自己
phead->next=phead;//后指针也指向自己
phead->data=0;//哨兵卫不需要存值
return phead;
}
初始化带头双向循环链表,首先动态申请一个头结点,头结点的前驱和后继指针都指向自己,形成一个循环。
3、双向链表的销毁
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode *cur=phead->next;
while(cur!=phead)
{
LTNode *new=cur->next;//记录cur的直接后继结点
free(cur);
cur=new;
}
free(phead);
}
4、双向链表的打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("guard<==>");//guard也就是哨兵卫
LTNode *cur=phead->next;//记录第一个结点
while(cur!=phead)
{
printf("%d<==>",cur->data);
cur=cur->next;
}
printf("\n");
}
5、双向链表尾插
void LTPushBack(LTNode* phead,LTDataType x)
{
assert(phead);
//LTInsert(phead,x);
LTNode *newnode= BuyLTNode(x);//动态申请一个新的结点
LTNode *tail=phead->prev;//记录尾结点
tail->next=newnode;//尾结点的next指针指向新的结点
newnode->prev=tail;//新的结点的prev指针指向尾结点
newnode->next=phead;//新结点的next指针指向头结点
phead->prev=newnode;//头结点的prev指针指向新结点
}
6、双向链表尾删
void LTPopBack(LTNode* phead,LTDataType x)
{
assert(phead);
assert(!LTEmpty(phead));//只剩下头结点时 链表为空,不能再继续删除
//LTErase(pjead->prev);
LTNode *tail=phead->prev;//记录尾结点
LTNode *tailprev=tail->prev;//记录尾结点的前一个
free(tail);//释放尾结点
tailprev->next=phead;//尾结点的前一个的next指针指向头结点
phead->prev=tailprev;//头结点的prev指针指向尾结点的前一个结点
}
7、双向链表的头插
void LTPushFront(LTNode* phead,LTDataType x)
{
assert(phead);
//LTInsert(phead->next,x);
LTNode *newnode= BuyLTNode(x);//申请新结点
LTNode *first=phead->next;//记录第一个结点
phead->next=newnode;
newnode->prev=phead;
newnode->next=first;
first->prev=newnode;
}
8、双向链表的头删
void LTPopFront(LTNode* phead,LTDataType x)
{
assert(phead);
assert(!LTEmpty(phead));
//LTErase(phead->next);
LTNode *first=phead->next;
LTNode *second=first->next;
phead->next=second;
second->prev=phead;
free(first);
}
9、查找双向链表中的元素
LTNode *LTFind(LTNode* phead,LTDataType x)
{
assert(phead);
LTNode *cur=phead->next;
while(cur!=phead)
{
if(cur->data==x)
return cur;
cur=cur->next;
}
return NULL;
}
10、在指定pos位置之前插入元素
void LTInsert(LTNode* pos,LTDataType x)
{
assert(pos);
LTNode *posprev=pos->prev;
LTNode *newnode= BuyLTNode(x);
posprev->next=newnode;
newnode->next=pos;
newnode->prev=posprev;
pos->prev=newnode;
}
实现了该函数后,可以尝试改进头插函数(pos相当于链表的第一个节点)和尾插函数(pos相当于链表的头节点),这样写起来更简便。
11、删除指定pos位置的元素
void LTErase(LTNode* pos)
{
assert(pos);
LTNode *posprev=pos->prev;
LTNode *posnext=pos->next;
posprev->next=posnext;
posnext->prev=posprev;
free(pos);
}
实现了该函数后,可以尝试改进头删函数(pos相当于链表的第一个节点)和尾删函数(pos相当于链表的最后一个节点),这样写起来更简便。
12、双向链表的判空
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead==phead->next;
}
13、获取双向链表的元素个数
size_t ListSize(LTNode* phead)
{
assert(phead);
size_t size = 0;
LTNode * cur=phead->next;
while(cur!=phead)
{
size++;
cur=cur->next;
}
return size;
}
四、代码整合
//List.c
#include "List.h"
LTNode * BuyLTNode(LTDataType x)
{
LTNode* newnode=(LTNode *)malloc(sizeof(LTNode));
if(newnode==NULL)
{
perror("malloc fail");
return NULL;
}
newnode->data=x;
newnode->next=NULL;
newnode->prev=NULL;
return newnode;
}
LTNode *LTInit()
{
LTNode *phead= BuyLTNode(0);
phead->prev=phead;
phead->next=phead;
phead->data=0;
return phead;
}
void LTPrint(LTNode* phead)
{
assert(phead);
printf("guard<==>");
LTNode *cur=phead->next;
while(cur!=phead)
{
printf("%d<==>",cur->data);
cur=cur->next;
}
printf("\n");
}
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead==phead->next;
}
void LTPushBack(LTNode* phead,LTDataType x)
{
assert(phead);
//LTInsert(phead,x);
LTNode *newnode= BuyLTNode(x);
LTNode *tail=phead->prev;
tail->next=newnode;
newnode->prev=tail;
newnode->next=phead;
phead->prev=newnode;
}
void LTPushFront(LTNode* phead,LTDataType x)
{
assert(phead);
//LTInsert(phead->next,x);
LTNode *newnode= BuyLTNode(x);
LTNode *first=phead->next;
phead->next=newnode;
newnode->prev=phead;
newnode->next=first;
first->prev=newnode;
}
void LTPopBack(LTNode* phead,LTDataType x)
{
assert(phead);
assert(!LTEmpty(phead));
//LTErase(pjead->prev);
LTNode *tail=phead->prev;
LTNode *tailprev=tail->prev;
free(tail);
tailprev->next=phead;
phead->prev=tailprev;
}
void LTPopFront(LTNode* phead,LTDataType x)
{
assert(phead);
assert(!LTEmpty(phead));
//LTErase(phead->next);
LTNode *first=phead->next;
LTNode *second=first->next;
phead->next=second;
second->prev=phead;
free(first);
}
LTNode *LTFind(LTNode* phead,LTDataType x)
{
assert(phead);
LTNode *cur=phead->next;
while(cur!=phead)
{
if(cur->data==x)
return cur;
cur=cur->next;
}
return NULL;
}
void LTInsert(LTNode* pos,LTDataType x)
{
assert(pos);
LTNode *posprev=pos->prev;
LTNode *newnode= BuyLTNode(x);
posprev->next=newnode;
newnode->next=pos;
newnode->prev=posprev;
pos->prev=newnode;
}
void LTErase(LTNode* pos)
{
assert(pos);
LTNode *posprev=pos->prev;
LTNode *posnext=pos->next;
posprev->next=posnext;
posnext->prev=posprev;
free(pos);
}
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode *cur=phead->next;
while(cur!=phead)
{
LTNode *new=cur->next;
free(cur);
cur=new;
}
free(phead);
}
size_t ListSize(LTNode* phead)
{
assert(phead);
size_t size = 0;
LTNode * cur=phead->next;
while(cur!=phead)
{
size++;
cur=cur->next;
}
return size;
}