第三章:查找与排序(下)----------- 3.16堆的概念及堆排序思路

本文深入解析了堆的概念,包括二叉堆的定义及其两种形态:大顶堆和小顶堆。详细阐述了堆排序的实现思路,包括堆化过程和按序输出元素的步骤,并提供了完整的伪代码和C++实现代码,帮助读者理解堆排序的原理和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆的概念及堆排序思路:

二叉堆是完全二叉树,或者近似完全二叉树。

二叉堆满足两个特性:

---1、父节点的键值总是大于或等于(小于或等于)任何一个节点的键值;

---2、每个节点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

任何节点的值都大于其子节点的值------大顶堆

任何节点的值都小于其子节点的值------小顶堆

 堆排序:

1、堆化,反向调整使得每个子树都是大顶或者小顶堆;

2、按序输出元素:把堆顶和堆末元素对调,然后调整堆顶元素。

伪代码: 

MakeMinHeap(A){
	n=A.length;
	for i from n/2-1 down to 0{
		MinHeapFixDown(A,i);
	}
}


/*
①、先看有没有左右孩子; 
②、找到左右孩子中较小的那个; 
③、调整(交换或者不交换); 
④、递归地向下调整。 
*/

MinHeapFixDown(A,i,n){
	//找到左右孩子
	left=2*i+1;
	right=2*i+2; 
	//左孩子已经越界,i就是叶子节点	
	if(left>=n){
		return;
	}
	min=left;
	if(right>=n){
		min=left;
	}
	else{
		if(A[right]<A[left]){
			min=right;
		}
	}
	//min指向了左右孩子中较小的那个 
	
	//如果A[i] 比两个孩子都要小,不用调整
	if(A[i]<=A[min]){
		return;
	} 
	
	//否则,找到两个孩子中较小的,和i交换
	temp=A[i];
	A[i]=A[min];
	A[min]=temp;
	
	//小孩子那个位置的值发生了变化,i变更为小孩子那个位置,递调整
	MinHeapFixDown(A,min,n);
}

 

//sort函数:
sort(A){
	//先对A进行堆化
	MakeMinHeap(A);
	for(int x=n-1;x>=0;x--)
		//把堆顶,0号元素和最后一个元素对调
		swap(A,0,x);
  		//缩小堆的范围,对堆顶元素进行向下调整 
  		MinHeapFixDown(A,0,x-1);
} 

代码:

#include<iostream>
using namespace std;
/**
*思路:首先要知道大顶堆和小顶堆,数组就是一个堆,每个i节点的左右孩子是2i+1和2i+2 
*      有了堆,将其堆化:从n/2-1个元素开始向下修复,将每个节点修复为小(大)顶堆 
*      修复完成后,数组具有小(大)顶堆的性质 
*      按序输出:小顶堆可以对数组逆序排列,每次交换堆顶和末尾元素,对栈顶进行向下修复 
*
*时间复杂度:堆化:一半的元素修复,修复是单分支的,所以整体堆化为nlgn。(PS:常数因子较大)
*排序:n个元素都要取出,因此调整为n次,每次调整修复同上是lgn的,整体为nlgn 
*空间复杂度:不需要开辟辅助空间 
*原址排序 
* 稳定性:不稳定 
*/
void MinHeapFixDown(int A[],int i,int n); 

void makeMinHeap(int A[],int length){
	int n=length;
	for(int i=n/2-1;i>=0;i--){
		MinHeapFixDown(A,i,n);
	}
} 

//向下调整函数 
void MinHeapFixDown(int A[],int i,int n){
	//找到左右孩子
	int left=2*i+1;
	int right=2*i+2;
	//左孩子已经越界,i就是叶子节点
	if(left>=n){
		return;
	} 
	 int min=left;
	 if(right>=n){
	 	min=left;
	 }
	 else{
	 	if(A[right]<A[left]){
	 		min=right;
	 	}
	 }
	 //min指向了左右孩子中较小的那个
	 
	 //如果A[i]比两个孩子都要小,不用调整
	 if(A[i]<A[min]){
	 	return;
	 } 
	 //否则,找到两个孩子中较小的,和i交换
	 int temp=A[i];
	 A[i]=A[min];
	 A[min]=temp;
	 
	 //小孩子那个位置的值发生了变化,i变更为小孩子的那个位置,递归调整
	 MinHeapFixDown(A,min,n);	 
}

//排序函数
void sort(int A[],int length){
	//先对A进行堆化
	makeMinHeap(A,length);
	for(int x=length-1;x>=0;x--){
		//把堆顶,0号元素和最后一个元素对调		
		swap(A[0],A[x]);
		//缩小堆的范围,对堆顶元素进行向下调整 
		MinHeapFixDown(A,0,x);
	}
} 

int main(){
	int arr[]={6,2,5,8,2,1,9,5,6};
	int len= 9;
	
	sort(arr,len);
	for(int i=0;i<len;i++){
		cout<<arr[i]<<" ";
	}
	return 0;
} 

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值