堆排序
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).相对于快速排序来说,这是堆排序的最大优点。此外,堆排序仅仅需要一个记录大小供交换用的辅助存储空间。
代码如下:
注:堆排序不是一种稳定排序。
堆排序方法对记录数较稍等文件并不值得提倡,但对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; }