有序单链表的合并

  #返回上一级

@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已经不存在了。

 

小结:单链表的非就地合并和就地合并,都是利用了链表的“尾插法”来建表。区别是,前者生成节点,后者链入节点,且后者的效率会更高。

 

  #返回上一级

posted @ 2014-01-23 14:38  张海拔  阅读(918)  评论(0编辑  收藏  举报