将两个有序链表合并成一个有序链表

问题定义:

        写一个函数SortedMerge函数,该函数有两个参数,都是递增的链表,函数的功能就是合并这两个递增的链表为一个递增的链表,SortedMerge的返回值是新的链表。新链表由前两个链表按元素递增顺序合并而成,也就是说它不会创建新的元素。

比如:这里有两个链表,分别是

list1: 5->10->15

list2: 2->3->20

SortedMerge函数返回一个指向新链表的指针,新链表应该是如下这样的:2->3->5->10->15->20

    程序需要考虑如下情况:两个链表(函数参数)都有可能为空,也可能其中一个链表已经遍历完了,另一个链表还有很多元素。

方法1(虚拟节点) 

        这种方法用一个虚拟节点(dummy node)作为结果链表的起始节点,为了方便在链表尾部插入节点,还需要用一个尾指针指向链表的尾节点。

        初始时,结果链表为空的时候,尾指针指向的是虚拟节点。因为虚拟节点是一个在栈上分配的临时变量,所以对它的操作都是非常高效的。在循环迭代中,每次从a或b中取一个节点插入到结果链表的尾部,循环结束时,虚拟节点的next域就是结果链表的地址,也就是我们期望的返回值。

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <assert.h>  
  4.   
  5. /*Link list node*/  
  6. struct node  
  7. {  
  8.     int data;  
  9.     struct node* next;  
  10. };  
  11.   
  12. /*Function to insert a node at the begining of the linked list*/  
  13. void push(struct node** head_ref, int new_data)  
  14. {  
  15.     /* allocate node*/  
  16.     struct node* new_node = (struct node*)malloc(sizeof(struct node));  
  17.       
  18.     /* put in the data*/  
  19.     new_node->data = new_data;  
  20.       
  21.     /*link the old list off the new node*/  
  22.     new_node->next = (*head_ref);  
  23.   
  24.     /*move the head to point to the new node*/  
  25.     (*head_ref) = new_node;  
  26. }  
  27.   
  28. /* Function to print nodes in a given linked list */  
  29. void printList(struct node* node)  
  30. {  
  31.     while(node != NULL)  
  32.     {  
  33.         printf("%d ", node->data);  
  34.         node = node->next;  
  35.     }  
  36.     printf("\n");  
  37. }  
  38.   
  39. /*pull off the front node of the source and put it in dest*/  
  40. /* MoveNode() function takes the node from the front of the source, and move it to  
  41. the front of the dest. 
  42. It is an error to call this with the source list empty. 
  43.  
  44.     Before calling MoveNode(): 
  45.     source == {1, 2, 3} 
  46.     dest == {1, 2, 3} 
  47.      
  48.     After calling MoveNode(): 
  49.     source == {2, 3} 
  50.     dest == {1, 1, 2, 3} 
  51. */  
  52.   
  53. void MoveNode(struct node** destRef, struct node** sourceRef)  
  54. {  
  55.     /* the front source node */  
  56.     struct node* newNode = *sourceRef;  
  57.     assert(newNode != NULL);  
  58.       
  59.     /*Advance the source pointer */  
  60.     *sourceRef = newNode->next;  
  61.       
  62.     /* Link th eold dest off the new node */  
  63.     newNode->next = *destRef;  
  64.   
  65.     /*Move dest to point to the new node */  
  66.     *destRef = newNode;  
  67. }  
  68.   
  69. /*Takes two lists sorted in creasing order, and splices their nodes together to  
  70. make ont big sorted list which is returned. */  
  71. struct node* SortedMerge(struct node* a, struct node* b)  
  72. {  
  73.     /* a dummy first node to hang the result on */  
  74.     struct node dummy;  
  75.       
  76.     /* tail points to the last result node */  
  77.     struct node* tail = &dummy;  
  78.       
  79.     /*so tail->next is the places to add new nodes to the result*/  
  80.     dummy.next = NULL;  
  81.     while(1)  
  82.     {  
  83.         if(a == NULL)  
  84.         {  
  85.             tail->next = b;  
  86.             break;  
  87.         }  
  88.         else if(b == NULL)  
  89.         {  
  90.             tail->next = a;  
  91.             break;  
  92.         }  
  93.   
  94.         if(a->data <= b->data)  
  95.         {  
  96.             MoveNode(&(tail->next), &a);  
  97.         }  
  98.         else  
  99.         {  
  100.             MoveNode(&(tail->next), &b);  
  101.         }  
  102.         tail = tail->next;  
  103.     }     
  104.     return (dummy.next);  
  105. }  
  106. /*Drier program to test above functions */  
  107. int main(int argc, char* argv[])  
  108. {  
  109.   
  110.     /*start with the empty list */  
  111.     struct node* res = NULL;  
  112.     struct node* a = NULL;  
  113.     struct node* b = NULL;  
  114.   
  115.     /*Let us create two sorted linked lists to test the functions  
  116.     Created lists shall be a:5->10->15, b:2->3->20 */  
  117.   
  118.     push(&a, 15);  
  119.     push(&a, 10);  
  120.     push(&a, 5);  
  121.   
  122.     push(&b, 20);  
  123.     push(&b, 3);  
  124.     push(&b, 2);  
  125.   
  126.     res = SortedMerge(a, b);  
  127.     printf("\nMerged Linked List is:\n");  
  128.     printList(res);  
  129.     return 0;  
  130. }  


方法2(局部引用)

        这种方法与上一种方法非常相似。这种方法避免使用虚拟节点(dummy node),而是使用一个指向指针的指针,struct node** lastPtrRef,这个指针指向结果链表的最后一个节点。在这个方法中,所有由虚拟节点完成的工作都有lastPtrRef完成。

  1. /* method2 Using local References */  
  2. struct node* SortedMerge(struct node* a, struct node* b)  
  3. {  
  4.     struct node* result = NULL;  
  5.   
  6.     /*point to the last result pointer */  
  7.     struct node** lastPtrRef = &result;  
  8.   
  9.     while(1)  
  10.     {  
  11.         if(a == NULL)  
  12.         {  
  13.             *lastPtrRef = b;  
  14.             break;  
  15.         }  
  16.         else if(b == NULL)  
  17.         {  
  18.             *lastPtrRef = a;  
  19.             break;  
  20.         }  
  21.         if(a->data <= b->data)  
  22.         {  
  23.             MoveNode(lastPtrRef, &a);  
  24.         }  
  25.         else  
  26.         {  
  27.             MoveNode(lastPtrRef, &b);  
  28.         }  
  29.         /*tricky:advance to point to the next ".next" field */  
  30.         lastPtrRef = &((*lastPtrRef)->next);  
  31.     }  
  32.     return (result);  
  33. }  


方法3(递归)

        合并操作是非常适合用递归来完成的一类操作,递归实现将会比迭代实现更加清晰且易于理解。尽管如此,你可能也不愿意使用递归来实现这个操作,因为递归方法所使用的栈空间与链表的长度成正比。

  1. /*Using Recursion*/  
  2. struct node* SortedMerge(struct node* a, struct node* b)  
  3. {  
  4.     struct node* result = NULL;  
  5.       
  6.     /*Base cases*/  
  7.     if(a == NULL)  
  8.         return (b);  
  9.     else if(b == NULL)  
  10.         return (a);  
  11.   
  12.     /*Pick either a or b, and recur */  
  13.     if(a->data <= b->data)  
  14.     {  
  15.         result = a;  
  16.         result->next = SortedMerge(a->next, b);  
  17.     }  
  18.     else  
  19.     {  
  20.         result = b;  
  21.         result->next = SortedMerge(a, b->next);  
  22.     }  
  23.     return (result);  
  24. }  
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值