排序之堆排序详解
堆排序思路:
1、将数据存在数组的1~n的编号中
2、根据元素的个数算出满二叉树的高度,记录为k
3、从第k-1层的每个节点开始处理,将以每个节点为根节点的子树变成大顶堆
(这里使用exchange()函数,该函数将在该节点、左右子女节点中找出值最大的节点,用flags记
录其编号,将j节点的值交换为最大值,交换之后再进行堆调整,即为递归调用exchange()函数)
4、对初始堆进行堆排序,将根节点的值换到末尾,每交换一次,剩余的元素进行堆调整,保证其为大顶堆
堆排序分析:
堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗
费在建初始堆和调整建新堆时进行的反复“筛选”上。堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对
于快速排序来说,这是堆排序的最大优点。此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。
#include<iostream> #include<cmath> #include<algorithm> using namespace std; int a[100]; void sort1(int *a, int n); int main() { int n; while(cin >> n) { for(int i = 1; i <= n; i++) cin >> a[i]; sort1(a, n); for(int i = 1; i <= n; i++) cout <<" " << a[i]; cout << endl; } } void exchange(int *a, int j, int num) {//将树中以j为顶点的子树变成大顶堆 int flags = j; if(2 * j <= num && a[2 * j] > a[flags]) { flags = 2 * j; } if(2 * j + 1 <= num && a[2 * j + 1] > a[flags]) { flags = 2 * j + 1; } if(j != flags) { int temp = a[j]; a[j] = a[flags]; a[flags] = temp; exchange(a, flags, num); } } void sort1(int *a, int n) { /*先将其变成大顶堆*/ int k; for(int i = 0; ; i++) {//将其转换成二叉树需要多少层 if(n >= pow(2, i) && n < pow(2, i + 1)) { k = i + 1; break; } } for(int i = k - 1; i >= 1; i--) {//从底层开始,使得非叶子节点的值大于其左右子女节点 for(int j = pow(2, i - 1); j < pow(2, i); j++) { exchange(a, j, pow(2, k) - 1); } } int num = n; for(int i = 1; i < n; i++) {//进行堆排序 int temp = a[1]; a[1] = a[n - i + 1]; a[n - i + 1] = temp; num--; exchange(a, 1, num); } }
浙公网安备 33010602011771号