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;
}
}