算法导论6.5-8堆排序-K路合并

一、题目

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


二、步骤

step1:取每个链表的第一个元素,构造成一个含有k个元素的堆

step2:把根结点的值记入排序结果中。

step3:判断根结点所在的链表,若该链表为空,则go to step4,否则go to step5

step4:删除根结点,调整堆,go to step2

step5:把根结点替换为原根结点所在链表中的第一个元素,调整堆,go to step 2


三、代码

  1. //heap.h   
  2. #include <iostream>   
  3. #include <stdio.h>   
  4. using namespace std;  
  5.   
  6. struct node  
  7. {  
  8.     int list;  
  9.     int value;  
  10.     node *next;  
  11.     node():next(NULL){}  
  12.     node(node& A){list = A.list; value = A.value;}  
  13.     bool operator < (const node& B)const  
  14.     {  
  15.         return value<B.value;  
  16.     }  
  17.     bool operator > (const node& B)const  
  18.     {  
  19.         return value>B.value;  
  20.     }  
  21. };  
  22.   
  23. #define PARENT(i) (i)>>1   
  24. #define LEFT(i) (i)<<1   
  25. #define RIGHT(i) ((i)<<1)+1  
  26.   
  27. int length = 10;//数组中元素的个数  
  28. int heap_size = 10;//属于堆的元素个数,看到HeapSort就会明白  
  29.   
  30.   
  31. /*************************以下是堆处理函数****************************************/  
  32. //使以i结点为根结点的子树成为堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn)  
  33. //递归方法   
  34. void Max_Heapify(node *A, int i)  
  35. {  
  36.     int l = LEFT(i), r = RIGHT(i), largest;  
  37.     //选择i、i的左、i的右三个结点中值最大的结点   
  38.     if(l <= heap_size && A[l] > A[i])  
  39.         largest = l;  
  40.     else largest = i;  
  41.     if(r <= heap_size && A[r] > A[largest])  
  42.         largest = r;  
  43.     //如果根最大,已经满足堆的条件,函数停止   
  44.     //否则   
  45.     if(largest != i)  
  46.     {  
  47.         //根与值最大的结点交互   
  48.         swap(A[i], A[largest]);  
  49.         //交换可能破坏子树的堆,重新调整子树   
  50.         Max_Heapify(A, largest);  
  51.     }  
  52. }  
  53.   
  54. //建堆,时间是O(nlgn)   
  55. void Build_Max_Heap(node *A)  
  56. {  
  57.     heap_size = length;  
  58.     //从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质   
  59.     for(int i = length / 2; i >= 1; i--)  
  60.         Max_Heapify(A, i);  
  61. }  
  62.   
  63. //将元素i的关键字增加到key,要求key>=A[i]   
  64. void Heap_Increase_Key(node *A, int i, node key)  
  65. {  
  66.     if(key < A[i])  
  67.     {  
  68.         cout<<"new key is smaller than current key"<<endl;  
  69.         exit(0);  
  70.     }  
  71.     A[i] = key;  
  72.     //跟父比较,若A[PARENT(i)]<A[i],则交换   
  73.     //若运行到某个结点时A[PARENT(i)]>A[i],就跳出循环  
  74.     while(PARENT(i) > 0 && A[PARENT(i)] < A[i])  
  75.     {  
  76.         swap(A[PARENT(i)], A[i]);  
  77.         i = PARENT(i);  
  78.     }  
  79. }  
  80. //把key插入到集合A中   
  81. void Max_Heap_Insert(node *A, node key)  
  82. {  
  83.     if(heap_size == 5)  
  84.     {  
  85.         cout<<"heap is full"<<endl;  
  86.         exit(0);  
  87.     }  
  88.     heap_size++;length++;  
  89.     A[heap_size] = key;  
  90.     Heap_Increase_Key(A, heap_size, key);  
  91. }  
  92. //返回A中最大关键字,时间O(1)   
  93. node Heap_Maximum(node *A)  
  94. {  
  95.     return A[1];  
  96. }  
  97.   
  98. void Heap_Delete(node *A, int i)  
  99. {  
  100.     if(i > heap_size)  
  101.     {  
  102.         cout<<"there's no node i"<<endl;  
  103.         exit(0);  
  104.     }  
  105.     A[i] = A[heap_size];  
  106.     heap_size--;  
  107.     Max_Heapify(A, i);  
  108. }  
//heap.h
#include <iostream>
#include <stdio.h>
using namespace std;

struct node
{
	int list;
	int value;
	node *next;
	node():next(NULL){}
	node(node& A){list = A.list; value = A.value;}
	bool operator < (const node& B)const
	{
		return value<B.value;
	}
	bool operator > (const node& B)const
	{
		return value>B.value;
	}
};

#define PARENT(i) (i)>>1
#define LEFT(i) (i)<<1
#define RIGHT(i) ((i)<<1)+1

int length = 10;//数组中元素的个数
int heap_size = 10;//属于堆的元素个数,看到HeapSort就会明白


/*************************以下是堆处理函数****************************************/
//使以i结点为根结点的子树成为堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn)
//递归方法
void Max_Heapify(node *A, int i)
{
	int l = LEFT(i), r = RIGHT(i), largest;
	//选择i、i的左、i的右三个结点中值最大的结点
	if(l <= heap_size && A[l] > A[i])
		largest = l;
	else largest = i;
	if(r <= heap_size && A[r] > A[largest])
		largest = r;
	//如果根最大,已经满足堆的条件,函数停止
	//否则
	if(largest != i)
	{
		//根与值最大的结点交互
		swap(A[i], A[largest]);
		//交换可能破坏子树的堆,重新调整子树
		Max_Heapify(A, largest);
	}
}

//建堆,时间是O(nlgn)
void Build_Max_Heap(node *A)
{
	heap_size = length;
	//从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质
	for(int i = length / 2; i >= 1; i--)
		Max_Heapify(A, i);
}

//将元素i的关键字增加到key,要求key>=A[i]
void Heap_Increase_Key(node *A, int i, node key)
{
	if(key < A[i])
	{
		cout<<"new key is smaller than current key"<<endl;
		exit(0);
	}
	A[i] = key;
	//跟父比较,若A[PARENT(i)]<A[i],则交换
	//若运行到某个结点时A[PARENT(i)]>A[i],就跳出循环
	while(PARENT(i) > 0 && A[PARENT(i)] < A[i])
	{
		swap(A[PARENT(i)], A[i]);
		i = PARENT(i);
	}
}
//把key插入到集合A中
void Max_Heap_Insert(node *A, node key)
{
	if(heap_size == 5)
	{
		cout<<"heap is full"<<endl;
		exit(0);
	}
	heap_size++;length++;
	A[heap_size] = key;
	Heap_Increase_Key(A, heap_size, key);
}
//返回A中最大关键字,时间O(1)
node Heap_Maximum(node *A)
{
	return A[1];
}

void Heap_Delete(node *A, int i)
{
	if(i > heap_size)
	{
		cout<<"there's no node i"<<endl;
		exit(0);
	}
	A[i] = A[heap_size];
	heap_size--;
	Max_Heapify(A, i);
}



  1. //main.cpp   
  2. #include <iostream>   
  3. #include "Heap.h"   
  4. using namespace std;  
  5.   
  6. int main()  
  7. {  
  8.     //5个链表,每个链表的头结点放入Head中   
  9.     node *Head[5] = {0},*tail[5] = {0};  
  10.     int i, j, list, value;  
  11.     int temp;  
  12.     //构造需要合并的数据   
  13.     for(value = 50; value >0; value--)  
  14.     {  
  15.         list = rand() % 5;  
  16.         node *a = new node;  
  17.         a->list = list;  
  18.         a->value = value;  
  19.         if(Head[list] == NULL)  
  20.             Head[list] = a;  
  21.         else  
  22.             tail[list]->next = a;  
  23.         tail[list] = a;  
  24.     }  
  25.     //显示待排序数据   
  26.     cout<<"显示待排序数据"<<endl;  
  27.     for(i = 0; i < 5; i++)  
  28.     {  
  29.         cout<<i<<':'<<endl;  
  30.         node *p = Head[i];  
  31.         while(p)  
  32.         {  
  33.             cout<<p->value<<' ';  
  34.             p = p->next;  
  35.         }  
  36.         cout<<endl;  
  37.     }  
  38.     length = 0;heap_size = 0;  
  39.     int ans[55] = {0};//合并结果存放在这里  
  40.     node A[6];//堆的大小是k   
  41.     //step1:取每个链表的第一个元素,构造成一个含有k个元素的堆  
  42.     for(i = 0; i < 5; i++)  
  43.     {  
  44.         if(Head[i])  
  45.         {  
  46.             Max_Heap_Insert(A, *Head[i]);  
  47.             Head[i] = Head[i]->next;  
  48.         }  
  49.     }  
  50.     while(1)  
  51.     {  
  52.         list = A[1].list;  
  53.         //step2:把根结点的值记入排序结果中   
  54.         ans[++ans[0]] = A[1].value;  
  55.         //step3:判断根结点所在的链表,若该链表为空  
  56.         if(Head[list] == NULL)  
  57.         {  
  58.             //删除根结点,调整堆   
  59.             Heap_Delete(A, 1);  
  60.             if(heap_size == 0)  
  61.                 break;  
  62.         }  
  63.         else//若该链表不为空  
  64.         {  
  65.             //把根结点替换为原根结点所在链表中的第一个元素  
  66.             A[1] = *Head[list];  
  67.             Head[list] = Head[list]->next;  
  68.             //调整堆   
  69.             Max_Heapify(A, 1);  
  70.         }  
  71.     }  
  72.     //输出合并结果   
  73.     cout<<"输出合并结果"<<endl;  
  74.     for(i = 1; i <= ans[0];i++)  
  75.         cout<<ans[i]<<' ';  
  76.     return 0;  
  77. }  
//main.cpp
#include <iostream>
#include "Heap.h"
using namespace std;

int main()
{
	//5个链表,每个链表的头结点放入Head中
	node *Head[5] = {0},*tail[5] = {0};
	int i, j, list, value;
	int temp;
	//构造需要合并的数据
	for(value = 50; value >0; value--)
	{
		list = rand() % 5;
		node *a = new node;
		a->list = list;
		a->value = value;
		if(Head[list] == NULL)
			Head[list] = a;
		else
			tail[list]->next = a;
		tail[list] = a;
	}
	//显示待排序数据
	cout<<"显示待排序数据"<<endl;
	for(i = 0; i < 5; i++)
	{
		cout<<i<<':'<<endl;
		node *p = Head[i];
		while(p)
		{
			cout<<p->value<<' ';
			p = p->next;
		}
		cout<<endl;
	}
	length = 0;heap_size = 0;
	int ans[55] = {0};//合并结果存放在这里
	node A[6];//堆的大小是k
	//step1:取每个链表的第一个元素,构造成一个含有k个元素的堆
	for(i = 0; i < 5; i++)
	{
		if(Head[i])
		{
			Max_Heap_Insert(A, *Head[i]);
			Head[i] = Head[i]->next;
		}
	}
	while(1)
	{
		list = A[1].list;
		//step2:把根结点的值记入排序结果中
		ans[++ans[0]] = A[1].value;
		//step3:判断根结点所在的链表,若该链表为空
		if(Head[list] == NULL)
		{
			//删除根结点,调整堆
			Heap_Delete(A, 1);
			if(heap_size == 0)
				break;
		}
		else//若该链表不为空
		{
			//把根结点替换为原根结点所在链表中的第一个元素
			A[1] = *Head[list];
			Head[list] = Head[list]->next;
			//调整堆
			Max_Heapify(A, 1);
		}
	}
	//输出合并结果
	cout<<"输出合并结果"<<endl;
	for(i = 1; i <= ans[0];i++)
		cout<<ans[i]<<' ';
	return 0;
}

四、输出结果

显示待排序数据
0:
47 40 39 34 21 12
1:
50 38 36 35 31 30 24 23 19 18 9 4 3
2:
49 42 37 33 32 28 26 25 20 15 14 8
3:
44 43 27 22 17 10 7 6 2 1
4:
48 46 45 41 29 16 13 11 5
输出合并结果
50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 请按任意键继续. . .

 
转载自: http://blog.csdn.net/mishifangxiangdefeng/article/details/7668486
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值