c语言链表排序增删改查,史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)...

本文介绍了如何使用C语言实现链表的基本操作,包括创建链表、在头部和尾部插入元素、删除节点、查询元素以及链表的长度和反转。通过实例展示了如何在链表中插入、删除元素并进行相关查找,适合初学者理解链表数据结构的实现原理。
摘要由CSDN通过智能技术生成

1.准备工作

首先包含头文件,定义链表结构体,产生随即链表的范围,定义全局头尾节点。#include#include#include#define MAX 10

/*定义链表*/

typedef struct Node

{

int data;

struct Node *next;

}Node;

/*定义全局头尾节点*/

Node *head = NULL;

Node *end = NULL;

2.创建链表/*根据传入的参数添加链表节点*/

int CreatList(int a)

{

/*定义临时结构体并分配空间*/

Node *temp = (Node *)malloc(sizeof(Node));

if (temp ==NULL)

{

printf("malloc error!");

return -1;

}

else

{

/*给数据类型赋值*/

temp->data = a;

temp->next = NULL;

/*如果链表长度为0*/

if (head == NULL)

{

head = temp;

end = temp;

}

else

{

end->next = temp;

end = temp;

}

}

}

3.打印链表/*打印链表*/

void PrintList(Node *temp)

{

if(temp == NULL)

{

printf("Empty List!\r\n");

}

while (temp)

{

printf("%d",temp->data);

temp = temp->next;

if(temp)

printf("->");

}

printf("\r\n");

}

4.在元素后面插入元素

向链表中增添元素,根据添加位置不同,可分为以下 3 种情况:

1.插入到链表的头部(头节点之后),作为首元节点;

2.插入到链表中间的某个位置;

3.插入到链表的最末端,作为链表中最后一个数据元素;

虽然新元素的插入位置不固定,但是链表插入元素的思想是固定的,只需做以下两步操作,即可将新元素插入到指定的位置:

a.将新结点的 next 指针指向插入位置后的结点;

b.将插入位置前结点的 next 指针指向插入结点;

例如,我们在链表 {1,2,3,4} 的基础上分别实现在头部、中间部位、尾部插入新元素 5,其实现过程如图 所示:

eaa1a44bec0397e54cd81c45fc70d812.png/*根据传入的数,在其后面增加元素*/

int InsertListEnd(int index,int a)

{

if (head == NULL)

{

printf("Empty List!\r\n");

return 0;

}

if (FindList(index)->next == FindList(a))

return 0;

else

{

/*找到传入值的位置并保存*/

Node *temp = FindList(index);

/*分配空间存放新的传入的值*/

Node *pt = (Node *)malloc(sizeof(Node));

pt->data = a;

/*是否是最后一个元素*/

if (temp == end)

{

//尾巴的下一个指向新插入的节点

end->next = temp;

//新的尾巴

end = temp;

}

else

{

// 先连后面 (先将要插入的节点指针指向原来找到节点的下一个)

pt->next = temp->next;

//后连前面

temp->next = pt;

printf("The list after insert %d is \r\n",a);

PrintList(head);

}

}

}

5.在元素前面增加元素/*根据传入的数,在其前面增加元素*/

int InsertListHead(int index,int a)

{

if (head == NULL)

{

printf("Empty List!\r\n");

return 0;

}

/*要插入的位置就在原位*/

if (FindList(index)->next == FindList(a))

return 0;

else

{

/*找到传入值的位置并保存*/

Node *temp = FindList(index);

/*分配空间存放新的传入的值*/

Node *pt = (Node *)malloc(sizeof(Node));

pt->data = a;

/*是否是第一个元素*/

if (temp == head)

{

//尾巴的下一个指向新插入的节点

pt->next = head;

//新的头

head = pt;

}

else

{

/*寻找到要插入位置的前驱节点*/

Node *pre = FindPreNode(temp);

pre->next = pt;

pt->next = temp;

printf("The list after insert %d is \r\n",a);

PrintList(head);

}

}

}

6.删除链表元素,要注意删除链表尾还是链表头

从链表中删除指定数据元素时,实则就是将存有该数据元素的节点从链表中摘除,但作为一名合格的程序员,要对存储空间负责,对不再利用的存储空间要及时释放。因此,从链表中删除数据元素需要进行以下 2 步操作:

1.将结点从链表中摘下来;

2.手动释放掉结点,回收被结点占用的存储空间;

其中,从链表上摘除某节点的实现非常简单,只需找到该节点的直接前驱节点 temp,执行一行程序:temp->next=temp->next->next;

例如,从存有 {1,2,3,4} 的链表中删除元素 3,则此代码的执行效果如图 2 所示:

bb60523d2c77181228457cf5c885bbb3.png/*删除链表头*/

void DeleteListHead()

{ //记住旧头

Node *temp = head;

//链表检测

if (NULL == head)

{

printf("Empty list!\n");

return;

}

head = head->next; //头的第二个节点变成新的头

free(temp);

}

/*尾删除————删*/

void DeleteListTail()

{

if (NULL == end)

{

printf("链表为空,无需删除\n");

return;

}

//链表不为空

//链表有一个节点

if (head == end)

{

free(head);

head = NULL;

end = NULL;

}

else

{

//找到尾巴前一个节点

Node *temp = head;

while (temp->next != end)

{

temp = temp->next;

}

//找到了,删尾巴

//释放尾巴

free(end);

//尾巴迁移

end = temp;

//尾巴指针为NULL

end->next = NULL;

}

}

/*删除链表任意元素*/

void DeleteList(int a)

{

//链表判断 是不是没有东西

if (NULL == head)

{

printf("Empty list!\n");

return;

}

//链表有东西,找这个节点

Node *temp = FindList(a);

if (NULL == temp)

{

printf("%d not find\r\n",a);

return;

}

//找到了,且只有一个节点

if (head == end)

{

free(head);

head = NULL;

end = NULL;

printf("The list after delete %d is empty!\r\n",a);

}

else if (head->next == end) //有两个节点

{

//看是删除头还是删除尾

if (end == temp)

{

DeleteListTail();

printf("The list after delete %d is \r\n",a);

PrintList(head);

}

else if (temp == head)

{

DeleteListHead();

printf("The list after delete %d is \r\n",a);

PrintList(head);

}

}

else //多个节点

{

//看是删除头还是删除尾

if (end == temp)

DeleteListTail();

else if (temp == head)

DeleteListHead();

else //删除中间某个节点

{//找要删除temp前一个,遍历

Node *pt = head;

while (pt->next != temp)

{

pt = pt->next;

}

//找到了

//让前一个直接连接后一个 跳过指定的即可

pt->next = temp->next;

free(temp);

printf("The list after delete %d is \r\n",a);

PrintList(head);

}

}

}

7.根据传入的数值查询链表/*根据传入的数值,查询链表*/

Node *FindList(int a)

{

Node *temp = head;

if(head == NULL)

{

printf("Empty List!\r\n");

return NULL;

}

else

{

while (temp)

{

if (temp->data == a)

{

printf("%d find!\r\n",a);

return temp;

}

temp = temp->next;

}

printf("%d not find!\r\n",a);

return 0;

}

}

8.修改链表元素/*修改链表元素,element为要修改的元素,modify为修改后的值*/

void ModifyList(Node *phead,int element,int modify)

{

Node *temp = phead;

while((temp!= NULL))

{

if(temp->data == element)

{

temp->data= modify;

}

temp = temp->next;

}

}

9.求链表长度/*求链表长度并返回*/

int LengthList(Node *temp)

{

int length = 0;

while (temp)

{

length++;

temp = temp->next;

}

return length;

}

10.前驱,后继节点的查找Node *FindPreNode(Node *p)

{

Node *temp = head;

/*寻找p的前驱节点*/

if(p == head)

{

printf("%d is head node\r\n",p->data);

return NULL;

}

else

{

while((temp->next != p) && (temp !=NULL))

{

temp = temp->next;

}

return temp;

}

}

Node *FindNextNode(Node *p)

{

Node *temp = head;

/*寻找p的后继节点*/

while(temp &&(temp != p))

{

temp = temp->next;

}

/*先不判断是否为尾节点,尾节点NULL也可以赋值*/

temp = temp->next;

return temp;

}

11.倒置链表/*方法一:倒置链表*/

Node *InvertList(Node *phead)

{

if(phead == NULL || phead->next == NULL)

{

return phead;

}

else

{

Node *p = phead;

Node *q = NULL;

Node *r = NULL;

while(p != NULL)

{

/*保存下一个节点*/

q = p->next;

/*让该节点指向上一个节点*/

p->next = r;

/*上一个节点走到当前节点*/

r = p;

/*当前节点走到下一个节点*/

p = q;

}

head = r;

return head;

}

}

/*方法二:倒置链表*/

Node *ReverseList(Node *phead)

{

/*创建一个新链*/

/*两个指针,一个指向新的链表,一个指向单个断开的节点元素。连接起来*/

Node *ptmp = NULL;

Node *tmp = NULL;

/*处理链表为空*/

if(NULL == phead)

{

printf("link is empty\n");

return NULL;

}else

{

/*将旧链上的结点链到新链上*/

while(phead != NULL)

{

tmp = phead;

phead = phead->next;

/*连接到上一次存下来的连表上。第一次时,ptmp为空,整个链表赋值给tmp后只剩下第一个元素*/

tmp->next = ptmp;

/*新的链表赋值给ptmp*/

ptmp = tmp;

}

}

head = ptmp;

return ptmp;

}

12.判断链表是否有环/*判断链表有环*/

int Is_Circular(Node *phead)

{

if(phead == NULL || phead->next == NULL){

return 0;

}

/*快慢指针,当二者相等时,一定有环*/

Node *p1 = phead;

Node *p2 = phead;

while(p1 != NULL && p2 != NULL){

p2 = p2->next;

if(p1 == p2)

return 1;

p2 = p2->next;

p1 = p1->next;

}

return 0;

}

测试函数int main ()

{

int i = 0;

/*设置获得随机数的种子(固定代码,没有这句,随机数是固定不变的)测试可以不加*/

srand((int)time(0));

for (i =5;i>0;i--)

CreatList(rand()%MAX);

// CreatList(i);

printf("新创建的的链表为:");

PrintList(head);

InsertListHead(4,10);

printf("在4前插入10后的链表为:");

PrintList(head);

InsertListEnd(4,10);

printf("在4后插入10后的链表为:");

PrintList(head);

DeleteList(0);

printf("删除0后的链表为:");

PrintList(head);

Node *p = FindList(7);

Node *q = FindList(4);

ModifyList(head,1,15);

printf("修改1为15后的链表为:");

PrintList(head);

ReverseList(head);

printf("反转后的链表为:");

PrintList(head);

printf("链表长度为:%d",LengthList(head));

return 0;

}

测试截图

2cf2692dec32493b11e48e5fd95f795a.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值