喜欢《数据结构》部分笔记的小伙伴可以订阅专栏,今后还会不断更新。🧑💻
此外,《程序员必备技能》专栏和《程序员必备工具》专栏(该专栏暂未开设)日后会逐步更新,感兴趣的小伙伴可以点一下订阅、收藏、关注!🚀
谢谢大家!🙏
循环单链表
之前学习的单链表,最后一个结点的next
指针都是指向NULL
但是循环单链表的表尾结点的next
指针指向头结点
/*
* 需要注意的是:
* 在我们初始化一个循环单链表的时候,
* 我们需要把头结点的next指针指向头结点它自己;
* 相应的,如果要判断循环单链表是否为空,
* 只需要检查头结点的next指针是否指向它自己就可以了。
*/
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;
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;
}
- 普通单链表:从一个结点出发只能找到后续的各个结点
- 循环单链表:从一个结点出发可以找到其他任何一个结点
特性:
- 从头部找到尾部:时间复杂度: O ( n ) O(n) O(n)
- 从尾部找到头部:时间复杂度:
O
(
1
)
O(1)
O(1)
如果很多时候对链表的操作都是在头部或者尾部,可以让L指向表尾元素(插入、删除时可能需要修改L)
循环双链表
- 双链表:
- 表头结点的
prior
指向NULL
- 表尾结点的
next
指向NULL
- 表头结点的
- 循环双链表:
- 表头结点的
prior
指向表尾结点 - 表尾结点的
next
指向头结点
- 表头结点的
循环双链表的初始化
//初始化为空的循环双链表
bool InitDLinkList(DLinkList &L){
L = (DNode *) malloc (sizeof(DNode));
if(L == NULL) //内存不足,分配失败
return false;
L->prior = L; //头结点的prior指向头结点
L->next = L; //头结点的next指向头结点
}
void testDLinkList(){
DLinkList L;
InitDLinkList(L);
//......
}
//判断循环双链表是否为空
bool Empty(DLinkList L){
if(L->next == L)
return true;
else
return false;
}
//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinkList L, DNode *p){
if(p->next == L)
return true;
else;
return false;
}
循环双链表和双链表代码差别
普通双链表代码没有优化前的插入操作在循环双链表中可以正确运行[[2.3.3 双链表#^b85fdc]]
那么对于双链表的删除也是一样[[2.3.3 双链表#^29e61b]]