链表的合并

PS: 将两个排序链表和将K个排序链表是同一类问题,下面主要从合并两个链表展开到合并K个链表的情况。 

合并两个排序链表

#include<iostream> 
#include <cstring>
#include <algorithm>
using namespace std; 
// 类似 归并排序
class Solution3 {
public:
        ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
        {
               if (!pHead1)
                       return pHead2;
               if (!pHead2)
                       return pHead1;
               ListNode* Head;
               ListNode* p;
               //取较小值作头结点
               if (pHead1->val <= pHead2->val) {
                       Head = pHead1;
                       pHead1 = pHead1->next;
               }
               else {
                       Head = pHead2;
                       pHead2 = pHead2->next;
               }
               //开始遍历合并
               p = Head;                      //p为合并后的链表的工作指针
               while (pHead1 && pHead2) {                       //当有一个链表到结尾时,循环结束
                       if (pHead1->val <= pHead2->val) {          //如果链表1的结点小于链表2的结点
                              p->next = pHead1;                            //取这个结点加入合并链表
                              pHead1 = pHead1->next;                 //链表1后移一位
                              p = p->next;                                      //工作指针后移一位
                       }
                       else {                                               //否则取链表2的结点
                              p->next = pHead2;
                              pHead2 = pHead2->next;
                              p = p->next;
                       }
               }
               if (pHead1 == NULL)           //链表1遍历完了
                       p->next = pHead2;         //如果链表2也遍历完了,则pHead2=NULL
               if (pHead2 == NULL)            //链表2遍历完了
                       p->next = pHead1;         ///如果链表1也遍历完了,则pHead1=NULL
               return Head;
        }
};
// 使用递归法
class Solution2 {
public:
        ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
        {
               if (pHead1 == NULL) return pHead2;
               if (pHead2 == NULL) return pHead1;
               ListNode* mergeList = NULL;
               if (pHead1->val < pHead2->val) {
                       mergeList = pHead1;
                       mergeList->next = Merge(pHead1->next, pHead2);
               }
               else {
                       mergeList = pHead2;
                       mergeList->next = Merge(pHead1, pHead2->next);
               }
               return mergeList;
        }
};

合并K个排序链表

方法一:K个链表可以看成是由若干个两两组成的链表,因此可以借鉴两个链表合并的情况。

class Solution {
public:
       // 合并两个有序链表
       ListNode* merge(ListNode* p1, ListNode* p2) {
              if (!p1) return p2;
              if (!p2) return p1;
              if (p1->val <= p2->val) {
                      p1->next = merge(p1->next, p2);
                      return p1;
              }
              else {
                      p2->next = merge(p1, p2->next);
                      return p2;
              }
       }
       ListNode* mergeKLists(vector<ListNode*>& lists) {
              if (lists.size() == 0) return nullptr;
              ListNode* head = lists[0];
              for (int i = 1; i < lists.size(); ++i) {
                      if (lists[i]) head = merge(head, lists[i]);
              }
              return head;
       }
};

方法二:类似于归并排序,分而治之

class Solution {
public:
       // 合并两个有序链表
       ListNode* merge_process(ListNode* p1, ListNode* p2) {
              if (!p1) return p2;
              if (!p2) return p1;
              if (p1->val <= p2->val) {
                      p1->next = merge(p1->next, p2);
                      return p1;
              }
              else {
                      p2->next = merge(p1, p2->next);
                      return p2;
              }
       }
       ListNode* merge(vector<ListNode*>& lists, int start, int end) {
              if (start == end) return lists[start];
              int mid = (start + end) / 2;
              ListNode* l1 = merge(lists, start, mid);
              ListNode* l2 = merge(lists, mid + 1, end);
              return merge_process(l1, l2);
       }
       ListNode* mergeKLists(vector<ListNode*>& lists) {
              if (lists.size() == 0) return nullptr;
              return merge(lists, 0, lists.size() - 1);
       }
};

方法三: 使用极小堆,维护一个size为所有节点大小的极小堆

// 使用最小堆, 时间复杂度O(Nlogk),空间复杂度O(N)
class Solution {
public:
      // 小根堆的回调函数
      struct cmp {
              bool operator()(ListNode* a, ListNode* b) {
                     return a->val > b->val;
              }
      };
     ListNode* mergeKLists(vector<ListNode*>& lists) {
             priority_queue<ListNode*, vector<ListNode*>, cmp> pri_queue;
             // 建立大小为k的小根堆
             for (auto it : lists) {
                    if (it) pri_queue.push(it);
             }
             // 可以使用哑节点/哨兵节点
             ListNode* dummy = new ListNode(-1);
             ListNode* p = dummy;
             // 开始出队
             while (!pri_queue.empty()) {
                    ListNode* top = pri_queue.top();
                    pri_queue.pop();
                    p->next = top;
                    p = top;
                    if (top->next) pri_queue.push(top->next);
             }
             return dummy->next;
     }
};

注意事项: 

1.两两合并的过程就是链表的归并排序的过程,可能存在一看就会,一写就废的现象。 

2.递归比较简洁,但是需要深刻理解这个合并的过程。