堆排序-C++

堆排序

用数组去表示二叉树的层次建树的结构,就是

大根堆:树的顶部元素是最大的,每一个子树都是这样

完全二叉树最后一个父亲元素是 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);
}




点击下载源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会挂科i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值