目录
3.在第一个值为 x 的结点前面添加值为 a 的结点(若未找到,则添加到链表末尾)
前言
这篇文章以及代码都是在某培训机构学完数据结构之后,自己根据课程重新写了一点代码总结。
文章和代码中如有谬误,敬请指出!
这里对文章中可能有疑虑的一些内容进行了综述:
1. typedef 语句的作用:
(1)简化定义语句,提高可读性
在使用 typedef
后,结构体变量的定义由原先的 struct Node newNode
简化为 Node newNode
,尤其在结构体名字较长时,可以使代码更为简洁,提高可读性。
(2)增强代码的可维护性和复用性
通过使用 typedef
定义数据类型的别名,代码在变更数据类型时变得更具灵活性。例如,若需将数据域的类型修改为 char
,使用 typedef
的情况下只需修改一处宏定义即可实现全局变更,而不必修改代码中所有使用了该类型的地方。这有助于提升代码的可维护性和复用性。
2.判空操作
在带头结点的链表判空时,我先对头节点进行判断 然后使用或运算 对首结点进行判空处理。这两个操作不能互换位置,因为当链表没有被创建时,链表是没有头节点的,这个时候通过头节点去判断首结点,会造成空指针的使用,引发段错误。
3.为什么插入,删除函数返回值都为指针类型
(1).在进行插入删除时,会对链表进行空值判断,若链表为空,则会创建新的头结点或者数据结点,所以需要使用返回值,来返回创建的表头地址。
(2).在不带头节点的链表中进行插入和删除时,可能会遇到插入到第一个结点前面,或者是删除第一个结点的情况,此时,头指针的指向就会发生变更,需要通过返回值,更新头指针,防止出现非法访问。
(3).可以通过返回值更新头指针,或者使用二级指针解决这个问题。
(4)本文的代码是在VS Studio中实现的,在输入时使用的是 scanf_s() 函数,在其他编译器中大概率不能使用,建议改成 scanf() 函数进行使用。
1.不带头节点的单链表
(1)定义数据结构
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
struct Node* next;
}Node;
(2)函数列表
1.尾插法建立单链表
//尾插法创建一个单链表
Node* Create_List_Tail()
{
/*1.输入链表元素 */
printf("请输入链表的数据元素\n");
int value;
/*2.建立头指针 和 尾指针*/
Node* head = NULL;
Node* rear = NULL;
while (1)
{
scanf_s("%d", &value);
if (value == 0)
{ //输入 0 退出
break;
}
/* 2.创建结点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
/*3.将结点插入到链表*/
if (head == NULL)
{ //1.链表为空,新节点作为第一个结点
head = newNode;
rear = newNode;
}
else
{ //2.链表不为空,新节点插入到链表末尾
rear->next = newNode;
rear = newNode;
}
}
return head;
}
2.头插法建立单链表
//头插法建立一个单链表
Node* Create_List_Head()
{
/*1.输入链表元素 */
printf("请输入链表的数据元素\n");
int value;
/*2.建立头指针 */
Node* head = NULL;
while (1)
{
scanf_s("%d", &value);
if (value == 0)
{ //输入 0 退出
break;
}
/* 2.创建结点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
/*3.将结点插入到链表*/
if (head == NULL)
{ //1.链表为空,新节点作为第一个结点
head = newNode;
}
else
{ //2.链表不为空,新节点插入到第一个结点的位置
newNode->next = head;
head = newNode;
}
}
return head;
}
3.在第一个值为 x 的结点前面添加值为 a 的结点(若未找到,则添加到链表末尾)
/*
* 在链表中查找值为x的结点,在x的前面添加一个值为a的结点
* 若没有找到x,则把a加入到链表的最后,并且将新链表的
* 第一个结点返回
*/
Node* ADD_a_Insert(Node* head,Elemtype x,Elemtype a)
{
/*1.建立结点*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = a;
newNode->next = NULL;
/*2.判空*/
if (head == NULL)
{ //链表为空,将新节点作为第一个结点也是最后一个结点
head = newNode;
return head;
}
/*3.链表不为空,需要查找 x 结点,建立遍历指针*/
Node* p = head;
Node* pre = NULL;
/*4.遍历链表,查找值为 x 的结点*/
while (p)
{
if (p->data == x)
break;
else
{
pre = p; //保存当前节点的上一个结点
p = p->next; //查找下一个结点
}
}
/*5.结果判断*/
if (p == head)
{ //1.第一个结点值为 x ,插入结点到第一个结点的位置
newNode->next = head;
head = newNode;
}
else
{ //2.插入到第一个结点后面的位置
pre->next = newNode;
newNode->next = p;
}
return head;
}
4.删除第一个值为 x 的结点
//在链表中中找到值为x的结点,将其删除,如果有多个值为x的结点,只删除第一个
Node* Delete_Frist_Value_Is_x(Node* head,Elemtype x)
{
/*1.判空*/
if (head == NULL)
return NULL;
/*2.链表不为空,建立遍历指针*/
Node* p = head;
Node* pre = NULL;
/*3.遍历链表,查找值为 x 的结点*/
while (p)
{ //找到了
if (p->data == x)
break;
else
{ //没找到,查找下一个元素
pre = p; //保存前一个结点
p = p->next;
}
}
/*4.查找结束,删除判断*/
if (p != NULL)
{ //存在值为 x 的结点
if (p == head)
head = head->next;
else
pre->next = p->next;
free(p);
p = NULL;
}
return head;
}
5.删除值为 x 的所有结点
注意:删除结点时需要考虑结点的位置,若需要删除的节点为头节点,则需要更换头结点,若需要删除的结点是尾结点,则需要将尾结点的上一个结点的 next 指针置空。
//在链表中删除全部值为 x 的结点
Node* Delete_Value_Is_x(Node* head, Elemtype x)
{
/*1.判空*/
if (head == NULL)
return NULL;
/*2.链表不为空,建立遍历指针*/
Node* p = head;
Node* pre = NULL;
/*3.遍历链表,查找值为 x 的结点*/
while (p)
{ //找到了,删除结点
if (p->data == x)
{
if (p == head)
head = head->next;
else
pre->next = p->next;
free(p);
//遍历下一个 结点
if (pre == NULL)
p = head;
else
p = pre->next;
}
else
{ //没找到,查找下一个元素
pre = p; //保存前一个结点
p = p->next;
}
}
return head;
}
6.销毁链表
注意:销毁链表之后,需要将空值 NULL 返回给头指针,或者将头指针置空。防止销毁链表后,头指针仍然指向了原来的内存,导致非法访问。
//销毁一个链表
Node* Destory_List(Node* head)
{
/*1.判空*/
if (head == NULL)
{
printf("\n空链表!\n");
return NULL;
}
/*2.链表不为空,开始删除*/
Node* p = head;
while (p)
{
head = head->next;
free(p);
p = head;
}
printf("\n删除完成!\n");
return NULL;
}
7.递归返回结点个数
//递归返回单链表的数目
int Get_List_Length(Node* head)
{
if (head == NULL)
return 0;
return 1 + Get_List_Length(head->next);
}
8.创建升序链表
注意:这里其实就是一个简单的插入,只不过在每次插入前都查找了一边插入的位置。
//创建一个升序链表
Node* Create_Sort_List()
{
/*1.创建头指针*/
Node* head = NULL;
/*2.输入数据*/
int value;
printf("请输入链表:\n");
while (1)
{
scanf_s("%d", &value);
if (value == 0)
break;
/*3.创建结点*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->next = NULL;
newNode->data = value;
/*4.创建遍历指针*/
Node* p = head;
Node* pre = NULL;
/*4.插入判断*/
if (head == NULL)
{ //链表为空,新节点作为链表的头结点
head = newNode;
}
else
{ //链表不为空,遍历链表,插入新节点到链表中
while (p)
{
if (p->data > newNode->data) //找到了,插入到 p 前面
{
if (p == head)
{ //插入到 第一个元素的位置
newNode->next = head;
head = newNode;
}
else
{ //插入到 pre 的后面,p 的前面
pre->next = newNode;
newNode->next = p;
}
break;
}
else
{ //没有找到,后面还有结点
if (p->next != NULL)
{
pre = p;
p = p->next;
}
else
{ //后面没有结点
p->next = newNode;
break;
}
}
}
}
}
return head;
}
9.递归升序插入
注意:这里使用了递归进行升序插入,在每次进行递归之前进行判断,查看是否在当前位置插入结点。每次传入的结点为当前结点的下一个结点,并将递归结果返回。用 当前节点的下一个结点接受即: head->next = Sort_Insert_List(head->next, x); 相当于每次进行的是一个头插法插入。
//递归升序插入
Node* Sort_Insert_List(Node* head, Elemtype x)
{
/*1.判空,若链表为空,则直接将新节点作为头节点返回*/
if (head == NULL)
{ //链表为空
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
head = newNode;
return head;
}
/*2.插入位置寻找*/
if (head->data < x)
{
head->next = Sort_Insert_List(head->next, x);
return head;
}
else
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
/*3.使用头插法将 新节点插入到链表中*/
newNode->next = head;
head = newNode;
return head;
}
}
10.就地逆序单链表
注意:这段代码的实质就是逐个摘下链表的第一个结点,放入新的链表中,每次都使用头插法插入,并更新新链表的头结点的位置。
//就地逆序一个单链表 (不申请额外的空间)
Node* Reverse_List(Node* head)
{
/*1.判空*/
if (head == NULL)
return NULL;
/*2.建立遍历指针和标志指针*/
Node* p = head;
Node* h = NULL;
/*3.反转链表*/
while (p)
{
/*1.将链表的第一个元素摘下来*/
head = head->next;
p->next = NULL;
/*2.按照头插法,将摘下来的结点加入到新的链表中*/
p->next = h;
h = p;
/*3.摘下一个结点*/
p = head;
}
return h;
}
11.打印链表
//打印链表
void Print_List(Node* head)
{
printf("\n打印链表:\n");
printf("---------------------------\n");
/*1.判空*/
if (head == NULL)
{
printf("空链表!");
}
else
{
/*2.链表不为空,遍历链表*/
Node* p = head;
while (p)
{
printf("%d ", p->data);
p = p->next;
}
}
printf("\n---------------------------\n");
}
(3)完整代码
#include<stdio.h>
#include<stdlib.h>
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
struct Node* next;
}Node;
//尾插法创建一个单链表
Node* Create_List_Tail()
{
/*1.输入链表元素 */
printf("请输入链表的数据元素\n");
int value;
/*2.建立头指针 和 尾指针*/
Node* head = NULL;
Node* rear = NULL;
while (1)
{
scanf_s("%d", &value);
if (value == 0)
{ //输入 0 退出
break;
}
/* 2.创建结点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
/*3.将结点插入到链表*/
if (head == NULL)
{ //1.链表为空,新节点作为第一个结点
head = newNode;
rear = newNode;
}
else
{ //2.链表不为空,新节点插入到链表末尾
rear->next = newNode;
rear = newNode;
}
}
return head;
}
//头插法建立一个单链表
Node* Create_List_Head()
{
/*1.输入链表元素 */
printf("请输入链表的数据元素\n");
int value;
/*2.建立头指针 */
Node* head = NULL;
while (1)
{
scanf_s("%d", &value);
if (value == 0)
{ //输入 0 退出
break;
}
/* 2.创建结点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
/*3.将结点插入到链表*/
if (head == NULL)
{ //1.链表为空,新节点作为第一个结点
head = newNode;
}
else
{ //2.链表不为空,新节点插入到第一个结点的位置
newNode->next = head;
head = newNode;
}
}
return head;
}
/*
* 在链表中查找值为x的结点,在x的前面添加一个值为a的结点
* 若没有找到x,则把a加入到链表的最后,并且将新链表的
* 第一个结点返回
*/
Node* ADD_a_Insert(Node* head,Elemtype x,Elemtype a)
{
/*1.建立结点*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = a;
newNode->next = NULL;
/*2.判空*/
if (head == NULL)
{ //链表为空,将新节点作为第一个结点也是最后一个结点
head = newNode;
return head;
}
/*3.链表不为空,需要查找 x 结点,建立遍历指针*/
Node* p = head;
Node* pre = NULL;
/*4.遍历链表,查找值为 x 的结点*/
while (p)
{
if (p->data == x)
break;
else
{
pre = p; //保存当前节点的上一个结点
p = p->next; //查找下一个结点
}
}
/*5.结果判断*/
if (p == head)
{ //1.第一个结点值为 x ,插入结点到第一个结点的位置
newNode->next = head;
head = newNode;
}
else
{ //2.插入到第一个结点后面的位置
pre->next = newNode;
newNode->next = p;
}
return head;
}
//在链表中中找到值为x的结点,将其删除,如果有多个值为x的结点,只删除第一个
Node* Delete_Frist_Value_Is_x(Node* head,Elemtype x)
{
/*1.判空*/
if (head == NULL)
return NULL;
/*2.链表不为空,建立遍历指针*/
Node* p = head;
Node* pre = NULL;
/*3.遍历链表,查找值为 x 的结点*/
while (p)
{ //找到了
if (p->data == x)
break;
else
{ //没找到,查找下一个元素
pre = p; //保存前一个结点
p = p->next;
}
}
/*4.查找结束,删除判断*/
if (p != NULL)
{ //存在值为 x 的结点
if (p == head)
head = head->next;
else
pre->next = p->next;
free(p);
p = NULL;
}
return head;
}
//在链表中删除全部值为 x 的结点
Node* Delete_Value_Is_x(Node* head, Elemtype x)
{
/*1.判空*/
if (head == NULL)
return NULL;
/*2.链表不为空,建立遍历指针*/
Node* p = head;
Node* pre = NULL;
/*3.遍历链表,查找值为 x 的结点*/
while (p)
{ //找到了,删除结点
if (p->data == x)
{
if (p == head)
head = head->next;
else
pre->next = p->next;
free(p);
//遍历下一个 结点
if (pre == NULL)
p = head;
else
p = pre->next;
}
else
{ //没找到,查找下一个元素
pre = p; //保存前一个结点
p = p->next;
}
}
return head;
}
//销毁一个链表
Node* Destory_List(Node* head)
{
/*1.判空*/
if (head == NULL)
{
printf("\n空链表!\n");
return NULL;
}
/*2.链表不为空,开始删除*/
Node* p = head;
while (p)
{
head = head->next;
free(p);
p = head;
}
printf("\n删除完成!\n");
return NULL;
}
//递归返回单链表的数目
int Get_List_Length(Node* head)
{
if (head == NULL)
return 0;
return 1 + Get_List_Length(head->next);
}
//创建一个升序链表
Node* Create_Sort_List()
{
/*1.创建头指针*/
Node* head = NULL;
/*2.输入数据*/
int value;
printf("请输入链表:\n");
while (1)
{
scanf_s("%d", &value);
if (value == 0)
break;
/*3.创建结点*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->next = NULL;
newNode->data = value;
/*4.创建遍历指针*/
Node* p = head;
Node* pre = NULL;
/*4.插入判断*/
if (head == NULL)
{ //链表为空,新节点作为链表的头结点
head = newNode;
}
else
{ //链表不为空,遍历链表,插入新节点到链表中
while (p)
{
if (p->data > newNode->data) //找到了,插入到 p 前面
{
if (p == head)
{ //插入到 第一个元素的位置
newNode->next = head;
head = newNode;
}
else
{ //插入到 pre 的后面,p 的前面
pre->next = newNode;
newNode->next = p;
}
break;
}
else
{ //没有找到,后面还有结点
if (p->next != NULL)
{
pre = p;
p = p->next;
}
else
{ //后面没有结点
p->next = newNode;
break;
}
}
}
}
}
return head;
}
//递归升序插入
Node* Sort_Insert_List(Node* head, Elemtype x)
{
/*1.判空,若链表为空,则直接将新节点作为头节点返回*/
if (head == NULL)
{ //链表为空
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
head = newNode;
return head;
}
/*2.插入位置寻找*/
if (head->data < x)
{
head->next = Sort_Insert_List(head->next, x);
return head;
}
else
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
/*3.使用头插法将 新节点插入到链表中*/
newNode->next = head;
head = newNode;
return head;
}
}
//就地逆序一个单链表 (不申请额外的空间)
Node* Reverse_List(Node* head)
{
/*1.判空*/
if (head == NULL)
return NULL;
/*2.建立遍历指针和标志指针*/
Node* p = head;
Node* h = NULL;
/*3.反转链表*/
while (p)
{
/*1.将链表的第一个元素摘下来*/
head = head->next;
p->next = NULL;
/*2.按照头插法,将摘下来的结点加入到新的链表中*/
p->next = h;
h = p;
/*3.摘下一个结点*/
p = head;
}
return h;
}
//打印链表
void Print_List(Node* head)
{
printf("\n打印链表:\n");
printf("---------------------------\n");
/*1.判空*/
if (head == NULL)
{
printf("空链表!");
}
else
{
/*2.链表不为空,遍历链表*/
Node* p = head;
while (p)
{
printf("%d ", p->data);
p = p->next;
}
}
printf("\n---------------------------\n");
}
int main()
{
Node* head = NULL;
int x;
int a;
printf("使用头插法建立链表\n");
head = Create_List_Head();
Print_List(head);
printf("\n销毁这个链表");
head = Destory_List(head);
Print_List(head);
printf("\n使用尾插法建立链表");
head = Create_List_Tail(head);
Print_List(head);
printf("\n请输入您需要删除的结点:");
scanf_s("%d", &x);
printf("\n删除第一个值为 %d 的结点", x);
head = Delete_Frist_Value_Is_x(head, x);
Print_List(head);
printf("\n删除所有值为 %d 的结点", x);
head = Delete_Value_Is_x(head, x);
Print_List(head);
int length = Get_List_Length(head);
printf("此时链表中的元素个数为:%d",length);
printf("\n销毁这个链表");
head = Destory_List(head);
Print_List(head);
printf("\n创建一个升序链表");
head = Create_Sort_List();
Print_List(head);
printf("\n请输入您需要插入的结点:");
scanf_s("%d", &x);
printf("\n升序插入结点: %d", x);
head = Sort_Insert_List(head, x);
Print_List(head);
printf("\n请输入您需要插入的结点位置:");
scanf_s("%d", &a);
printf("\n请输入您需要插入的结点:");
scanf_s("%d", &x);
printf("\n在 %d 的前面插入结点 %d ", a, x);
head = ADD_a_Insert(head, a, x);
Print_List(head);
printf("\n销毁这个链表");
head = Destory_List(head);
Print_List(head);
return 0;
}
2.带头节点的单链表
(1)定义数据结构
1.结点类型
typedef int Elemtype;
typedef struct Node
{
Elemtype data; //数据结点,存储数据
struct Node* next; //指针域,指向下一个结点
}Node;
2.头节点类型
typedef struct ListNode
{
Node* frist; //指向链表的第一个结点
Node* last; //指向链表的最后一个结点
int length; //保存链表长度
}List;
注意:
头节点的定义有多种类型
(1)数据结点做头节点,头节点数据域不保存数据
(2)数据节点做头节点,头节点数据域存储链表长度
(3)建立新的结点类型,保存指向链表第一个元素的 frist 指针,指向链表最后一个节点的 last 指针,保存链表长度的 length 变量。
我都代码使用的是第三种类型。使用什么样的头节点无关紧要,能够达到要求就可以。
(2)函数列表
1.创建头节点
List* Create_List_With_Head()
{
List* L = (List*)malloc(sizeof(List));
//初始化参数
L->frist = NULL;
L->last = NULL;
L->length = 0;
}
2.尾插法建立链表
//尾插法建立链表
List* Tail_Insert_List(List*L,Elemtype x)
{
//1.判空
if (L == NULL)
{ //头节点未初始化
L = Create_List_With_Head();
}
/*2.创建新节点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
/*3.使用尾插法插入新结点到链表中*/
if (L->frist == NULL)
{ //链表为空时
L->frist = newNode;
L->last = newNode;
}
else
{ //链表不为空
L->last->next = newNode;
L->last = newNode;
}
//更新结点个数
L->length++;
}
3.头插法建立链表
//使用头插法建立链表
List* Head_Insert_List(List* L, Elemtype x)
{
/*1.判空*/
if (L == NULL)
L = Create_List_With_Head();
/*2.创建新节点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->next = NULL;
newNode->data = x;
/*3.使用头插法插入结点*/
if (L->frist == NULL)
{
L->frist = newNode;
L->last = newNode;
}
else
{
newNode->next = L->frist;
L->frist = newNode;
}
L->length++;
return L;
}
4.升序插入元素
//有序--升序插入元素到链表
List* Sort_Insert_List(List* L, Elemtype x)
{
/*1.判空*/
if (L == NULL)
return;
/*2.创建新结点并,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
/*3.寻找插入位置*/
Node* p = L->frist;
Node* pre = NULL;
while (p)
{
if (p->data > x) //插入到 p 前面的位置
break;
else
{ //没有找到,更新 p 和 pre 的位置
pre = p;
p = p->next;
}
}
/*4.插入结点到链表中*/
if (p == L->frist)
{ //要插入到 第一个元素的位置
p->next = L->frist;
L->frist = newNode;
}
else if(p!=NULL)
{ //要插入到 中间节点的位置
newNode->next = p;
pre->next = newNode;
}
else
{
//没有找到比 x 大的元素,插入到链表的末尾
pre->next = newNode;
}
return L;
}
5.删除全部值为 x 的结点
//在链表中查找值为 x 的结点,并将其全部删除,若没找到就不删除
void Delete_Value_Is_x(List* L, Elemtype x)
{
/*1.判空*/
if (L == NULL || L->frist == NULL)
return;
/*2.创建两个个遍历链表的指针,用于寻找删除结点*/
Node* p = L->frist; //指向当前结点
Node* pre = NULL; //指向 p 的上一个结点
/*3.遍历链表*/
while (p)
{
if (p->data == x)
{ //找到了,p为需要删除的结点
/*判断结点的位置*/
if (p == L->frist)
{ //要删除的是 头节点
L->frist = p->next;
}
else if (p->next == NULL)
{ //要删除的是 尾结点
L->last = pre;
pre->next = NULL;
}
else
{ //要删除的是中间结点
pre->next = p->next;
}
//释放 p
free(p);
p = NULL;
}
else
{ //没有找到
pre = p;
p = p->next;
}
}
}
6.升序排序
//对链表进行排序--升序
void Sort_List(List* L)
{
/*1.判空*/
if (L == NULL || L->frist == NULL)
return;
/*2.排序*/
Node* pnew = L->frist; //有序链表
Node* pold = L->frist->next; //无序链表
Node* p = NULL;
Node* pre = NULL;
while (pold!=NULL)
{
/*3.复位*/
p = pold;
pold = pold->next;
pnew = L->frist;
pre = L->frist;
/*4.查找插入位置*/
while (pnew != p)
{
if (pnew->data > p->data)
break;
else
{
pre = pnew;
pnew = pnew->next;
}
}
/*5.插入节点*/
if (pnew == L->frist)
{ //插入到有序表的表头
pnew->next = pold;
p->next = pnew;
L->frist = p;
}
else if (pnew != p)
{
pnew->next = pold;
p->next = pnew;
pre->next = p;
}
else;
}
}
7.查找值为 x 的结点,将 x 改为 a
//在链表中查找值为 x 的结点,将其所有的值都改为 a ,若没有找到,则不修改
void Update_Value_Is_x(List* L,Elemtype x,Elemtype a)
{
/*1.判空*/
if (L == NULL || L->frist == NULL)
return;
/*2.寻找值为 x 的结点*/
Node* p = L->frist;
while (p)
{
if (p->data == x)
p->data = a;
else
p = p->next;
}
}
8.销毁链表
//销毁链表
List* Destory_List(List* L)
{
if (L == NULL)
return NULL;
Node* p;
while (L->frist)
{
p = L->frist;
L->frist = p->next;
free(p);
p = NULL;
}
free(L);
L = NULL;
return NULL;
}
9.打印链表
//循环打印链表
void Print_List(List* L)
{
printf("\n打印链表:");
/*1.判空*/
if (L == NULL || L->frist == NULL)
{
printf("空链表!\n");
return;
}
/*2.遍历输出*/
Node* p = L->frist;
printf("\n----------------------------\n");
while (p!=NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n----------------------------\n");
}
(3)完整代码
#include<stdio.h>
typedef int Elemtype;
typedef struct Node
{
Elemtype data; //数据结点,存储数据
struct Node* next; //指针域,指向下一个结点
}Node;
typedef struct ListNode
{
Node* frist; //指向链表的第一个结点
Node* last; //指向链表的最后一个结点
int length; //保存链表长度
}List;
//创建头节点
List* Create_List_With_Head()
{
List* L = (List*)malloc(sizeof(List));
//初始化参数
L->frist = NULL;
L->last = NULL;
L->length = 0;
}
//尾插法建立链表
List* Tail_Insert_List(List*L,Elemtype x)
{
//1.判空
if (L == NULL)
{ //头节点未初始化
L = Create_List_With_Head();
}
/*2.创建新节点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
/*3.使用尾插法插入新结点到链表中*/
if (L->frist == NULL)
{ //链表为空时
L->frist = newNode;
L->last = newNode;
}
else
{ //链表不为空
L->last->next = newNode;
L->last = newNode;
}
//更新结点个数
L->length++;
}
//使用头插法建立链表
List* Head_Insert_List(List* L, Elemtype x)
{
/*1.判空*/
if (L == NULL)
L = Create_List_With_Head();
/*2.创建新节点,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->next = NULL;
newNode->data = x;
/*3.使用头插法插入结点*/
if (L->frist == NULL)
{
L->frist = newNode;
L->last = newNode;
}
else
{
newNode->next = L->frist;
L->frist = newNode;
}
L->length++;
return L;
}
//有序--升序插入元素到链表
List* Sort_Insert_List(List* L, Elemtype x)
{
/*1.判空*/
if (L == NULL)
return;
/*2.创建新结点并,并初始化*/
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = NULL;
/*3.寻找插入位置*/
Node* p = L->frist;
Node* pre = NULL;
while (p)
{
if (p->data > x) //插入到 p 前面的位置
break;
else
{ //没有找到,更新 p 和 pre 的位置
pre = p;
p = p->next;
}
}
/*4.插入结点到链表中*/
if (p == L->frist)
{ //要插入到 第一个元素的位置
p->next = L->frist;
L->frist = newNode;
}
else if(p!=NULL)
{ //要插入到 中间节点的位置
newNode->next = p;
pre->next = newNode;
}
else
{
//没有找到比 x 大的元素,插入到链表的末尾
pre->next = newNode;
}
return L;
}
//在链表中查找值为 x 的结点,并将其全部删除,若没找到就不删除
void Delete_Value_Is_x(List* L, Elemtype x)
{
/*1.判空*/
if (L == NULL || L->frist == NULL)
return;
/*2.创建两个个遍历链表的指针,用于寻找删除结点*/
Node* p = L->frist; //指向当前结点
Node* pre = NULL; //指向 p 的上一个结点
/*3.遍历链表*/
while (p)
{
if (p->data == x)
{ //找到了,p为需要删除的结点
/*判断结点的位置*/
if (p == L->frist)
{ //要删除的是 头节点
L->frist = p->next;
}
else if (p->next == NULL)
{ //要删除的是 尾结点
L->last = pre;
pre->next = NULL;
}
else
{ //要删除的是中间结点
pre->next = p->next;
}
//释放 p
free(p);
p = NULL;
}
else
{ //没有找到
pre = p;
p = p->next;
}
}
}
//对链表进行排序--升序
void Sort_List(List* L)
{
/*1.判空*/
if (L == NULL || L->frist == NULL)
return;
/*2.排序*/
Node* pnew = L->frist; //有序链表
Node* pold = L->frist->next; //无序链表
Node* p = NULL;
Node* pre = NULL;
while (pold!=NULL)
{
/*3.复位*/
p = pold;
pold = pold->next;
pnew = L->frist;
pre = L->frist;
/*4.查找插入位置*/
while (pnew != p)
{
if (pnew->data > p->data)
break;
else
{
pre = pnew;
pnew = pnew->next;
}
}
/*5.插入节点*/
if (pnew == L->frist)
{ //插入到有序表的表头
pnew->next = pold;
p->next = pnew;
L->frist = p;
}
else if (pnew != p)
{
pnew->next = pold;
p->next = pnew;
pre->next = p;
}
else;
}
}
//在链表中查找值为 x 的结点,将其所有的值都改为 a ,若没有找到,则不修改
void Update_Value_Is_x(List* L,Elemtype x,Elemtype a)
{
/*1.判空*/
if (L == NULL || L->frist == NULL)
return;
/*2.寻找值为 x 的结点*/
Node* p = L->frist;
while (p)
{
if (p->data == x)
p->data = a;
else
p = p->next;
}
}
//销毁链表
List* Destory_List(List* L)
{
if (L == NULL)
return NULL;
Node* p;
while (L->frist)
{
p = L->frist;
L->frist = p->next;
free(p);
p = NULL;
}
free(L);
L = NULL;
return NULL;
}
//循环打印链表
void Print_List(List* L)
{
printf("\n打印链表:");
/*1.判空*/
if (L == NULL || L->frist == NULL)
{
printf("空链表!\n");
return;
}
/*2.遍历输出*/
Node* p = L->frist;
printf("\n----------------------------\n");
while (p!=NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n----------------------------\n");
}
int main()
{
int x, a;
//创建头节点
List* L = Create_List_With_Head();
//尾插法建立链表
printf("请输入结点的值:\n");
while (1)
{
int x;
scanf_s("%d", &x);
if (x == 0)
break;
L = Tail_Insert_List(L, x);
}
//打印链表
Print_List(L);
printf("头插法插入结点\n请输入你需要插入到结点的值:");
scanf_s("%d", &x);
L = Head_Insert_List(L, x);
//打印链表
Print_List(L);
//升序排序链表
printf("\n对链表进行升序排序");
Sort_List(L);
//打印链表
Print_List(L);
printf("\n使用升序插入,插入一个结点\n请输入您需要插入到节点的值:\n");
scanf_s("%d", &x);
Sort_Insert_List(L, x);
//打印链表
Print_List(L);
//查找值
printf("\n请输入要更改的元素值:");
scanf_s("%d", &x);
printf("\n请输入替换后的元素的值:");
scanf_s("%d", &a);
Update_Value_Is_x(L, x, a);
//打印链表
Print_List(L);
//删除值
printf("\n请输入需要删除的元素的值:");
scanf_s("%d", &x);
Delete_Value_Is_x(L, x);
//打印链表
Print_List(L);
printf("\n销毁链表");
//销毁链表
L = Destory_List(L);
//打印链表
Print_List(L);
}
3.双向链表
(1)数据结构
注意:我才用的双向链表是带头节点的双向链表,包含了指向 第一个元素的指针 frist 和指向最后一个元素的 last 指针。
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
struct Node* next; //指向上一个结点
struct Node* prev; //指向下一个结点
}DNode;
typedef struct DList
{
DNode* first;
DNode* last;
int length;
}DList;
(2)函数列表
1.初始化头节点
//初始化头结点
DList* Init_DList()
{
DList* DL = (DList*)malloc(sizeof(DList));
DL->first = NULL;
DL->last = NULL;
DL->length = 0;
return DL;
}
2.打印双向链表
注意:这里我使用的是双向打印,这样可以查看双向链表是否准确连接。
//打印双向链表
void Print_DList(DList* DL)
{
printf("\n打印双向链表:\n");
printf("---------------------\n");
if (DL == NULL || DL->first == NULL)
{
printf("空链表!");
}
else
{
DNode* p = DL->first;
while (p)
{
printf("%d ", p->data);
p = p->next;
}
p = DL->last;
printf("\n");
while (p)
{
printf("%d ", p->data);
p = p->prev;
}
}
printf("\n---------------------\n");
}
3.尾插法插入数据
//尾插法建立链表
DList* Tail_Insert_DList(DList* DL,Elemtype x)
{
/*1.判空*/
if (DL == NULL)
{
DL = Init_DList();
}
/*3.创建节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
/*4.插入结点到链表中*/
if (DL->first == NULL)
{ //空链表,新节点作为第一个元素
DL->first = newNode;
DL->last = newNode;
}
else
{ //链表不为空,使用尾插法插入结点
DL->last->next = newNode;
newNode->prev = DL->last;
DL->last = newNode;
}
DL->length++;
return DL;
}
4.头插法插入数据
//头插法插入数据
DList* Head_Insert_DList(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_DList();
/*2.创建新结点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
if (DL->first == NULL)
{ //空链表
DL->first = newNode;
DL->last = newNode;
}
else
{
DL->first->prev = newNode;
newNode->next = DL->first;
DL->first = newNode;
}
DL->length++;
return DL;
}
5.有序插入
注意:有序插入需要考虑插入位置,分别为:头插、中间插、尾插。在进行头插时,需要更新原链表的第一个结点的 prev 指针指向新结点。在进行尾插时,要更新原链表的尾结点的 next 指针指向新节点。
//有序插入
DList* Sort_Insert_DList(DList* DL, Elemtype x)
{
if (DL == NULL)
{ //空链表
DL = Init_DList();
}
/*创建新节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
/*寻找插入位置*/
DNode* p = DL->first;
/*开始遍历*/
while (p)
{
if (p->data > x)
break;
else
p = p->next;
}
//查找结束,将新节点插入到 p 的前面
if (p == DL->first)
{ //插入到头节点后面
DL->first->prev = newNode;
newNode->next = DL->first;
DL->first = newNode;
}
else if(p)
{ //插入到中间结点的位置
p->prev->next = newNode;
newNode->prev = p->prev;
newNode->next = p;
p->prev = newNode;
}
else
{ //p == null 或则 没有找打比他大的结点,插入到末尾的位置
newNode->prev = DL->last;
DL->last->next = newNode;
DL->last = newNode;
}
DL->length++;
return DL;
}
6.函数指针创建链表
注意:这里其实没有必要使用函数指针,只是有意练习。
使用函数指针,将一个指向返回值为 DList* 参数列表为:DList*,Elemtype 类型的指针变量作为参数,可以通过一段代码,更改函数调用,来达到一段代码实现头插和尾插两个功能,减少了代码的冗余。
//创建链表 函数指针
DList* Create_DList(DList* (*func)(DList*, Elemtype))
{
DList* DL = Init_DList();
Elemtype value;
printf("\n请输入链表:\n");
while(1)
{
scanf_s("%d", &value);
if (value == 0)
break;
DL = func(DL, value);
}
return DL;
}
7.删除所有值为 x 的结点
注意:删除结点和插入结点时一样,在找到删除位置之后,需要对删除的结点进行判断,如果是首位结点,则需要更新 prev 和 next 指针,防止指针指向不可访问的内存。
//删除所有值为 x 的结点
void Delete_Value_Is_x(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL || DL->first == NULL)
return;
/*2.创建遍历指针*/
DNode* p = DL->first;
/*3.开始遍历链表*/
while (p)
{
if (p->data == x) //找到了,删除当前结点
{
/*4.判断需要删除的结点的位置*/
if (p == DL->first)
{ //删除第一个结点
DL->first = p->next;
DL->first->prev = NULL;
free(p);
p = NULL;
//将 p 指向下一个需要遍历的结点
p = DL->first;
}
else if (p->next != NULL)
{ //要删除的是中间结点
DNode* pre = p->next;
p->next->prev = p->prev;
p->prev->next = p->next;
free(p);
p = NULL;
p = pre;
}
else
{ //要删除的是尾结点
p->prev->next = NULL;
DL->last = p->prev;
free(p);
p = NULL;
}
DL->length--;
}
else
{ //没有找到,遍历下一个结点
p = p->next;
}
}
}
8.销毁链表
//销毁链表
DList* Destory_DList(DList* DL)
{
if (DL == NULL)
{
printf("\n空链表!\n");
return;
}
DNode* p = DL->first;
while (p)
{
p = DL->first;
DL->first = p->next;
free(p);
p = NULL;
DL->length--;
}
free(DL);
DL = NULL;
return DL;
}
(3)完整代码
#include <stdio.h>
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
struct Node* next; //指向上一个结点
struct Node* prev; //指向下一个结点
}DNode;
typedef struct DList
{
DNode* first;
DNode* last;
int length;
}DList;
//初始化头结点
DList* Init_DList()
{
DList* DL = (DList*)malloc(sizeof(DList));
DL->first = NULL;
DL->last = NULL;
DL->length = 0;
return DL;
}
//打印双向链表
void Print_DList(DList* DL)
{
printf("\n打印双向链表:\n");
printf("---------------------\n");
if (DL == NULL || DL->first == NULL)
{
printf("空链表!");
}
else
{
DNode* p = DL->first;
while (p)
{
printf("%d ", p->data);
p = p->next;
}
p = DL->last;
printf("\n");
while (p)
{
printf("%d ", p->data);
p = p->prev;
}
}
printf("\n---------------------\n");
}
//尾插法建立链表
DList* Tail_Insert_DList(DList* DL,Elemtype x)
{
/*1.判空*/
if (DL == NULL)
{
DL = Init_DList();
}
/*3.创建节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
/*4.插入结点到链表中*/
if (DL->first == NULL)
{ //空链表,新节点作为第一个元素
DL->first = newNode;
DL->last = newNode;
}
else
{ //链表不为空,使用尾插法插入结点
DL->last->next = newNode;
newNode->prev = DL->last;
DL->last = newNode;
}
DL->length++;
return DL;
}
//头插法插入数据
DList* Head_Insert_DList(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_DList();
/*2.创建新结点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
if (DL->first == NULL)
{ //空链表
DL->first = newNode;
DL->last = newNode;
}
else
{
DL->first->prev = newNode;
newNode->next = DL->first;
DL->first = newNode;
}
DL->length++;
return DL;
}
//有序插入
DList* Sort_Insert_DList(DList* DL, Elemtype x)
{
if (DL == NULL)
{ //空链表
DL = Init_DList();
}
/*创建新节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
/*寻找插入位置*/
DNode* p = DL->first;
/*开始遍历*/
while (p)
{
if (p->data > x)
break;
else
p = p->next;
}
//查找结束,将新节点插入到 p 的前面
if (p == DL->first)
{ //插入到头节点后面
DL->first->prev = newNode;
newNode->next = DL->first;
DL->first = newNode;
}
else if(p)
{ //插入到中间结点的位置
p->prev->next = newNode;
newNode->prev = p->prev;
newNode->next = p;
p->prev = newNode;
}
else
{ //p == null 或则 没有找打比他大的结点,插入到末尾的位置
newNode->prev = DL->last;
DL->last->next = newNode;
DL->last = newNode;
}
DL->length++;
return DL;
}
//创建链表 函数指针
DList* Create_DList(DList* (*func)(DList*, Elemtype))
{
DList* DL = Init_DList();
Elemtype value;
printf("\n请输入链表:\n");
while(1)
{
scanf_s("%d", &value);
if (value == 0)
break;
DL = func(DL, value);
}
return DL;
}
//删除所有值为 x 的结点
void Delete_Value_Is_x(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL || DL->first == NULL)
return;
/*2.创建遍历指针*/
DNode* p = DL->first;
/*3.开始遍历链表*/
while (p)
{
if (p->data == x) //找到了,删除当前结点
{
/*4.判断需要删除的结点的位置*/
if (p == DL->first)
{ //删除第一个结点
DL->first = p->next;
DL->first->prev = NULL;
free(p);
p = NULL;
//将 p 指向下一个需要遍历的结点
p = DL->first;
}
else if (p->next != NULL)
{ //要删除的是中间结点
DNode* pre = p->next;
p->next->prev = p->prev;
p->prev->next = p->next;
free(p);
p = NULL;
p = pre;
}
else
{ //要删除的是尾结点
p->prev->next = NULL;
DL->last = p->prev;
free(p);
p = NULL;
}
DL->length--;
}
else
{ //没有找到,遍历下一个结点
p = p->next;
}
}
}
//销毁链表
DList* Destory_DList(DList* DL)
{
if (DL == NULL)
{
printf("\n空链表!\n");
return;
}
DNode* p = DL->first;
while (p)
{
p = DL->first;
DL->first = p->next;
free(p);
p = NULL;
DL->length--;
}
free(DL);
DL = NULL;
return DL;
}
int main() {
DList* myDList = NULL; // 初始化一个空的双向链表
// 测试尾插法建立链表
printf("插入数据:1,2,3\n");
myDList = Tail_Insert_DList(myDList, 1);
myDList = Tail_Insert_DList(myDList, 2);
myDList = Tail_Insert_DList(myDList, 3);
Print_DList(myDList);
// 测试头插法插入数据
printf("头插法插入数据:0\n");
myDList = Head_Insert_DList(myDList, 0);
Print_DList(myDList);
// 测试有序插入
printf("有序插入数据:5,4,6\n");
myDList = Sort_Insert_DList(myDList, 5);
myDList = Sort_Insert_DList(myDList, 4);
myDList = Sort_Insert_DList(myDList, 6);
Print_DList(myDList);
// 测试删除值为 x 的结点
printf("删除结点0,3,6\n");
Delete_Value_Is_x(myDList, 0);
Delete_Value_Is_x(myDList, 3);
Delete_Value_Is_x(myDList, 6);
Print_DList(myDList);
// 销毁链表
printf("销毁链表\n");
myDList = Destory_DList(myDList);
// 再次测试空链表情况
Print_DList(myDList);
// 测试创建链表函数指针
printf("使用函数指针,用尾插法创建链表");
myDList = Create_DList(Tail_Insert_DList);
Print_DList(myDList);
// 测试创建链表后销毁
printf("销毁链表\n");
myDList = Destory_DList(myDList);
Print_DList(myDList);
return 0;
}
(4)运行结果
4.带头结点的单循环链表
(1)数据结构
//定义数据结构
typedef int Elemtype;
typedef struct DNode
{
Elemtype data;
struct DNode* next;
}DNode;
//创建头节点
typedef struct List
{
DNode* frist;
DNode* last;
int length;
}DList;
(2)函数列表
1.初始化头节点
注意:本段代码采用的是带头节点的实现,在链表为空且头结点存在时,认为 frist 指针和 last 指针都指向空,这两个指针都默认初始化为空值。
//初始化头节点
DList* Init_List_Head()
{
DList* DL = (DList*)malloc(sizeof(DList));
DL->frist = NULL;
DL->last = NULL;
DL->length = 0;
return DL;
}
2.尾插函数
注意:在第一次插入时,首结点的 next 指针指向自己本身,在链表不为空时,需要更新尾指针,以及尾指针重新指向首结点。
//尾插
DList* Tail_Insert_List(DList* DL,Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_List_Head();
/*2.创建新节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
/*3.尾插法插入结点*/
if (DL->frist == NULL)
{ //链表为空,新节点作为首尾结点
DL->frist = newNode;
DL->last = newNode;
DL->frist->next = newNode;
}
else
{ //链表不为空
DL->last->next = newNode;
newNode->next = DL->frist;
DL->last = newNode;
}
DL->length++;
return DL;
}
3.头插函数
//头插
DList* Head_Insert_List(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_List_Head();
/*2.创建新节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
/*3.头插法插入结点*/
if (DL->frist == NULL)
{
//链表为空,新节点作为首尾结点
DL->frist = newNode;
DL->last = newNode;
DL->frist->next = newNode;
}
else
{
//链表不为空
newNode->next = DL->frist;
DL->last->next = newNode;
DL->frist = newNode;
}
DL->length++;
return DL;
}
4.升序插入函数
注意:因为是循环链表,所以当链表不为空时,一般不能将 p == NULL 作为循环结束条件,这会造成死循环。也不能将 p == DL->frist 作为循环结束条件,因为 p 的初值为 DL->frist ,这会导致循环刚开始就结束。
我的思路是先将循环链表断开,变成熟悉的单链表模型,再进行操作
也可以使用 DL->length 因为链表长度是已知的。可以使用循环,控制循环次数为 length 来遍历链表
//升序插入
DList* Sort_Insert_List(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_List_Head();
/*2.建立结点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
/*3.建立遍历结点*/
DNode* p = DL->frist;
DNode* pre = NULL;
/*4.断开循环链表首尾结点的连接*/
DL->last->next = NULL;
/*5.查找插入位置*/
while (p)
{
if (p->data > x)
{ //找到了,插入到 p 的前面
break;
}
else
{
pre = p;
p = p->next;
}
}
/*6.判断插入位置*/
if (p == DL->frist)
{ //头插
newNode->next = DL->frist;
DL->frist = newNode;
}
else if (p != NULL)
{ //插入到中间结点
pre->next = newNode;
newNode->next = p;
}
else
{ //没有找到,newNode值 为最大的结点,插入到链表末端
DL->last->next = newNode;
}
DL->length++;
/*7.重新连接断开的链表*/
DL->last->next = DL->frist;
return DL;
}
5.删除所有值为 x 的结点
注意:删除结点后,重新连接 last 指针的 next 指向时,需要对链表进行判空操作,若链表为空,使用 DL->frist->next 时会造成空指针的使用,会发生段错误,所以,删除后需要对链表进行判空。
//删除所有值为 x 的结点
void Delete_All_Value_Is_x(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL || DL->frist == NULL)
return;
/*2.设置遍历指针*/
DNode* p = DL->frist;
DNode* pre = NULL;
/*3.断开循环链表*/
DL->last->next = NULL;
/*4.遍历链表*/
while (p)
{
if (p->data == x)
{ //找到了,删除 p 结点
/*5.删除位置判断*/
if (p == DL->frist)
{ //头删
DL->frist = p->next;
free(p);
p = NULL;
p = DL->frist;
}
else
{ //中间删除
pre->next = p->next;
free(p);
p = NULL;
p = pre->next;
}
DL->length--;
}
else
{ //没有找到,遍历下一个结点
pre = p;
p = p->next;
}
}
/*6.重新连接循环链表*/
if (DL->frist != NULL)
{ //链表不为空
DL->last->next = DL->frist;
}
else
{
DL->frist = NULL;
DL->last = NULL;
}
}
6.销毁链表
//销毁链表
DList* Destory_DList(DList* DL)
{
/*1.判空*/
if (DL == NULL)
return NULL;
/*2.判空,防止使用空指针*/
if (DL->last != NULL)
{
DL->last->next = NULL;
}
/*3.建立遍历指针*/
DNode* p = DL->frist;
/*4.遍历链表,逐个释放结点*/
while (p)
{
p = DL->frist;
DL->frist = p->next;
free(p);
p = NULL;
}
/*5.释放头节点*/
free(DL);
DL = NULL;
return DL;
}
7.打印链表
//打印链表
void Print_DList(DList* DL)
{
printf("\n打印链表\n");
printf("----------------------\n");
if (DL == NULL || DL->frist == NULL)
printf("空链表!");
else
{
DNode* p = DL->frist;
int len = DL->length;
for (int i = 0; i < len; i++)
{
printf("%d ",p->data);
p = p->next;
}
}
printf("\n----------------------\n");
}
(3)完整代码
#include<stdio.h>
//定义数据结构
typedef int Elemtype;
typedef struct DNode
{
Elemtype data;
struct DNode* next;
}DNode;
//创建头节点
typedef struct List
{
DNode* frist;
DNode* last;
int length;
}DList;
//初始化头节点
DList* Init_List_Head()
{
DList* DL = (DList*)malloc(sizeof(DList));
DL->frist = NULL;
DL->last = NULL;
DL->length = 0;
return DL;
}
//尾插
DList* Tail_Insert_List(DList* DL,Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_List_Head();
/*2.创建新节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
/*3.尾插法插入结点*/
if (DL->frist == NULL)
{ //链表为空,新节点作为首尾结点
DL->frist = newNode;
DL->last = newNode;
DL->frist->next = newNode;
}
else
{ //链表不为空
DL->last->next = newNode;
newNode->next = DL->frist;
DL->last = newNode;
}
DL->length++;
return DL;
}
//头插
DList* Head_Insert_List(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_List_Head();
/*2.创建新节点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
/*3.头插法插入结点*/
if (DL->frist == NULL)
{
//链表为空,新节点作为首尾结点
DL->frist = newNode;
DL->last = newNode;
DL->frist->next = newNode;
}
else
{
//链表不为空
newNode->next = DL->frist;
DL->last->next = newNode;
DL->frist = newNode;
}
DL->length++;
return DL;
}
//升序插入
DList* Sort_Insert_List(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL)
DL = Init_List_Head();
/*2.建立结点*/
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = x;
newNode->next = NULL;
/*3.建立遍历结点*/
DNode* p = DL->frist;
DNode* pre = NULL;
/*4.断开循环链表首尾结点的连接*/
DL->last->next = NULL;
/*5.查找插入位置*/
while (p)
{
if (p->data > x)
{ //找到了,插入到 p 的前面
break;
}
else
{
pre = p;
p = p->next;
}
}
/*6.判断插入位置*/
if (p == DL->frist)
{ //头插
newNode->next = DL->frist;
DL->frist = newNode;
}
else if (p != NULL)
{ //插入到中间结点
pre->next = newNode;
newNode->next = p;
}
else
{ //没有找到,newNode值 为最大的结点,插入到链表末端
DL->last->next = newNode;
}
DL->length++;
/*7.重新连接断开的链表*/
DL->last->next = DL->frist;
return DL;
}
//删除所有值为 x 的结点
void Delete_All_Value_Is_x(DList* DL, Elemtype x)
{
/*1.判空*/
if (DL == NULL || DL->frist == NULL)
return;
/*2.设置遍历指针*/
DNode* p = DL->frist;
DNode* pre = NULL;
/*3.断开循环链表*/
DL->last->next = NULL;
/*4.遍历链表*/
while (p)
{
if (p->data == x)
{ //找到了,删除 p 结点
/*5.删除位置判断*/
if (p == DL->frist)
{ //头删
DL->frist = p->next;
free(p);
p = NULL;
p = DL->frist;
}
else
{ //中间删除
pre->next = p->next;
free(p);
p = NULL;
p = pre->next;
}
DL->length--;
}
else
{ //没有找到,遍历下一个结点
pre = p;
p = p->next;
}
}
/*6.重新连接循环链表*/
if (DL->frist != NULL)
{ //链表不为空
DL->last->next = DL->frist;
}
else
{
DL->frist = NULL;
DL->last = NULL;
}
}
//销毁链表
DList* Destory_DList(DList* DL)
{
/*1.判空*/
if (DL == NULL)
return NULL;
/*2.判空,防止使用空指针*/
if (DL->last != NULL)
{
DL->last->next = NULL;
}
/*3.建立遍历指针*/
DNode* p = DL->frist;
/*4.遍历链表,逐个释放结点*/
while (p)
{
p = DL->frist;
DL->frist = p->next;
free(p);
p = NULL;
}
/*5.释放头节点*/
free(DL);
DL = NULL;
return DL;
}
//打印链表
void Print_DList(DList* DL)
{
printf("\n打印链表\n");
printf("----------------------\n");
if (DL == NULL || DL->frist == NULL)
printf("空链表!");
else
{
DNode* p = DL->frist;
int len = DL->length;
for (int i = 0; i < len; i++)
{
printf("%d ",p->data);
p = p->next;
}
}
printf("\n----------------------\n");
}
int main() {
// 创建带头结点的循环链表
DList* DL = Init_List_Head();
printf("tail insert 1,3,5\n");
// 尾插法插入一些数据
DL = Tail_Insert_List(DL, 1);
DL = Tail_Insert_List(DL, 3);
DL = Tail_Insert_List(DL, 5);
// 打印链表
Print_DList(DL);
printf("head insert 0,-2\n");
// 头插法插入一些数据
DL = Head_Insert_List(DL, 0);
DL = Head_Insert_List(DL, -2);
// 打印链表
Print_DList(DL);
printf("sort insert 4,2\n");
// 升序插入一些数据
DL = Sort_Insert_List(DL, 4);
DL = Sort_Insert_List(DL, 2);
// 打印链表
Print_DList(DL);
printf("delete value is 3\n");
// 删除值为 3 的所有结点
Delete_All_Value_Is_x(DL, 3);
// 打印链表
Print_DList(DL);
// 打印删除后的链表
Print_DList(DL);
// 极端测试
printf("delete value is -2\n");
// 删除值为 0 的所有结点
Delete_All_Value_Is_x(DL, -2);
printf("delete value is 5\n");
// 删除值为 4 的所有结点
Delete_All_Value_Is_x(DL, 5);
// 打印删除后的链表
Print_DList(DL);
printf("destory list\n");
// 销毁链表
DL = Destory_DList(DL);
Print_DList(DL);
return 0;
}