-
单向循环链表基础
- 概念
循环链表是另一种形式的链式存贮结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
与单链表的区别在于尾结点的指针不是指向NULL,而是指向头结点或者是首元结点
- 图解
-
单向循环链表的初始化以及赋值
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
typedef struct Node {
ElemType data;
struct Node * next;
} Node;
typedef struct Node *LinkList;
//单向循环链表操作
Status createLinkList(LinkList *L){
int number;
LinkList temp = NULL;
LinkList target = NULL;
printf("可输入一个数值用于插入懂啊链表,输入0跳出循环\n");
//向链表中插入数据
while(1){
scanf("%d",&number);
if(number == 0) break;
if(*L == NULL){
//列表是NULL
//1.创建一个新的节点
//2.节点的next指向*L
*L = (LinkList)malloc(sizeof(Node));
if(L == NULL) exit(0);
(*L)->data = number;
(*L)->next = *L; //首元节点的指针需要指向自己
}else{
//列表不是NULL
//1.创建一个新的节点
//2.找到尾节点
//3.新节点的next指向*L
//4.尾节点的next 指向新节点
temp = (LinkList)malloc(sizeof(Node));
if(temp == NULL) exit(0);
for(target = *L; target->next != *L; target = target->next);
temp->data = number;
temp->next = *L;
target->next = temp;
}
}
return OK;
}
Status createLinkList2(LinkList *L){
int number;
LinkList temp = NULL;
LinkList lastNode = NULL;
printf("可输入一个数值用于插入懂啊链表,输入0跳出循环\n");
while (1) {
scanf("%d",&number);
if(number == 0) break;
if(*L == NULL){
//列表是NULL
//1.创建一个新的节点
//2.节点的next指向*L
//3.lastNode = *L
*L = (LinkList)malloc(sizeof(Node));
if(*L == NULL) exit(0);
(*L)->data = number;
(*L)->next = *L;
lastNode = *L;
}else{
//列表不是NULL
//1.创建一个新的节点
//2.新节点的next指向*L
//3.lastNode->next 指向新节点
//4.lastNode等于新节点
temp = (LinkList)malloc(sizeof(Node));
if(temp == NULL) exit(0);
temp->data = number;
temp->next = *L;
lastNode->next = temp;
lastNode = temp;
}
}
return OK;
}
-
单向循环链表插入
-
不含头结点链表插入
- 插入位置在首元结点上
- 创建新节点target并赋值
- 找到尾结点
- target指向首元结点
- 尾结点next指针指向target
- L指向target
与含有头结点的区别在于插入在首元结点时需要额外修改L的指向
- 插入位置在其他位置
- 创建新节点target并赋值
- 找到插入位置的上一个结点temp
- target->next 指向 temp->next
- temp->next 指向target
注:切搞反3、4的顺序否则会造成temp后面的结点丢失
- 插入位置在首元结点上
-
含有头结点的链表插入
-
//插入元素
Status insert(LinkList *L,int item, int place){
if(*L == NULL) return ERROR;
LinkList temp = NULL;
LinkList target = NULL;
if(place == 1){
//当插入的位置是1
//1.找到尾节点
//2.创建一个新节点temp并复制data
//3.将新节点的next指向*L
//4.将尾节点的next指向temp
//5.将*L指向temp
//找到最后一个节点
for(target = *L; target->next != *L; target = target->next);
temp = (LinkList)malloc(sizeof(Node));
temp->next = (*L)->next;
target->next = temp;
*L = temp;
}else{
//当插入的位置不是1的时候
//1.找到插入位置的前一个节点target
//2.创建一个新节点temp,并赋值data
//3.将temp->next指向target->next
//4.将target->next指向temp
//注:3、4位置不能调换 否侧会造成后面节点丢失
int i;
for (target = *L,i = 1; target->next != *L && i != place - 1; i ++,target = target->next);
if(i != place - 1){
printf("插入位置超出链表长度");
return ERROR;
}
temp = (LinkList)malloc(sizeof(Node));
if(temp == NULL) return ERROR;
temp->data = item;
temp->next = target->next;
target->next = temp;
}
return OK;
}
-
单向循环链表删除
-
不含头结点链表删除
- 删除首元结点
- 创建一个指针target指向首元结点
- 找到尾结点temp
- temp->next指针指向target->next
- L指向target->next
- 释放target
- 删除其他位置结点
- 找到待删除指针的上一个指针temp
- 创建一个指针target指向temp->next(待删除指针)
- temp->next指向target->next
- 释放target
同样的注意顺序否则有可能造成结点丢失
- 删除首元结点
-
含头结点链表删除
-
//删除元素
Status delete(LinkList *L,int place){
if(*L == NULL) return ERROR;
LinkList target = NULL;
LinkList temp = NULL;
if(place == 1){
//删除的是首元结点
//1.找到尾结点
//2.temp指向首元结点
//3.*L 指向 *L->next
//4.尾结点指向*L
//5.释放temp
for(target = *L; target->next != *L; target = target->next);
temp = *L;
target->next = (*L)->next;
*L = (*L)->next;
free(temp);
}else{
//删除的不是首元结点
//1.找到要删除位置的上一个接点target
//2.将target->next赋值给temp
//3.target->next 指向temp->next
//4.释放temp
int i;
for(i = 1,target = *L; target->next != *L && i < place-1; target = target->next,i++);
if(i < place) return ERROR;
temp = target->next;
target->next = temp->next;
free(temp);
}
return OK;
}
注:代码展示的是含有头结点链表的操作,感兴趣的朋友可以尝试一下不含有头结点链表的实现