Merge Two Sorted Single-linke List

引言
在解决某个算法问题的时候,我们经常会遇到这样的情况:单纯解决这个问题本身并不难,但是如果在解决问题的同时我们还需要考虑到时间复杂度和空间复杂度,这时候情况就显得稍微复杂一点。那么对于某个具体的问 题,我们如何才能设计出高效的算法呢?本文通过对一个具体问题的分析试图阐述一个这样的观点: 对题目已知条件的充分挖掘和理解是设计出高效算法的前提

近日在CSDN上看到一个关于单链的算法题:
        "将两个已经按升序排列的单链合并成一个按升序排列的单链“
拿到这个题目的时候,我就有意识的去关注题目的已知条件并注意到其中包含两条重要的信息:
1。单链。 我的另外一篇文章中已经分析了单链的一些特点,即它的迭代操作只能向前,不能后退,在迭代过程中可以使用额外的变量来保存需要的结点。
2.。已升序排列。由于两个单链都已经是排好序的,合并的结果也要求一个排好序的单链,很显然这个条件可能为我们的算法设计提供有意义的帮助。

我们可以设想这样一个最简单(也是最特殊)的一种情况: 一个单链的最后的一个结点(即这个单链中最大的结点),小于另外一个单链的第一个结点(即这个单链中最小的结点),在这种情况下,这两个单链的合并就显得异常的简单:我们只需要把这两个单链简单的串联起来即可,即将一个单链的最后一个结点的Next指针指向另一个单链的头结点。在这种特殊的情况下,我们充分利用了两个单链都已经排好序的条件,那么在其他更一般的情况下我们可否利用这个条件呢?经过一段时间的思考,利用已经排好序这个有利条件并根据单链的递归特性我设计出一个递归算法:
1。声明一些变量并初始化:
   Node *  pHeadA  =  pListA;     /* list A */
   Node
*  pHeadB  =  pListB;     /* list B */

2。在pHeadB单链中寻找第一个满足以下两个条件的结点:
      结点的值小于由pHeadA所指向的单链的头结点;
      结点的Next结点的值大于由pHeadA所指向的单链的头结点;

3。如果能够找到这样的结点。首先将pHeadB从此结点处断开,此时需要保存此结点后面的结点:
        Node *  pActiveNode;  /* point to the active Node */
        Node
*  pTempNode =  pActiveNode -> next;
      将此结点的Next指向pHeadA单链:
        pActiveNode -> next  =  pHeadA;
      更新pHeadB和pHeadA的值:
        pHeadB  =  pTempNode;
        pTempNode 
=  pHeadA;
        pHeadA 
=  pHeadA -> next;
     此时应该有三个单链:
        pHeadA被截断后剩下的部分,仍然用pHeadA来表示;
        pHeadB被截断后剩下的部分,仍然用pHeadB来表示;
        pHeadB的前段加上变化前pHeadA的头结点,这个单链最后的结点保存在pTempNode变量中;
    剩下的部分就是使用递归的方法将pHeadA和pHeadB的剩下的部分合并后连接到pTempNode的后面:
   pTempNode -> next  =  Merge(pHeadA,pHeadB);

4。如果在pHeadB单链中没有找到这样的结点:
      如果单链中结点个数小于2
            将唯一的结点连在pHeadB单链中的适当位置
      如果单链中结点个数大于(或等于2),最大结点比另外一个单链的最小结点小
            将pHeadA单链连接在pHeadB单链的前面,即pHeadA
-> ... -> pHeadB -> ...
      如果单链中结点个数大于(或等于2),最小结点比另外一个单链的最大结点大
             将pHeadA单链连接在pHeadB单链的后面,即pHeadB
-> ... -> pHeadA -> ...
     迭代过程停止

后记
1。本文充分利用了两个单链已经排好序的条件,在合并的过程中避免了大量不必要的比较和排序(不必要的操作正是算法中的"水分"所在,也正是可以优化的地方所在);同时由于单链便于插入的特点,在合并过程中大量的插入操作就显得比较轻松(简单的改变一些值即可,不需要大量的内存移动)。我虽然没有系统的分析本文算法的平均时间复杂度,但是凭感觉应该还是不错的 。同时由于算法中只使用了少量额外的变量(准确的说是三个结点指针),所以在空间复杂度上本文的算法也具有良好的表现。
2。在很多情况下,通过分析题目的字面信息就可以得到很多有用的信息。但是对于有些问题,有用的信息,甚至是解决问题的唯一思路隐藏在字面信息背后。当遇到这样的问题的时候,如果我们分析字面信息受挫的时候,不妨换换思路,或者站到一个更高的层次,或者转化到另一个切如点(甚至是对立点),说不定我们会看到一个完全不同的世界。

BTW:上面只是我个人的分析和理解,可能存在错误,甚至是本文的算法存在严重的错误,希望大家帮我指出来 。我很乐意和大家对相关问题进行深入的讨论。

 历史记录
03/31/2007   v1.0
原文的第一版
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
To merge k sorted linked lists, one approach is to repeatedly merge two of the linked lists until all k lists have been merged into one. We can use a priority queue to keep track of the minimum element across all k linked lists at any given time. Here's the code to implement this idea: ``` struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; // Custom comparator for the priority queue struct CompareNode { bool operator()(const ListNode* node1, const ListNode* node2) const { return node1->val > node2->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*, vector<ListNode*>, CompareNode> pq; for (ListNode* list : lists) { if (list) { pq.push(list); } } ListNode* dummy = new ListNode(-1); ListNode* curr = dummy; while (!pq.empty()) { ListNode* node = pq.top(); pq.pop(); curr->next = node; curr = curr->next; if (node->next) { pq.push(node->next); } } return dummy->next; } ``` We start by initializing a priority queue with all the head nodes of the k linked lists. We use a custom comparator that compares the values of two nodes and returns true if the first node's value is less than the second node's value. We then create a dummy node to serve as the head of the merged linked list, and a current node to keep track of the last node in the merged linked list. We repeatedly pop the minimum node from the priority queue and append it to the merged linked list. If the popped node has a next node, we push it onto the priority queue. Once the priority queue is empty, we return the head of the merged linked list. Note that this implementation has a time complexity of O(n log k), where n is the total number of nodes across all k linked lists, and a space complexity of O(k).
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值