数据结构
双向循环链表和它名字的表意一样,就是把双向链表的两头连接,使其成为了一个环状链表。只需要将表中最后一个节点的next指针指向头节点,头节点的prior指针指向尾节点,链表就能成环儿,如图所示:

需要注意的是,虽然双向循环链表成环状,但本质上还是双向链表,因此在双向循环链表中,依然能够找到头指针和头节点等。双向循环链表和双向链表相比,唯一的不同就是双向循环链表首尾相连,其他都完全一样。
//定义结点
typedef struct Node{
ElemType data;
struct Node *prior;
struct Node *next;
}Node;
typedef struct Node * LinkList;
1、双向循环链表的创建
初始化时需要将头节点的next和prior都指向自己。

//6.1 双向循环链表初始化
Status creatLinkList(LinkList *L){
*L = (LinkList)malloc(sizeof(Node));
if (*L == NULL) {
return ERROR;
}
(*L)->next = (*L);
(*L)->prior = (*L);
//新增数据
LinkList p = *L;
for(int i=0; i < 10;i++){
//1.创建1个临时的结点
LinkList temp = (LinkList)malloc(sizeof(Node));
temp->data = i;
//2.为新增的结点建立双向链表关系
//① temp 是p的后继
p->next = temp;
//② temp 的前驱是p
temp->prior = p;
//③ temp的后继是*L
temp->next = (*L);
//④ p 的前驱是新建的temp
p->prior = temp;
//⑤ p 要记录最后的结点的位置,方便下一次插入
p = p->next;
}
return OK;
}
2.双向循环链表插入元素
这里不需要判断尾节点的next是否为Null,因为它会指向头节点。
//6.2 双向循环链表插入元素
/*当插入位置超过链表长度则插入到链表末尾*/
Status LinkListInsert(LinkList *L, int index, ElemType e){
//1. 创建指针p,指向双向链表头
LinkList p = (*L);
int i = 1;
//2.双向循环链表为空,则返回error
if(*L == NULL) return ERROR;
//3.找到插入前一个位置上的结点p
while (i < index && p->next != *L) {
p = p->next;
i++;
}
//4.如果i>index 则返回error
if (i > index) return ERROR;
//5.创建新结点temp
LinkList temp = (LinkList)malloc(sizeof(Node));
//6.temp 结点为空,则返回error
if (temp == NULL) return ERROR;
//7.将生成的新结点temp数据域赋值e.
temp->data = e;
//8.将结点temp 的前驱结点为p;
temp->prior = p;
//9.temp的后继结点指向p->next;
temp->next = p->next;
//10.p的后继结点为新结点temp;
p->next = temp;
//如果temp 结点不是最后一个结点
if (*L != temp->next) {
//11.temp节点的下一个结点的前驱为temp 结点
temp->next->prior = temp;
}else{
(*L)->prior = temp;
}
return OK;
}
3.遍历双向循环链表
注意它的尾节点的next不再是Null,而是头节点
//6.3 遍历双向循环链表
Status Display(LinkList L){
if (L == NULL) {
printf("打印的双向循环链表为空!\n\n");
return ERROR;
}
printf("双向循环链表内容: ");
LinkList p = L->next;
while (p != L) {
printf("%d ",p->data);
p = p->next;
}
printf("\n\n");
return OK;
}
4.根据索引位置删除节点
这里不需要判断尾节点的next是否为Null,因为它会指向头节点。
//6.4 双向循环链表删除结点
Status LinkListDelete(LinkList *L,int index,ElemType *e){
int i = 1;
LinkList temp = (*L)->next;
if (*L == NULL) {
return ERROR;
}
//①.如果删除到只剩下首元结点了,则直接将*L置空;
if(temp->next == *L){
free(*L);
(*L) = NULL;
return OK;
}
//1.找到要删除的结点
while (i < index) {
temp = temp->next;
i++;
}
//2.给e赋值要删除结点的数据域
*e = temp->data;
//3.修改被删除结点的前驱结点的后继指针 图1️⃣
temp->prior->next = temp->next;
//4.修改被删除结点的后继结点的前驱指针 图2️⃣
temp->next->prior = temp->prior;
//5. 删除结点temp
free(temp);
return OK;
}
5.根据存储的值删除节点
//5、根据存储的值删除节点
这里不需要判断尾节点的next是否为Null,因为它会指向头节点。
Status deleteLinkListByData(LinkList *list, ElemType data){
if (*list == NULL) {
return ERROR;
}
LinkList locaNode = (*list)->next;
while (locaNode != *list) {
if (locaNode->data == data) {
break;
}
locaNode = locaNode->next;
}
if (locaNode == *list) {
printf("没有这个你想要删除的节点\n");
return ERROR;
}
//开始删除,只需要做两步
locaNode->prior->next = locaNode->next;
locaNode->next->prior = locaNode->prior;
free(locaNode);
return OK;
}
6.根据值查找节点
尾节点的next是头节点,找到它就是最后一个了。
//6、查找元素
Status selectNode(LinkList list, ElemType data, LinkList *locaNode){
if (list == NULL) {
return ERROR;
}
LinkList p = list->next;
while (p != list) {
if (p->data == data) {
*locaNode = p;
break;
}
p = p->next;
}
if (*locaNode == NULL) {
printf("没有这个你想要的节点\n");
return ERROR;
}
else {
return OK;
}
}
网友评论