小白解堆排序(附代码和详细注释)

堆排序(附代码和注释)

堆排序就是使用完全二叉树的逻辑结构来对数据进行排序,理解堆排序主要理解三个部分内容

  • 什么是完全二叉树,堆在逻辑结构上是一种怎样的完全二叉树
  • 堆元素的添加
  • 堆元素的删除

什么是完全二叉树,堆在逻辑结构上是一种怎样的完全二叉树

通俗来讲,完全二叉树就是在二叉树添加结点时完全按照从左到右的顺序添加结点的二叉树。
完全二叉树

上图为完全二叉树,下图先添加右边结点所以不是
在这里插入图片描述
堆分为大根堆和小根堆,本文以小根堆为例,小根堆即二叉树中所有结点的值都小于子结点的值,大根堆则反之。
入图所示
要构造小根堆就得理解,堆元素的添加和删除过程

堆元素的添加

堆元素的添加需遵循从左到右的添加原则,添加到二叉树的最后,添加元素后,二叉树需重新构造确保每个结点的值小于子结点值。构造方式就是添加的结点a,与a的父结点值比较,如果a值小于父结点值则将a值与父节点值互换,以此类推,直到满足小根堆的条件,整个构造过程就像a结点上浮的过程。

小根堆构造过程

堆元素的删除

堆元素删除,一般遵循删除根节点,然后将小根堆的最后一个结点代替根结点,再重新构造小根堆,与堆元素的添加相反,根节点与值最小的子结点比较,如果该结点小于最小子结点,则两元素值互换,整个构造过程类似新的根结点下沉的过程。
在这里插入图片描述
由于小根堆的根结点值是整个二叉树中最小的值,所以不断取出根的值(也就是不断删除根结点,并重构堆的过程),则取出后的元素是一个从小到大的排序列。为了实现这一排序思想,将逻辑结构转换为数组的存储结构。
图片来源于网络
图片来源

逻辑结构与数据存储结构转换(采用数组存储逻辑完全二叉树):
当前i下标的父节点下标为:(i-1)/2
当前i下标的子结点下标为:2i+1和2i+2

代码实现堆排序(c++实现)

#include <iostream>
using namespace std;

/*逻辑结构与数据存储结构转换(采用数组存储逻辑完全二叉树):
当前i下标的父节点下标为:(i-1)/2
当前i下标的子结点下标为:2*i+1和2*i+2*/
void Heapfixup(int a[],int i){ //添加元素,结点上浮 
	int tem = a[i];
	int j = (i-1)/2;
	while(j >= 0 && i != 0){
		if(a[j] <= tem) break;
		
		a[i] = a[j];
		i = j;
		j = (i-1)/2;
	}
	a[i] = tem;
	
}

void Heapfixdown(int a[],int i,int n){  //删除元素,根结点下沉 
	int tem = a[i];//临时保存根节点,便于后续结点值的互换 
	int j = 2*i + 1; 
	while(i <= n && j < n){    //所有下标的序号不能大于数组限制 着重注意j<n 
		if( j+1<n && a[j+1] < a[j]) j++; //使用子结点中的最小值与父结点比较 
		if(a[j] >= tem) break; //如果父结点值小于子结点中的最小值则下沉结束 
		a[i] = a[j]; //否则,将父节点值与子结点值呼唤,父节点值下沉 
		i = j;
		j = 2*i + 1;
	}
	a[i] = tem;
}

void printall(int a[],int n){
		cout<<"\n";
		for(int i=0;i<n;i++){
		cout<<a[i]<<"\t";
	}
}
int main(){
	int a[5];
	cout<<"请输入将要排序的5个数字:"; 
	for(int i=0;i<5;i++){
		cin>>a[i];
	}
	for(int i=4;i>=0;i--){
		Heapfixup(a,i);//从数组的最后一个元素开始不断重构小根堆 
	} 
	printall(a,5);
	cout<<"\n排序结果为:"; 
	for(int i=4;i>=0;){
		int tem;
		tem = a[0];
		a[0] = a[i];
		a[i] = tem;     //将根结点与二叉树的最后一个结点值互换
		i--;
		Heapfixdown(a,0,i); //不断将根节点放在数组末尾,最后达到从小到大的排序 
	}
	printall(a,5);
} 


感谢你的阅读,如有疑问欢迎在下方评论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值