一、循环单链表![](https://i-blog.csdnimg.cn/blog_migrate/3090c01898501ff9bfb571409cbd945c.png)
循环单链表初始化
typedef struct LNode{ //定义单链表结点类型
ElemType data; //定义节点存放一个数据元素
struct LNode *next; //指针指向下一个节点
}LNode, *LinkList;
//初始化一个循环单链表
bool InitList(LinkList &L){
L = (LNode *)malloc(sizeof(LNode)); //分配一个头结点
if(L == NULL) //内存不足,分配失败
return false;
L -> next = L; //头结点next指向头结点
return true;
}
//判断循环单链表是否为空
bool Empty(LinkList L){
if(L -> next == L)
return true;
else
return false;
}
//判断结点p是否为循环单链表的表尾结点
bool isTail(LinkList L, LNode *p){
if(p -> next == L)
return true;
else
return false;
}
如果经常使用表头/表尾,可以使L指向表头/表尾元素,时间复杂度为O(1)
二、循环双链表![](https://i-blog.csdnimg.cn/blog_migrate/51b4bbb0656fc57f8e87e3b7bb822527.png)
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode, *DLinklist;
//初始化空的循环双链表
bool InitDLinkList(DLinklist &L){
L = (DNode *) malloc(sizeof(DNode)); //分配一个头结点
if(L==NULL) //内存不足,分配失败
return false;
L -> prior = L; //头结点的prior指向头结点
L -> next = L; //头结点的next指向头节点
return true;
}
void testDLinklist(){
//初始化循环双链表
DLinklist L;
InitDLinkList(L);
///..后续代码..
}
bool Empty(DLInklist L){
if(L -> next == L)//👈是否指向链表自身
return true;
else
return false;
}
三、双链表的插入
//在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s){
s -> next = p -> next; //将结点*s插入到结点*pzhiho
p -> next -> prior = s; //👈,在双链表中出现错误;但是在循环双链表中不会出现错误
s -> prior = p;
p -> next = s;
}
原本普通双链表当p指向最后一个节点时,p->next->prior=s会指向空指针报错,需要特殊处理,而循环双链表可直接采用改代码
(57条消息) 数据结构——双链表(小白入门第二天)_MUTA️的博客-CSDN博客
四、双链表的删除
//删除p的后继结点q
p -> next = q -> next;
q -> next -> prior = p;//👈,在双链表中出现错误;但是在循环双链表中不会出现错误
free(q);