1.1 双向循环链表简介
看图:

- 同样有前驱指针域和后继指针域
- 空表时,头结点的前驱指针域指向自己,后继指针域指向自己
- 非空表时,头结点的前驱指针域指向尾节点,尾节点的后继指针域指向头结点
在处理双向循环链表时特别注意头结点的前驱指针域指向,尾节点的后继指针域指向,其余的还是和双向链表一致
1.2 双向循环链表实现方式
算法实现:
#include <stdio.h>
#include "string.h"
#include "ctype.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
//定义结点
typedef struct Node{
ElemType data;
struct Node *prior;
struct Node *next;
}Node;
typedef struct Node * LinkList;
//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
(*L)->prior = temp;
//⑤ p 要记录最后的结点的位置,方便下一次插入
p = p->next;
}
return OK;
}
//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;
}
//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;
}
//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;
}
main函数调用:
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!\n");
LinkList L;
Status iStatus;
ElemType temp,item;
iStatus = creatLinkList(&L);
printf("双向循环链表初始化是否成功(1->YES)/ (0->NO): %d\n\n",iStatus);
Display(L);
printf("输入要插入的位置和数据用空格隔开:");
scanf("%d %d",&temp,&item);
iStatus = LinkListInsert(&L,temp,item);
Display(L);
printf("输入要删除位置:");
scanf("%d",&temp);
iStatus = LinkListDelete(&L, temp, &item);
printf("删除链表位置为%d,结点数据域为:%d\n",temp,item);
Display(L);
printf("输入要删除位置:");
scanf("%d",&temp);
iStatus = LinkListDelete(&L, temp, &item);
printf("删除链表位置为%d,结点数据域为:%d\n",temp,item);
Display(L);
return 0;
}
运行结果:
Hello, World!
双向循环链表初始化是否成功(1->YES)/ (0->NO): 1
双向循环链表内容: 0 1 2 3 4 5 6 7 8 9
输入要插入的位置和数据用空格隔开:8 66
双向循环链表内容: 0 1 2 3 4 5 6 66 7 8 9
输入要删除位置:7
删除链表位置为7,结点数据域为:6
双向循环链表内容: 0 1 2 3 4 5 66 7 8 9
输入要删除位置:56
删除链表位置为56,结点数据域为:0
双向循环链表内容: 1 2 3 4 5 66 7 8 9
Program ended with exit code: 0
1.2 线性表总结
看图:

线性表篇章已经结束,从存储结构上分为顺序存储结构和链式存储结构,其中链式存储存储结构包含(单链表、单循环链表、双向链表、双向循环链表)
1.2.1 链表和顺序存储的优缺点对比

