循环单链表
之前学习的单链表,最后一个结点的next
指针都是指向NULL
但是循环单链表 的表尾结点的next
指针指向头结点
c
/*
* 需要注意的是:
* 在我们初始化一个循环单链表的时候,
* 我们需要把头结点的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
指向头结点
- 表头结点的
循环双链表的初始化
c
//初始化为空的循环双链表
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]]