最小堆k路归并

转至:http://www.cnblogs.com/shuaiwhu/archive/2011/03/20/2065077.html

CLRS 6.5-9 原题为:请给出一个时间为O(nlgk)、用来将k个已排序链表合并为一个排序链表的算法。此处n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)。


      算法思想:
1. 从k个链表中取出每个链表的第一个元素,组成一个大小为k的数组arr,然后将数组arr转换为最小堆,那么arr[0]就为最小元素了
2. 取出arr[0],将其放到新的链表中,然后将arr[0]元素在原链表中的下一个元素补到arr[0]处,即arr[0].next,如果 arr[0].next为空,即它所在的链表的元素已经取完了,那么将堆的最后一个元素补到arr[0]处,堆的大小自动减一,循环n-k次即可。

      为了方便粘贴,把.h和.cpp都弄在一起,首先是两个类List和Node,然后就是两个关于最小堆操作的函数,代码有点长,但是一点都不难,因为你肯定看过最大堆的操作,那么最小堆就大同小异了:

#include <iostream>
using namespace std;


class Node
{
public:
  Node* next;
      int data;


  Node();
  Node(int d);


      operator Node() const;
      //只需用到"<"号
  bool operator < (const Node& temp);
};


class List
{
public:
  Node* first;


  List();
      void insert(int d);
};


//修正i的位置,在此处已经假设i的子节点都是堆
void min_heapify(Node*&a, int i, int length);
//建立数组的堆
void build_min_heap(Node*&a, int length);


int main()
{
      int K =5;
  List* list_one  =new List();
  List* list_two =new List();
  List* list_three =new List();
  List* list_four =new List();
  List* list_five =new List();
    
      for(int i =0; i <5; i++)
  {
    list_one->insert(i);
    list_two->insert(i -3);
    list_three->insert(i +5);
    list_four->insert(2*i);
    list_five->insert(i -10);
  }


  Node* arr =new Node[K];
  arr[0] =*(list_one->first);
  arr[1] =*(list_two->first);
  arr[2] =*(list_three->first);
  arr[3] =*(list_four->first);
  arr[4] =*(list_five->first);


      //先对这K个排序
  build_min_heap(arr, K);


  List* list =new List();


      //每次取arr[0]的下一个Node,如果Node为空的话,
      //则把堆末尾的元素补到arr[0],由于有--K,所以堆的大小减一
  while(K >0)
  {
    list->insert(arr[0].data);
            if(arr[0].next != NULL)
      arr[0] =*(arr[0].next);
            else 
      arr[0] = arr[--K];
    min_heapify(arr, 0, K);
  }
  Node* begin = list->first;


      while(begin != NULL)
  {
    cout<<begin->data<<endl;
    begin = begin->next;
  }
      return 0;
}


void min_heapify(Node*&a, int i, int length)
{
      int smallest = i;


      while(smallest <= length -1)
  {
            int left =2*smallest +1;
            int right =2*smallest +2;
            int temp = smallest;
            if(left <= length -1&& a[left] < a[smallest])
    {
      smallest = left;
    }


            if(right <= length -1&& a[right] < a[smallest])
    {
      smallest = right;
    }


            if(smallest != temp)
    {
      Node exchange = a[smallest];
      a[smallest] = a[temp];
      a[temp] = exchange;
    }
            else
                  break;
  }
}


void build_min_heap(Node*&a, int length)
{
      int root = length/2-1;


      for(int i = root; i >=0; i--)
    min_heapify(a, i, length);
}


Node::Node()
{
  next = NULL;
}


Node::Node(int d)
{
  data = d;
  next = NULL;
}


Node::operator Node() const
{
      return data;
}


bool Node::operator < (const Node& temp)
{
      if(data < temp.data)
            return true;
      return false;
}


List::List()
{
  first = NULL;
}


void List::insert(int d)
{
  Node* node = new Node(d);


      if(first == NULL)
    first = node;
      else
  {
    Node* temp = first->next;
    Node* prev = first;
            while(temp != NULL)
    {
      prev = temp;
      temp = temp->next;
    }
    prev->next = node;
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值