有序单链表的合并
@Author: 张海拔
@Update: 2014-01-23
@Link: http://www.cnblogs.com/zhanghaiba/p/3531142.html
1 /* 2 *Author: ZhangHaiba 3 *Date: 2014-1-23 4 *File: sorted_list_merge.c 5 * 6 *a demo shows how to merge two sorted single linked list by 7 *creating a new list or in-place. 8 */ 9 10 #include <stdio.h> 11 #include <stdbool.h> 12 #include <stdlib.h> 13 #define INF 0x7fffffff 14 #define CMD_LNE 128 15 16 typedef struct node* link; 17 typedef struct node { 18 int item; 19 link next; 20 }node; 21 22 //public 23 link NODE(int item, link next); 24 link list_create(int n); 25 link sorted_list_merge_create1(link list_src_a, link list_src_b); 26 link sorted_list_merge_create2(link list_src_a, link list_src_b); 27 link sorted_list_merge_in_place1(link list_src_a, link list_src_b); 28 link sorted_list_merge_in_place2(link list_src_a, link list_src_b); 29 void list_travel(link head); 30 void list_destroy(link head); 31 //private 32 //accept list without Head Node, and return list without Head Node as well 33 link sorted_list_merge_create_iter(link a, link b); 34 link sorted_list_merge_in_place_iter(link a, link b); 35 link sorted_list_merge_create_rec(link a, link b); 36 link sorted_list_merge_in_place_rec(link a, link b); 37 38 39 int main(void) 40 { 41 int len_a, len_b; 42 43 scanf("%d", &len_a); 44 link list_a = list_create(len_a); 45 printf("list_a travel: "); 46 list_travel(list_a); 47 48 scanf("%d", &len_b); 49 link list_b = list_create(len_b); 50 printf("list_b travel: "); 51 list_travel(list_b); 52 53 printf("create list_c by using(merging) list_a and list_b nodes.\n"); 54 //link list_c = sorted_list_merge_create1(list_a, list_b); 55 link list_c = sorted_list_merge_create2(list_a, list_b); 56 printf("list_c travel: "); 57 list_travel(list_c); 58 59 printf("merge list_c and list_a to list_d.\n"); 60 //link list_d = sorted_list_merge_in_place1(list_c, list_a); 61 link list_d = sorted_list_merge_in_place2(list_c, list_a); 62 printf("list_d travel: "); 63 list_travel(list_d); 64 65 list_c = list_a = NULL; 66 list_destroy(list_b); 67 printf("list_b destroyed!\n"); 68 list_destroy(list_d); 69 printf("list_d destroyed!\n"); 70 return 0; 71 } 72 73 link NODE(int item, link next) 74 { 75 link born = malloc(sizeof (node)); 76 born->item = item; 77 born->next = next; 78 return born; 79 } 80 81 //tail insert 82 link list_create(int n) 83 { 84 int i, item; 85 link head = NODE(INF, NULL); 86 link tail = head; 87 88 for (i = 0; i < n; ++i) { 89 scanf("%d", &item); 90 tail->next = NODE(item, NULL); 91 tail = tail->next; 92 } 93 return head; 94 } 95 96 //Iterative implementation begin here 97 link sorted_list_merge_create_iter(link a, link b) 98 { 99 link tmp_head = NODE(INF, NULL); 100 link c = tmp_head; //c as tail pointer for the list_c 101 102 for (; a != NULL && b != NULL; c = c->next) 103 if (a->item < b->item) 104 c->next = NODE(a->item, NULL), a = a->next; 105 else 106 c->next = NODE(b->item, NULL), b = b->next; 107 for (; a != NULL; c = c->next, a = a->next) 108 c->next = NODE(a->item, NULL); 109 for (; b != NULL; c = c->next, b = b->next) 110 c->next = NODE(b->item, NULL); 111 link first = tmp_head->next; 112 free(tmp_head); 113 return first; 114 } 115 116 link sorted_list_merge_create1(link a, link b) 117 { 118 if (a == NULL || b == NULL) 119 return NULL; 120 return NODE(INF, sorted_list_merge_create_iter(a->next, b->next)); 121 } 122 123 link sorted_list_merge_in_place_iter(link a, link b) 124 { 125 link tmp_head = NODE(INF, NULL); 126 link c = tmp_head; //c as tail pointer for the list_c 127 128 for (; a != NULL && b != NULL; c = c->next) 129 if (a->item < b->item) 130 c->next = a, a = a->next; 131 else 132 c->next = b, b = b->next; 133 c->next = a != NULL ? a : b; //link left ordered list 134 link first = tmp_head->next; 135 free(tmp_head); 136 return first; 137 } 138 139 link sorted_list_merge_in_place1(link a, link b) 140 { 141 if (a == NULL || b == NULL) 142 return NULL; 143 link head = NODE(INF, sorted_list_merge_in_place_iter(a->next, b->next)); 144 free(a); 145 free(b); 146 return head; 147 } 148 //Iterative implementation end here 149 150 151 //Recursive implementation begin here 152 link sorted_list_merge_create_rec(link a, link b) 153 { 154 link first = NULL; 155 156 if (a == NULL) { 157 link tmp_head = NODE(INF, NULL); 158 link c = tmp_head; //c as tail pointer for left list 159 while (b != NULL) { 160 c->next = NODE(b->item, NULL); 161 c = c->next; 162 b = b->next; 163 } 164 link left = tmp_head->next; 165 free(tmp_head); 166 return left; 167 } 168 if (b == NULL) { 169 link tmp_head = NODE(INF, NULL); 170 link c = tmp_head; //c as tail pointer for left list 171 while (a != NULL) { 172 c->next = NODE(a->item, NULL); 173 c = c->next; 174 a = a->next; 175 } 176 link left = tmp_head->next; 177 free(tmp_head); 178 return left; 179 } 180 if (a->item < b->item) { 181 first = NODE(a->item, NULL); 182 first->next = sorted_list_merge_create_rec(a->next, b); 183 } else { 184 first = NODE(b->item, NULL); 185 first->next = sorted_list_merge_create_rec(b->next, a); 186 } 187 return first; 188 } 189 190 link sorted_list_merge_create2(link a, link b) 191 { 192 if (a == NULL || b == NULL) 193 return NULL; 194 return NODE(INF, sorted_list_merge_create_rec(a->next, b->next)); 195 } 196 197 link sorted_list_merge_in_place_rec(link a, link b) 198 { 199 if (a == NULL) 200 return b; 201 if (b == NULL) 202 return a; 203 link first = NULL; 204 if (a->item < b->item) { 205 first = a; 206 first->next = sorted_list_merge_in_place_rec(a->next, b); 207 } else { 208 first = b; 209 first->next = sorted_list_merge_in_place_rec(a, b->next); 210 } 211 return first; 212 } 213 214 link sorted_list_merge_in_place2(link a, link b) 215 { 216 if (a == NULL || b == NULL) 217 return NULL; 218 link head = NODE(INF, sorted_list_merge_in_place_rec(a->next, b->next)); 219 free(a); 220 free(b); 221 return head; 222 } 223 //Recursive implementation end here 224 225 void list_travel(link head) 226 { 227 for (head = head->next; head != NULL; head = head->next) 228 printf(head->next == NULL ? "%d\n" : "%d ", head->item); 229 } 230 231 void list_destroy(link head) 232 { 233 head->next == NULL ? free(head) : list_destroy(head->next); 234 }
测试示例:
ZhangHaiba-MacBook-Pro:code apple$ ./a.out 6 30 53 65 77 88 99 list_a travel: 30 53 65 77 88 99 9 11 22 33 44 55 100 120 199 211 list_b travel: 11 22 33 44 55 100 120 199 211 create list_c by using(merging) list_a and list_b nodes. list_c travel: 11 22 30 33 44 53 55 65 77 88 99 100 120 199 211 merge list_c and list_a to list_d. list_d travel: 11 22 30 30 33 44 53 53 55 65 65 77 77 88 88 99 99 100 120 199 211 list_b destroyed! list_d destroyed!
单链表的合并,给出了两个接口(函数):sorted_list_merge_create()和sorted_list_merge_in_place()。分别对应非就地合并和就地合并。
两个函数各有用武之地,非就地合并生成一个新链表,输入的两个链表还可以继续使用;
就地合并则把输入的两个链表a和b合并为一个链表c,合并后a和b逻辑上就不存在了。
由于这里操作的链表是:带头节点的单链表。
考虑函数的复用性,首先设计的合并函数A:接收两个不带头节点的链表,返回一个不带头节点的(新)链表。
带头节点的链表只是不带头节点的链表的一种限定(子集),
所以通过设计一个外壳函数包装上一步实现的合并函数A,就可以实现带头节点的单链表合并的函数B。
合并函数B:接收两个带头节点的链表,返回一个带头节点的(新)链表。规定传入链表的头节点不能为空,否则返回NULL。
A函数对应上述实现中的
sorted_list_merge_create_iter()和sorted_list_merge_create_rec()
sorted_list_merge_in_place_iter()和sorted_list_merge_in_place_rec()
下面从实现方法的角度做一个纵向对比——
(1)迭代实现
迭代实现中,借助了一个临时头节点,这样才能保存第一个节点的指针first,返回first之前先释放临时头节点
1)非就地合并
如果b遍历完了a还没完,则把a剩下的依次复制到新链表后面;b同理。
2)就地合并
如果b遍历完了a还没完,则把a剩下的链表一次链接到tail指针c中即可,效率很高的说;b同理。
(2)递归实现
1)非就地合并
若链表a为空,则复制b剩下的链表(借助了临时头节点来实现,返回left前释放临时头节点);b同理。
否则选较小的节点复制作为当前链表的根节点,然后合并剩下的链表作为子链表。
2)就地合并
若链表a为空,则直接返回链表b;b同理。
否则选较小的节点作为当前链表的根节点,然后合并剩下的链表作为子链表。
对于外壳函数,非就地合并没啥可说,就地合并返回前还需要释放a和b的头节点。
客户端程序(主函数)中,就地合并c和a之后,有责任把c和a置为NULL,因为调用方知道此时c和a已经不存在了。
小结:单链表的非就地合并和就地合并,都是利用了链表的“尾插法”来建表。区别是,前者生成节点,后者链入节点,且后者的效率会更高。