zoukankan      html  css  js  c++  java
  • 链表的合并

    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.递归比较简洁,但是需要深刻理解这个合并的过程。 

  • 相关阅读:
    windows下安装git
    使用forever运行nodejs应用
    在Sublime Text 2 中使用Git插件连接GitHub
    一个向导功能JS库
    GitHub window 提交失败的问题
    jquery.shapeshift网格插件支持动画效果
    类似bootstrap的UI库FlatUI
    timus_1006
    timus_1692
    系统引导加载器的简单实现
  • 原文地址:https://www.cnblogs.com/E-Dreamer-Blogs/p/12915400.html
Copyright © 2011-2022 走看看