CLRS 6.5-8 原题为:请给出一个时间为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;
}
}
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;
}
}