问题定义:
写一个函数SortedMerge函数,该函数有两个参数,都是递增的链表,函数的功能就是合并这两个递增的链表为一个递增的链表,SortedMerge的返回值是新的链表。新链表由前两个链表按元素递增顺序合并而成,也就是说它不会创建新的元素。
比如:这里有两个链表,分别是
list1: 5->10->15
list2: 2->3->20
SortedMerge函数返回一个指向新链表的指针,新链表应该是如下这样的:2->3->5->10->15->20
程序需要考虑如下情况:两个链表(函数参数)都有可能为空,也可能其中一个链表已经遍历完了,另一个链表还有很多元素。
方法1(虚拟节点)
这种方法用一个虚拟节点(dummy node)作为结果链表的起始节点,为了方便在链表尾部插入节点,还需要用一个尾指针指向链表的尾节点。
初始时,结果链表为空的时候,尾指针指向的是虚拟节点。因为虚拟节点是一个在栈上分配的临时变量,所以对它的操作都是非常高效的。在循环迭代中,每次从a或b中取一个节点插入到结果链表的尾部,循环结束时,虚拟节点的next域就是结果链表的地址,也就是我们期望的返回值。
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- /*Link list node*/
- struct node
- {
- int data;
- struct node* next;
- };
- /*Function to insert a node at the begining of the linked list*/
- void push(struct node** head_ref, int new_data)
- {
- /* allocate node*/
- struct node* new_node = (struct node*)malloc(sizeof(struct node));
- /* put in the data*/
- new_node->data = new_data;
- /*link the old list off the new node*/
- new_node->next = (*head_ref);
- /*move the head to point to the new node*/
- (*head_ref) = new_node;
- }
- /* Function to print nodes in a given linked list */
- void printList(struct node* node)
- {
- while(node != NULL)
- {
- printf("%d ", node->data);
- node = node->next;
- }
- printf("\n");
- }
- /*pull off the front node of the source and put it in dest*/
- /* MoveNode() function takes the node from the front of the source, and move it to
- the front of the dest.
- It is an error to call this with the source list empty.
- Before calling MoveNode():
- source == {1, 2, 3}
- dest == {1, 2, 3}
- After calling MoveNode():
- source == {2, 3}
- dest == {1, 1, 2, 3}
- */
- void MoveNode(struct node** destRef, struct node** sourceRef)
- {
- /* the front source node */
- struct node* newNode = *sourceRef;
- assert(newNode != NULL);
- /*Advance the source pointer */
- *sourceRef = newNode->next;
- /* Link th eold dest off the new node */
- newNode->next = *destRef;
- /*Move dest to point to the new node */
- *destRef = newNode;
- }
- /*Takes two lists sorted in creasing order, and splices their nodes together to
- make ont big sorted list which is returned. */
- struct node* SortedMerge(struct node* a, struct node* b)
- {
- /* a dummy first node to hang the result on */
- struct node dummy;
- /* tail points to the last result node */
- struct node* tail = &dummy;
- /*so tail->next is the places to add new nodes to the result*/
- dummy.next = NULL;
- while(1)
- {
- if(a == NULL)
- {
- tail->next = b;
- break;
- }
- else if(b == NULL)
- {
- tail->next = a;
- break;
- }
- if(a->data <= b->data)
- {
- MoveNode(&(tail->next), &a);
- }
- else
- {
- MoveNode(&(tail->next), &b);
- }
- tail = tail->next;
- }
- return (dummy.next);
- }
- /*Drier program to test above functions */
- int main(int argc, char* argv[])
- {
- /*start with the empty list */
- struct node* res = NULL;
- struct node* a = NULL;
- struct node* b = NULL;
- /*Let us create two sorted linked lists to test the functions
- Created lists shall be a:5->10->15, b:2->3->20 */
- push(&a, 15);
- push(&a, 10);
- push(&a, 5);
- push(&b, 20);
- push(&b, 3);
- push(&b, 2);
- res = SortedMerge(a, b);
- printf("\nMerged Linked List is:\n");
- printList(res);
- return 0;
- }
方法2(局部引用)
这种方法与上一种方法非常相似。这种方法避免使用虚拟节点(dummy node),而是使用一个指向指针的指针,struct node** lastPtrRef,这个指针指向结果链表的最后一个节点。在这个方法中,所有由虚拟节点完成的工作都有lastPtrRef完成。
- /* method2 Using local References */
- struct node* SortedMerge(struct node* a, struct node* b)
- {
- struct node* result = NULL;
- /*point to the last result pointer */
- struct node** lastPtrRef = &result;
- while(1)
- {
- if(a == NULL)
- {
- *lastPtrRef = b;
- break;
- }
- else if(b == NULL)
- {
- *lastPtrRef = a;
- break;
- }
- if(a->data <= b->data)
- {
- MoveNode(lastPtrRef, &a);
- }
- else
- {
- MoveNode(lastPtrRef, &b);
- }
- /*tricky:advance to point to the next ".next" field */
- lastPtrRef = &((*lastPtrRef)->next);
- }
- return (result);
- }
方法3(递归)
合并操作是非常适合用递归来完成的一类操作,递归实现将会比迭代实现更加清晰且易于理解。尽管如此,你可能也不愿意使用递归来实现这个操作,因为递归方法所使用的栈空间与链表的长度成正比。
- /*Using Recursion*/
- struct node* SortedMerge(struct node* a, struct node* b)
- {
- struct node* result = NULL;
- /*Base cases*/
- if(a == NULL)
- return (b);
- else if(b == NULL)
- return (a);
- /*Pick either a or b, and recur */
- if(a->data <= b->data)
- {
- result = a;
- result->next = SortedMerge(a->next, b);
- }
- else
- {
- result = b;
- result->next = SortedMerge(a, b->next);
- }
- return (result);
- }