stA;//先把A的结点链到C表
29 listC = listA;//listC等价于尾指针
30 //A指针后移,继续循环比较
31 listA = listA->next;
32 }
33 else
34 {
35 //把B的结点插入到C(尾插)
36 listC->next = listB;
37 listC = listB;
38 listB = listB->next;
39 }//end of if
40 }//end of while
41 //循环结束,只需要把剩下的某个表的结点一次性链接到C表尾
42 if (listA)
43 {
44 //说明B空
45 listC->next = listA;
46 }
47
48 if (listB)
49 {
50 //A空
51 listC->next = listB;
52 }
53 //最后AB表比较之前一定有一个表都被遍历了(也就是链接到了C),剩下的结点比如属于某个表的,最后也都链接到C尾部
54 //那么,此时就还有一个结点,那就是B表的头结点!勿忘把B表头结点释放,这才是完全的两个归并为一个
55 free(LB);
56 LB = NULL;//杜绝野指针
57 }
复制代码
算法时间复杂度,和头插法比较的话,还是O(n),其实顺序表的有序归并也是这个时间复杂度O(A.length + B.length),但是链表的尾插法归并没有移动元素,只是解除和重建链接的操作,也没有额外开辟内存空间。空间复杂度不同。
复制代码
1 /*
2 8、销毁单链表
3 */
4 void destoryLinkList(LinkList *L)
5 {
6 LinkList p = NULL;
7
8 while (*L)
9 {
10 p = (*L)->next;
11 free(*L);//free不能对指向NULL的指针使用多次!
12 *L = p;
13 //彻底搞掉指针本身,free(L)仅仅是销毁指针指向的内存,故还要连头结点一起干掉,不过while循环里隐形的包含了
14 }
15
16 *L = NULL;
17 puts("链表L已经销毁,不存在!");
18 }
复制代码
函数内部有动态分配内存的情形,应该把参数设定为指向指针的指针,当然还有别的方法,我习惯而已。
记得说:值传递函数,是把实参的一个拷贝送到函数体,函数体修改的是那份传入的拷贝,不是函数跑到main里去给它修改。
且形参和传入的拷贝,还有函数体内的变量(栈中分配的内存),都是是代码块内的自动存储类型的变量,也就是局部变量,函数执行完毕,变量自动销毁,改变就不起作用。
指针形参可以改变实参,但是如果是针对函数内动态分配了内存的情况,把堆分配的内存地址赋给了指针参数,改变的是指针指向的内容,而指针变量(形参)本身的内存地址没有改变,故根本句不会成功修改实参。
指向指针的指针,存放的是指向实参内存地址A的指针的地址B,修改B地址,改变了B指向的内容,而B指向的内容恰恰就是一级指针A本身,一级指针A的修改,使得实参被改变,对实参(指针变量C),需要取出指针C自己的的地址,传入函数。达到间接修改实参的目的。
复制代码
1 /*
2 9、求表长,长度保存在头结点
3 */
4 void getLength(LinkList L)
5 {
6 int length = 0;
7 LinkList p = NULL;
8
9 if (L)
10 {
11 p = L->next;
12
13 while (p)
14 {
15 p = p->next;
16 length++;
17 }
18
19 L->data = length;
20 printf("%d\n", L->data);
21 }
22 else
23 {
24 puts("表已经销毁!无法计算长度了……");
25 }
26 }
复制代码
复制代码
1 /*
2 10、遍历链表
3 */
4 void traversalList(LinkList L)
5 {
6 int i = 0;
7 int length = 0;
8 LinkList p = L->next;
9 length = L->data;//遍历之前,务必先求表长!
10 puts("遍历之前,务必先求表长!");
11
12 for (; i < length; i++)
13 {
14 putchar(p->data);
15 p = p->next;
16 }
17 putchar('\n');
18 }
复制代码
测试
复制代码
1 #include
2 #include
4 #include "ADT.h"
5
6 int main(void)
7 {
8 LinkList L = NULL;//完全的空表,连头结点都没有
9 LinkList LTwo = NULL;
10 LinkList val = NULL;
11 int i = 0;
12 char value = '0';
13
14 puts("请输入5个字符变量(一行一个):");
15 puts("使用尾插法建立单链表L,5个结点,一个头结点");
16 //输入 12345
17 createListByTail(&L, 5);//尾插法建表
18
19 //12345正确的存入到了5个结点里,尾插法创建了一个单链表L
20
21 //先求长度
22 puts("L长度为");
23 getLength(L);
24
25 //遍历 12345
26 puts("遍历这个链表结点元素");
27 traversalList(L);
28
29 //用完必须销毁
30 puts("把链表L销毁,L = NULL;");
31 destoryLinkList(&L);
32
33 //头插法 abcde
34 //void createListByHead(<wo, 5);//报错;语法错误 : 缺少“;”(在“类型”的前面)
35 puts("使用头插法建立新的单