学到了堆排序,并将重要代码都注释了,有需要的可以白嫖,欢迎纠正。
堆排序的基本思想:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次大值。如此反复执行,便能得到一个有序序列了
步骤:
a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
#include<iostream>
using namespace std;
void swap(int &num1, int &num2)
{
int temp = num1;
num1 = num2;
num2 = temp;
}
/***堆调整函数***/
/*已知arr[]中记录的关键字除arr[s]之外都满足大顶堆的定义*/
/*本函数一次只能调整arr[s],使得arr[]成为一个大顶堆*/
void HeapAdjust(int arr[], int s, int high) // s 要被调整的下标, high 参与排序的最后一个结点的下标
{
int temp;
temp = arr[s]; //先将要调整的关键字保存
int j = 2 * s + 1; //s的左孩子下标
while (j <= high)
{
if (j < high&&arr[j] < arr[j + 1]) // 如果有两个孩子(j<high),且左孩子小于右孩子,
j++; // 就j+1,使j 就指向右孩子,最终目的找出孩子结点最大值的那个,
if (temp < arr[j]) //将要调整的结点与其“每一代子孙结点的最大值(arr[j])”比较
{
arr[s] = arr[j]; //如果要调整的值比孩子的值小,
s = j; //更新s值,保存调整值要插入的位置下标——arr[s] = temp;
j = 2 * s + 1; //移向下一代,继续比较,找到适合插入调整值的位置
}
else //要调整的值大于孩子结点,直接返回。
break;
}
arr[s] = temp; //插入
}
/****堆排序 首结点下标为0!!!***/
void HeapSort(int arr[], int n)
{
for (int i = n / 2 - 1; i >= 0; i--) // n/2-1为最后一个非叶结点,循环到0,调整所有的非叶结点
{
HeapAdjust(arr, i, n - 1); //第一个下标为0,所以最后一个下标为n-1
}
for (int i = n - 1; i > 0; i--)//for循环是与堆顶数据交换,所以去掉堆顶下标i=0
{
swap(arr[i], arr[0]); //将堆顶记录与当前未经排序子序列的最后一个数据交换
HeapAdjust(arr, 0, i - 1); //交换完后,对新的堆顶记录进行调整,调整范围要除去新产生的排序序列,如第一次除去arr[n-1](找出的最大值)
}
}
int main()
{
int arr[8] = { 1,6,7,9,3,4,0,8 };
HeapSort(arr, 8);
for (int i = 0; i < 8; i++)
{
cout << arr[i] << " ";
}
return 0;
}