堆排序
用数组去表示二叉树的层次建树的结构,就是堆
大根堆:树的顶部元素是最大的,每一个子树都是这样
完全二叉树最后一个父亲元素是 n/2-1
左孩子的下标 son = 2*dad+1
右孩子 = 左孩子 +1
得到大根堆后,将树根和最后一个元素交换,然后将除去最后一个元素外的树变成大根堆。以此类推。
编码过程中需要注意的事项在代码注释中标明
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef int ElemType;
struct SSTable
{
ElemType* elem;//存储元素的起始地址
int TableLen;//元素个数
};
void ST_Init(SSTable& ST, int len) {
ST.TableLen = len;
ST.elem = (ElemType*)malloc(sizeof(ElemType) * ST.TableLen);
int i;
srand(time(NULL));
for (i = 0; i < ST.TableLen; i++) {
ST.elem[i] = rand() % 100;
}
}
//打印函数
void ST_print(SSTable ST) {
for (int i = 0; i < ST.TableLen; i++) {
cout << ST.elem[i] << " ";
}
cout << endl;
}
//交换函数
void swap(ElemType& a, ElemType& b) {
ElemType c = a;
a = b;
b = c;
}
//调整子树
void AdjustDown(ElemType A[], int k, int len) {
int dad = k;
int son = 2 * dad + 1;//左孩子下标
while ( son <= len ){
//当son的值等于len的值的时候,说明下面已经没有孩子了
//判断里面的<= 看一下传入的len的值,有十个元素,传的是9就有等于(从0开始);传的是10就没有等于
if (son + 1 <= len && A[son] < A[son + 1]) {
//看一下有没有右孩子。比较左右孩子谁大,谁大就交换谁
//判断里面的<= 看一下传入的len的值,有十个元素,传的是9就有等于(从0开始);传的是10就没有等于
son++;
}
if (A[son] > A[dad]) {
swap(A[son], A[dad]);
//交换之后,让孩子成为父亲,继续往下遍历
dad = son;
son = 2 * dad + 1;
}
else {
break;
}
}
}
void HeapSort(ElemType A[], int len) {
int i;
//建立大根堆
for (i = len / 2; i >= 0; i--) {
AdjustDown(A, i, len);
}
//建立完大根堆后交换最后一个元素和树根
//交换完之后,逻辑上将最后一个元素移出这棵树
swap(A[0], A[len]);
for (i = len - 1; i > 0; i--) {
/*剩下元素调整为大根堆
* 循环里面i = len - 1;因为传入的长度len为9,实际有十个元素,所以是从0开始计数的,因为刚刚上面交换
* 了一遍并且找到了最大的数字并移出数组。所以现在数组的长度需要减一。
*注意交换的时候最后一个元素随着最大的数移出数组而改变。
* 但是最后一个数一直都是循环里面的i
* 所以后面交换的时候交换的是数组第0个元素和第i个元素
*/
AdjustDown(A, 0, i);
swap(A[0], A[i]);
}
}
int main()
{
SSTable ST;
ElemType A[10] = { 64,94,95,79,69,84,18,22,12,99 };
ST_Init(ST, 10);//初始化
memcpy(ST.elem, A, sizeof(A));//将数组的内容赋值给初始化的ST
ST_print(ST);
HeapSort(ST.elem, 9);//王道书零号元素不参与排序
ST_print(ST);
}