堆排序

堆排序
堆:堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
基本思想:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。(将最大元素放在末尾)
a. 将无需序列构建成一个堆,一般升序采用大顶堆,降序采用小顶堆

1.无序数组
这里写图片描述
2.从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整
这里写图片描述
3.找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换
这里写图片描述
交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6,构成大顶堆
这里写图片描述
b. 将堆顶元素与末尾元素交换,将最大元素”沉”到数组末端;
c. 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

1.将堆顶元素9和末尾元素4进行交换
这里写图片描述
2.重新调整结构,使其继续满足堆定义
这里写图片描述
3.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8
这里写图片描述
最后得到有序数组
这里写图片描述

#include <iostream>
using namespace std;
void heapfy(int A[], int len);
void buildheap(int A[], int idx, int max);

int main() {
    int A[] = { 4,6,8,5,9 };
    int len = sizeof(A) / sizeof(A[0]);
    heapfy(A, len);
    //输出结果
    for (int i = 0; i < len; ++i) {
        cout << A[i] << " ";
    }
    cout << endl;
    system("pause");
    return 0;
}

void heapfy(int A[], int len) {
    //从len / 2 - 1开始到0递减,对每一个节点执行heapfy,最后实现把最大的数字放在第0个的位置
    for (int i = len / 2 - 1; i >= 0; --i) {
        buildheap(A, i, len);
    }
    //把堆的第0个数字和第len-1个交换
    for (int i = len - 1; i >= 1; --i) {//i = 0 时只剩一个数字不需要交换
        int temp = A[i];
        A[i] = A[0];
        A[0] = temp;
        buildheap(A, 0, i);//建立下一个最大堆,这次从0开始,最大是i(i在循环中从len-1开始减小)
    }
}

void buildheap(int A[], int idx, int max) {
    int left = 2 * idx + 1;//idx的左孩子标号
    int right = left + 1;//idx的右孩子标号
    int largest = idx;//初始设为idx节点自己
    if (left < max && A[left] > A[idx])
        largest = left;//这里只记录标号,后面才交换
    //注意!下面这时候A[right]不能和idx比了,要跟largest比,因为可能在上一个if中被改变了,比如idx= 6,left= 8,right= 7
    if (right < max && A[right] > A[largest])
        largest = right;
    if (largest != idx) {//如果largest不是初始值了的话
        int temp = A[idx];
        A[idx] = A[largest];
        A[largest] = temp;
        buildheap(A, largest, max);//注意这里的递归调用
        //这里对第largest节点递归调用,因为刚交换了idx和largest的数字
        //需要保证,如果largest有子节点的话,它的子节点也遵循最大堆原则(父节点最大)
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值