您的位置:首页 > 其它

堆排序

2012-02-22 18:22 134 查看
参考文章有很多,推荐:http://www.wutianqi.com/?p=1820

注:堆排序不是一种稳定排序。

堆排序方法对记录数较稍等文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上。对深度为k的堆,筛选算法中进行的关键字比较次数之多为2(k-1)次,则在建含n个元素,深度为h的堆时,总共进行的关键字比较次数不超过4n。又,n个节点的完全二叉树的深度为lgn+1,则调整建新堆时调用heapadjust过程n-1次,总共进行的比较次数不超过O(nlogn).相对于快速排序来说,这是堆排序的最大优点。此外,堆排序仅仅需要一个记录大小供交换用的辅助存储空间。

代码如下:

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;

const int N = 10;
int arr
;

int parent(int i)	{	return i / 2;	} //父节点
int left(int i)	{	return 2 * i;	} //左子节点
int right(int i)	{	return 2 * i + 1;	} //右子节点

void heapadjust(int i, int n)
{
	int l, r, largest;
	l = left(i), r = right(i);
	if(l <= n && arr[l] > arr[i])
		largest = l;
	else
		largest = i;
	if(r <= n && arr[r] > arr[largest])
		largest = r;
	if(largest != i)
	{
		swap(arr[i], arr[largest]);
		heapadjust(largest, n); 
		/*
		交换后子部分可能不满足堆性质,所以递归调整。
		堆:对任意一棵树的任意一个非叶子节点,该节点值应该大于等于(或小于)左右子节点的数据结构.
		若满足大于等于,则为大顶堆;反之为小顶堆
		*/
	}
}

/*
初始调用buildheap将arr[1..n]变成最大堆
因为数组最大元素在arr[1],则可以通过将arr[1]与a
互换达到正确位置
现在新的根元素破坏了最大堆的性质,所以调用heapadjust调整,
使arr[1..n-1]成为最大堆,arr[1]又是arr[1..n-1]中的最大元素,
将arr[1]与arr[n-1]互换达到正确位置。
反复调用heapadjust(1, i - 1),使整个数组成从小到大排序。
*/
void buildheap(int n) //自底向上是因为要使最大元素升至堆顶
{
	for(int i = n / 2; i > 0; --i)
		heapadjust(i, n);
}

/*
交换只是破坏了以a[1]为根的二叉树最大堆性质,它的左右子二叉树还是具备最大堆性质。
这也是为何在build_maxheap时需要遍历n/2到1的结点才能构成最大堆,而这里只需要堆化arr[1]即可。
*/
void heap_sort(int n)
{
	buildheap(n);
	for(int i = n; i > 1; --i) //n-1次之后排序完成
	{
		swap(arr[1], arr[i]);
		heapadjust(1, i - 1);
	}
}

int main()
{
	for(int i = 1; i <= 10; ++i)
		scanf("%d", &arr[i]);
	heap_sort(10);
	for(int i = 1; i <= 10; ++i)
		cout<<arr[i]<<" ";
	cout<<endl;
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: