循环链表建议自己一定要下去实现一遍,你会发现和普通的单链表还是有很大区别的,尤其是遍历的时候循环的条件!!
一、创建一个链表
// 创建一个链表
void Creat_LinkedList(LinkedList* list)
{
list->head = NULL;
list->len = 0;
}
二、销毁一个循环链表
2.1、核心代码实现:
注意:
1、 因为在循环链表中,我们不能移动头指针的位置,所以相较于普通链表的销毁,我们还多需要一个结点来进行缓存的操作
2、使用do--while是因为current的初始值就是list->head,所以需要使用do--while先跳过一轮,防止直接退出
// 销毁一个链表
void Destroy_LinkList(LinkedList* list)
{
//因为在循环链表中,我们不能移动头指针的位置,
//所以相较于普通链表的销毁,我们还多需要一个结点来进行缓存的操作
if (list->head == NULL) return; // 空链表
ListNode* current = list->head; //定义一个迭代器指向头节点
ListNode* temp; //用来暂存结点 来释放结点
//使用do--while是因为current的初始值就是list->head
//所以需要使用do--while先跳过一轮,防止直接退出
do {
temp = current; // 定义一个值指向
current = current->next; // 移动到下一个节点
free(temp); // 释放当前节点
} while (current != list->head); // 检查是否回到头节点
list->head = NULL;
list->len = 0;
}
2.2、代码图解:
1、用一个temp指向current
2、current往下移一位
3、释放free
三、插入元素
3.1、核心代码实现:
// 在链表中插入一个元素,在第i个位置插入value值
void Insert_LinkList(LinkedList* list, int i, int value)
{
if (i < 0 || i > list->len) //越界
{
printf("插入失败\n");
return;
}
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->data = value;
if (list->len == 0) // 如果链表为空
{
newNode->next = newNode; // 指向自身
list->head = newNode; // 新节点为头节点
}
else if (i == 0) // 插入到头部,头插法
{
ListNode* tail = list->head;
while (tail->next != list->head) // 找到尾节点
{
tail = tail->next;
}
newNode->next = list->head; // 新节点指向头
tail->next = newNode; // 尾节点指向新节点
list->head = newNode; // 更新头节点
}
else //尾插法
{
ListNode* current = list->head;
for (int j = 0; j < i - 1; j++)
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
list->len++;
}
3.2、代码图解
3.2.1:当链表为空时
下一个结点指向自身
头节点指向当前结点
3.2.2、当链表不为空,且需要插入元素到头部时
1、定义一个tail指针,指向头节点
2、遍历到尾结点
3、同普通链表一致,修改指针指向即可
3.2.3:当链表不为空,且需要插入元素到链表中时
1、定义一个迭代器cur指向头节点,
2、遍历到第i-1个下标
3、改变指针指向
四、删除元素
4.1、核心代码实现
// 删除节点,把第i个元素删除
void Delete_LinkList(LinkedList* list, int i)
{
if (i < 0 || i >= list->len) //下标越界
{
printf("删除失败\n");
return;
}
ListNode* toDelete = list->head;
if (i == 0) // 删除头节点
{
ListNode* tail = list->head; //定义一个迭代器指向 头节点
while (tail->next != list->head) //移动tail到 尾节点
{
tail = tail->next;
}
if (list->len == 1) // 只有一个节点
{
free(list->head);
list->head = NULL;
}
else //不只有一个头节点
{
tail->next = toDelete->next; // 更新尾节点指向
list->head = toDelete->next; // 更新头节点
free(toDelete);
}
}
else //删除的结点不是头结点
{
ListNode* current = list->head;
for (int j = 0; j < i - 1; j++) //找到要删除的结点的前一个结点
{
current = current->next;
}
toDelete = current->next; //把toDelete指向cur->next
current->next = toDelete->next; //把cur->next指向toDelete的next
free(toDelete);
}
list->len--;
}
4.2、代码图解:
4.2.1、删除头节点,且只有一个元素
释放头节点,置空即可。
4.2.2、删除头节点,但不只有一个元素
0、定义一个toDelete结点,指向头节点,表示要删除头节点,用来最后的释放
1、定义一个迭代器tail指向头节点
2、把tail移动到尾结点
3、更新尾结点的指向
4、更新头节点
5、删除要删除的结点
4.2.3、删除的结点不是头节点:
0、定义一个toDelete,指向头结点
1、定义一个迭代器current,指向头节点
2、把current移动到要删除结点的前一个结点
3、把toDelete指向current的下一个结点,即指向要删除的结点。
4、把cur->next指向toDelete的next.
5、释放要删除的结点toDelete
五、通过元素来查找链表节点
5.1核心代码实现:
// 通过元素来查找链表节点
ListNode* Find_element_Linked(LinkedList* list, int value)
{
if (list->head == NULL) return NULL; // 空链表
ListNode* current = list->head;
do
{
if (current->data == value) //简单!!和单链表一致
{
return current;
}
current = current->next;
} while (current != list->head);
return NULL; // 没有找到
}
5.2、代码图解:
六、通过下标来查找链表节点:
// 通过下标来寻找链表的节点,寻找第i个元素
ListNode* Find_Index_Linked(LinkedList* list, int i)
{
if (i < 0 || i >= list->len)
{
printf("寻找错误\n");
return NULL;
}
ListNode* current = list->head;
for (int j = 0; j < i; j++) //因为链表的下标默认从0开始
{
current = current->next;
}
return current;
}
七、更新链表元素
// 更新链表的元素
void Update_LInked(LinkedList* list, int i, int value)
{
ListNode* temp = Find_Index_Linked(list, i); //调用寻找元素下标的函数,直接获取要更新的元素的结点指针
if (temp)
{
temp->data = value;
}
//可以不用加Ddeque语句,因为Find_Index_Linked程序中已经有了
}
八、遍历打印链表的元素
//打印链表的元素
void Print_Linked(LinkedList* list)
{
if (list->head == NULL)
{
printf("链表为空\n");
return;
}
ListNode* current = list->head;
do
{
printf("%d -> ", current->data);
current = current->next;
} while (current != list->head);
printf("(回到头节点)\n");
}
总结:完整代码的实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode { // 创建循环链表单独节点
int data; // 数值域
struct ListNode* next; // 下一个节点的指针域
} ListNode;
typedef struct LinkedList { // 完整的链表
ListNode* head; // 头节点
int len; // 长度
} LinkedList;
// 创建一个链表
void Creat_LinkedList(LinkedList* list)
{
list->head = NULL;
list->len = 0;
}
// 销毁一个链表
void Destroy_LinkList(LinkedList* list)
{
//因为在循环链表中,我们不能移动头指针的位置,
//所以相较于普通链表的销毁,我们还多需要一个结点来进行缓存的操作
if (list->head == NULL) return; // 空链表
ListNode* current = list->head; //定义一个迭代器指向头节点
ListNode* temp; //用来暂存结点 来释放结点
//使用do--while是因为current的初始值就是list->head
//所以需要使用do--while先跳过一轮,防止直接退出
do {
temp = current; // 定义一个值指向
current = current->next; // 移动到下一个节点
free(temp); // 释放当前节点
} while (current != list->head); // 检查是否回到头节点
list->head = NULL;
list->len = 0;
}
// 在链表中插入一个元素,在第i个位置插入value值
void Insert_LinkList(LinkedList* list, int i, int value)
{
if (i < 0 || i > list->len) //越界
{
printf("插入失败\n");
return;
}
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->data = value;
if (list->len == 0) // 如果链表为空
{
newNode->next = newNode; // 指向自身
list->head = newNode; // 新节点为头节点
}
else if (i == 0) // 插入到头部,头插法
{
ListNode* tail = list->head;
while (tail->next != list->head) // 找到尾节点
{
tail = tail->next;
}
newNode->next = list->head; // 新节点指向头
tail->next = newNode; // 尾节点指向新节点
list->head = newNode; // 更新头节点
}
else //尾插法
{
ListNode* current = list->head;
for (int j = 0; j < i - 1; j++)
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
list->len++;
}
// 删除节点,把第i个元素删除
void Delete_LinkList(LinkedList* list, int i)
{
if (i < 0 || i >= list->len) //下标越界
{
printf("删除失败\n");
return;
}
ListNode* toDelete = list->head;
if (i == 0) // 删除头节点
{
ListNode* tail = list->head; //定义一个迭代器指向 头节点
while (tail->next != list->head) //移动tail到 尾节点
{
tail = tail->next;
}
if (list->len == 1) // 只有一个节点
{
free(list->head);
list->head = NULL;
}
else //不只有一个头节点
{
tail->next = toDelete->next; // 更新尾节点指向
list->head = toDelete->next; // 更新头节点
free(toDelete);
}
}
else //删除的结点不是头结点
{
ListNode* current = list->head;
for (int j = 0; j < i - 1; j++) //找到要删除的结点的前一个结点
{
current = current->next;
}
toDelete = current->next; //把toDelete指向cur->next
current->next = toDelete->next; //把cur->next指向toDelete的next
free(toDelete);
}
list->len--;
}
// 通过元素来查找链表节点
ListNode* Find_element_Linked(LinkedList* list, int value)
{
if (list->head == NULL) return NULL; // 空链表
ListNode* current = list->head;
do
{
if (current->data == value) //简单!!和单链表一致
{
return current;
}
current = current->next;
} while (current != list->head);
return NULL; // 没有找到
}
// 通过下标来寻找链表的节点,寻找第i个元素
ListNode* Find_Index_Linked(LinkedList* list, int i)
{
if (i < 0 || i >= list->len)
{
printf("寻找错误\n");
return NULL;
}
ListNode* current = list->head;
for (int j = 0; j < i; j++) //因为链表的下标默认从0开始
{
current = current->next;
}
return current;
}
// 更新链表的元素
void Update_LInked(LinkedList* list, int i, int value)
{
ListNode* temp = Find_Index_Linked(list, i); //调用寻找元素下标的函数,直接获取要更新的元素的结点指针
if (temp)
{
temp->data = value;
}
//可以不用加Ddeque语句,因为Find_Index_Linked程序中已经有了
}
//打印链表的元素
void Print_Linked(LinkedList* list)
{
if (list->head == NULL)
{
printf("链表为空\n");
return;
}
ListNode* current = list->head;
do
{
printf("%d -> ", current->data);
current = current->next;
} while (current != list->head);
printf("(回到头节点)\n");
}
int main()
{
LinkedList list; //定义一个链表
Creat_LinkedList(&list); //创建链表
Insert_LinkList(&list, 0, 10);
Insert_LinkList(&list, 1, 20);
Insert_LinkList(&list, 2, 30);
Insert_LinkList(&list, 3, 40);
printf("Original List:\n");
Print_Linked(&list);
Delete_LinkList(&list, 2);
Update_LInked(&list, 1, 100);
printf("Change1 List:\n");
Print_Linked(&list);
ListNode* found = Find_element_Linked(&list, 30); //通过元素寻找元素
if (!found)
{
printf("此节点不存在\n");
}
Destroy_LinkList(&list); // 销毁链表
system("pause");
return 0;
}
纯私人撰写,欢迎大家私信勘误!!