单链表的操作

文件名为:linklist.h
3 * 文件作用:声明结构体,声明各个操作函数,便于主函数的调用
4 * 文件用途:用于单链表的操作使用
5 /
6 typedef int datatype; /自定义变量datatype 便于阅读。/
7 /
定义结构体部分*/
8 typedef struct node{
9 datatype data;
10 int no;
11 struct node * next;
12 }listnode,linklist;
13
14 /
声明各个操作函数*/
15 /* 声明创建空表函数,返回值为空表指针*/
16 linklist list_create(void);
17 /* 声明头结点插入节点函数,返回值为操作是否成功,成功:0失败:-1*/
18 int list_head_insert(linklist H,datatype x);
19 /* 声明按节点编号插入节点函数,返回值为操作是否成功,成功:0失败:-1*/
20 int list_pos_insert(linklist H,datatype x,int pos);
21 /* 声明按数值查找函数,返回值为节点编号,失败:-1*/
22 int list_number_search(linklist H,datatype x);
23 /* 声明按节点序号查找函数,返回值为该节点编号下的数值,失败:-1*/
24 int list_pos_search(linklist H,int pos);
25 /* 声明删除指定节点编号的节点函数,返回值为操作是否成功,成功:0失败:-1*/
26 int list_delete(linklist H,int pos);
27 /* 声明将链表数据全部倒置,返回值为操作是否成功,成功:0失败:-1*/
28 int list_invode(linklist H);
29 /* 声明链表输出显示各个节点数据的函数,返回值为操作是否成功,成功:0失败:-1*/
30 int list_show(linklist H);
复制代码
以上便是头文件的编写,下面创建linklist.c文件,用于各个函数功能的实现。由于文件中代码行数较多,不方便讲述,所以下面的讲述,不是将代码整段贴在下面,而是以函数为单位进行了分割,组合起来和源文件也是一模一样的。

   第一个函数功能是创建空表,函数没有参数,但是返回值是指向创建空表的指针。首先要创建动态内存,赋值给空表指针,判断指针是否为空来确定动态内存是否分配成功,若成功,则继续给空表内的各个数值及指针赋值。最后返回指针,完成空表的创建。

复制代码
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include “linklist.h”
4 linklist list_create(void)
5 {
6 linklist H = NULL;
7 /* 申请动态内存,赋值给指针*/
8 H = (linklist)malloc(sizeof(listnode));
9 /* 判断动态内存是否申请成功*/
10 if(H == NULL)
11 {
12 printf(“no memory\n”);
13 return NULL;
14 }else
15 {
16 /* 给空表中结构体中的各个成员赋值*/
17 H -> data = 0;
18 H -> no = -1;
19 H -> next = NULL;
20 /* 返回空表指针*/
21 return H;
22 }
23 }
复制代码
第二个函数功能是,在头结点之后插入结点元素。函数有两个参数,第一个参数是:所要插入节点的链表指针,第二个参数是:插入节点中结构体成员中数据的数值。返回值为操作是否成功,若成功则返回0,若失败则返回-1。

   首先要判断传参传入的链表指针是否为空,若为空说明是一个失败的链表,不能继续执行插入操作,因此返回-1,就此程序结束;若不为空则继续执行插入操作。在执行插入之前先要创建一个节点,节点的创建也需要申请动态内存管理空间,将动态内存申请的节点指针,赋予头结点的节点指针,头结点的节点指针赋予动态内存申请的指针,将参数传入的数据赋值给新创建的节点结构体中的成员,成员编号赋予0,表示头结点的下一个编号。由于每次调用这个函数,我们不能确定是第几次给头结点插入节点,因此节点的编号必然需要刷新,这样构建循环,在循环中让插入的节点的下一个节点依次自增1,使编号不会混乱。最后返回0值表明程序顺利执行。

复制代码
1 int list_head_insert(linklist H,datatype x)
2 {
3 linklist P = NULL;
4 /* 判断传入的链表是否为空*/
5 if(H == NULL)
6 {
7 printf(“linklist H is NULL\n”);
8 return -1;
9 }else
10 {
11 /* 创建节点,动态内存*/
12 P = (linklist)malloc(sizeof(listnode));
13 if(P == NULL)
14 {
15 printf(“no memory\n”);
16 return -1;
17 }else
18 {
19 /* 插入节点操作,直接赋值*/
20 P -> next = H -> next;
21 H -> next = P;
22 P -> data = x;
23 P -> no = H -> no + 1;
24 /* 刷新各个节点的编号*/
25 while(P -> next != NULL)
26 {
27 P -> next -> no ++;
28 P = P -> next;
29 }
30 return 0;
31 }
32 }
33 }
复制代码
第三个函数的功能是,依据节点编号插入节点。函数有三个参数,第一个参数是:所要插入节点的链表指针;第二个参数是:所要插入节点的数据值;第三个参数是:所要插入节点在链表中的节点序号。返回值为操作是否成功,若成功则返回0,若失败则返回-1。

   程序的开始依旧是判断传参传入的链表指针是否为空,若不为空,则继续执行,申请动态内存创建节点,首先要循环找到指定编号的指针的前一个指针(因为是单链表,所以没有反向的连接以进行灵活的赋值),然后新创建的节点指针赋予指定编号的前一个节点指针,指定编号的前一个节点指针赋予新创建的指针,之后便是成员赋值和刷新编号。

复制代码
1 int list_pos_insert(linklist H,datatype x,int pos)
2 {
3 linklist P = NULL;
4 linklist Q = NULL;
5 /* 判断传入的链表指针是否为空*/
6 if(H == NULL)
7 {
8 printf(“linklist H is NULL\n”);
9 return -1;
10 }else
11 {
12 /*  创建新节点*/
13 P = (linklist)malloc(sizeof(listnode));
14 if(P == NULL)
15 {
16 printf(“no memory\n”);
17 return -1;
18 }else
19 {
20 /* 找到指定编号的前一个节点*/
21 Q = H;
22 while(Q -> next -> no != pos)
23 {
24 Q = Q -> next;
25 }
26 /* 插入操作*/
27 P -> next = Q -> next;
28 Q -> next = P;
29 /* 成员赋值*/
30 P -> data = x;
31 /* 刷新节点编号*/
32 P -> no = pos;
33 while(P -> next != NULL)
34 {
35 P -> next -> no ++;
36 P = P -> next;
37 }
38 Q = NULL;
39 P = NULL;
40 return 0;
41 }
42 }
43 }
复制代码
第四个和第五个函数功能分别是按值查找和按位查找,代码很简单,也没有复杂的刷新编号操作,在此就不再赘述。仅将代码陈述其下,以供参考。

复制代码
1 int list_number_search(linklist H,datatype x)
2 {
3 linklist P = NULL;
4 if(H == NULL)
5 {
6 printf(“linklist H is NULL\n”);
7 return -1;
8 }else
9 {
10 P = H;
11 while(P -> data != x)
12 {
13 P = P -> next;
14 }
15 return P -> no;
16 }
17 }
18
19 /按位查找的返回值是指定节点编号的数据值/
20 int list_pos_search(linklist H,int pos)
21 {
22 linklist P = NULL;
23 if(H == NULL)
24 {
25 printf(“linklist H is NULL\n”);
26 return -1;
27 }else
28 {
29 P = H;
30 while(P -> no != pos)
31 {
32 P = P -> next;
33 }
34 return P -> data;
35 }
36 }
复制代码
第六个函数功能是,删除指定编号的节点。函数有两个参数,第一个参数是:要删除节点的链表的指针;第二个参数是:指定删除的节点编号。返回值是操作是否成功,若成功则返回0,若失败则返回-1。

   第一步是要找到指定编号的节点前一个节点的指针。第二步指针赋值,第三部释放删除节点的动态内存空间,第四步刷新节点编号,第五步返回操作结果。

复制代码
1 int list_delete(linklist H,int pos)
2 {
3 linklist P = NULL;
4 linklist Q = NULL;
5 /* 判断传入链表指针是否为空*/
6 if(H == NULL)
7 {
8 printf(“linklist H is NULL\n”);
9 return -1;
10 }else
11 {
12 /* 找到指定编号节点的前一个节点的指针*/
13 P = H;
14 while(P -> next -> no != pos)
15 {
16 P = P -> next;
17 }
18 /* 删除操作*/
19 Q = P -> next;
20 P -> next = Q -> next;
21 free(Q);
22 Q = NULL;
23 /* 刷新节点编号*/
24 while(P -> next != NULL)
25 {
26 P -> next -> no --;
27 P = P -> next;
28 }
29 P = NULL;
30 return 0;
31 }
32 }
复制代码
第七个函数功能是,将链表中的节点依次倒置。函数只有一个参数,就是传入待倒置的链表指针。返回值是操作是否成功,若成功则返回0,若失败则返回-1。

   实现倒置的原理很简单,就是将链表一分为二,然后依次从头结点重新插入,这样便实现了倒置操作。着重提示的便是节点编号的刷新问题。

复制代码
1 int list_invode(linklist H)
2 {
3 linklist P = NULL;
4 linklist Q = NULL;
5 /* 判断传入链表的指针是否为空*/
6 if(H == NULL)
7 {
8 printf(“linklist H is NULL\n”);
9 return -1;
10 }else
11 {
12 /* 将链表一分为二*/
13 P = H -> next;
14 H -> next = NULL;
15 /* 依次从头结点插入节点*/
16 while(P -> next != NULL)
17 {
18 Q = P -> next;
19 P -> next = H -> next;
20 H -> next = P;
21 P -> no = 0;
22 /* 刷新结点编号*/
23 while(P -> next != NULL)
24 {
25 P -> next -> no ++;
26 P = P -> next;
27 }
28 P = Q;
29 }
30 /* 为最后一个节点补充插入操作*/
31 P -> next = H -> next;
32 H -> next = P;
33 P -> no = 0;
34 while(P -> next != NULL)
35 {
36 P -> next -> no ++;
37 P = P -> next;
38 }
39 return 0;
40 }
41 }
复制代码
第八个函数功能是,输出显示链表数据。函数只有一个参数,待显示数据的链表指针。返回值是操作结果是否成功,若成功则返回0,若失败则返回-1。

复制代码
1 int list_show(linklist H)
2 {
3 linklist P = NULL;
4 /* 判断传入链表指针是否为空*/
5 if(H == NULL)
6 {
7 printf(“linklist H is NULL\n”);
8 return -1;
9 }else
10 {
11 /* 输出打印数值*/
12 P = H -> next;
13 while(P != NULL)
14 {
15 printf(“H -> data number %d is %d\n”,P -> no,P -> data);
16 P = P -> next;
17 }
18 return 0;
19 }
20 }
复制代码
以上便是linklist.c的文件内容,下面创建test.c的文件,用于测试函数的功能是否正确、完整。

复制代码
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include “linklist.h”
4 int main()
5 {
6 linklist H = NULL;
7 /* 创建空链表*/
8 H = list_create();
9 /* 从头结点插入节点*/
10 list_head_insert(H,10);
11 list_head_insert(H,20);
12 list_head_insert(H,30);
13 list_head_insert(H,40);
14 list_head_insert(H,50);
15 list_show(H);
16 printf(“insert 2=========================\n”);
17 /* 插入操作演示*/
18 list_pos_insert(H,99,2);
19 list_show(H);
20 printf(“delete 2=========================\n”);
21 /* 删除操作演示*/
22 list_delete(H,2);
23 list_show(H);
24 printf(“invode===========================\n”);
25 /* 倒置操作演示*/
26 list_invode(H);
27 list_show(H);
28 return 0;
29 }
复制代码
之后便创建Makefile文件,进行编译。

1 CFLAGS=-c –Wall –g
2 test:linklist.o test.o
3 .PHONY:clean
4 clean:
5 rm *.o test
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值