选择排序之堆排序

本文详细介绍了Python和C++实现的堆排序,包括选择排序的原理,堆数据结构,大根堆和小根堆的概念,以及如何通过调整堆来完成排序。提供了C++代码示例并分析了算法的空间和时间复杂度,指出堆排序的不稳定性特点。
摘要由CSDN通过智能技术生成

前言

本篇文章记录了Python与C++的堆排序实现与讲解

以下是本篇文章正文内容,下面案例可供参考

一、选择排序是什么?

选择排序:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列 ,主要分为"简单选择排序"和"堆排序".

二、什么是堆排序?

堆排序是指利用堆这种数据结构所设计的一种排序算法,每一趟将堆顶元素加入有序子序列(与待排序序列中的最后一个元素位置进行交换)
堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。”

  1. 若满足:L(i)≥L(2i)且L(i)≥L(2i+1) (1≤i≤n/2) --称为大根堆(大顶堆)
  2. 若满足:L(i)≤L(2i)且L(i)≤L(2i+1) (1≤i≤n/2) --称为小根堆(小顶堆)
  3. 完全二叉树中,根≥左、右那么就是一个大根堆
  4. 完全二叉树中,根≤左、右那么就是一个小根堆
    在这里插入图片描述

三、算法思想

3.1 建立大根堆

给定一个初始序列,需要先构造一个大根堆
在这里插入图片描述
思路:把所有非终端节点都检查一遍,是否满足大根堆要求,如果不满足,则进行调整,非终端节点为L[1…n/2]的值,从后往前进行检查当前节点i是否满足根≥左、右孩子,若不满足,将当前节点与更大的孩子互换位置,具体看代码注释。

  • i的左孩子 —2i
  • i的右孩子 —2i+1
  • i的父节点 —[i/2]

期间元素互换破坏了下一级的堆,则采用相同的方法,继续往下调整(期间小元素不断下坠)

3.2 基于大根堆排序

每一趟将堆顶元素加入子序序列(与待排序序列中最后一个元素交换位置),并将待排序序列再次调整为大根堆(小元素不断下坠的过程).
基于大根堆排序会获得一个递增的序列

四、动态演示

图片来自菜鸟编程

五、代码示例

5.1.C++代码示例

void HeapAdjust(int A[],int k,int len){
	/************************************************* 
	Function:       // BuildMaxHeap
	Description:    // 建立大根堆
	Calls:          // HeapAdjust;
	Input:          // A[]-被排序数组 
	                // n  -数组长度
	Output:         // None
	Return:         // None 
	*************************************************/  
    A[0]=A[k];						// A[0]暂存子树的根节点
    for (int i=2*k; i <= len; i*=2) // 以k节点不断向下寻找较大节点
    {
       if (i<len && A[i] < A[i+1])	// 判断左右子树谁大
       {
           i++;						// 当右子树大于左子树时i++,获取右子树的i值
       }
       if (A[0]>=A[i])				// 判断当前的根节点是否大于左右子树中的最大值
       {
           break;					// 筛选结束
       }
       else{   
           A[k]=A[i];				// 将最大的A[i]替换k节点
           k=i;						// 修改k节点的值,便于继续向下筛选
       } 
    }
    A[k] =A[0];						// 将筛选到的节点值,放到最终位置
}



void BuildMaxHeap(int A[],int len){
	/************************************************* 
	Function:       // BuildMaxHeap
	Description:    // 建立大根堆,时间复杂度为O(n)
	Calls:          // HeapAdjust;
	Input:          // A[]-被排序数组 
	                // n  -数组长度
	Output:         // None
	Return:         // None 
	*************************************************/  
    for(int k=len/2;k>0;k--){       // 从后往前调整所有非叶子节点
            HeapAdjust(A,k,len);    // 小元素下坠的过程  
    }
}

void swap(int &a,int &b){
    int temp;					    // 用于交换的临时变量
    temp=a;
    a=b;
    b=temp;
};

void HeapSort(int A[],int len){
	/************************************************* 
	Function:       // HeapSort
	Description:    // 对数组进行堆排序
	Calls:          // swap; BuildMaxHeap; HeapAdjust;
	Input:          // A[]-被排序数组 
	                // n  -数组长度
	Output:         // None
	Return:         // None 
	Others:         // 堆排序 
	*************************************************/  
    BuildMaxHeap(A,len);            // 第一次建立大根堆
    for (int i = len; i >1; i--)    // n-1一次交换与建堆过程
    {
        swap(A[1],A[i]);            // 堆顶元素与堆底元素交换
        HeapAdjust(A,1,i-1);        // 把剩余待排序的元素整理成大根堆
    }
}

5.2.Python代码示例

与C++一致,不再赘述。

六、性能分析

6.1 空间复杂度

空间复杂度=O(1)

6.2 时间复杂度

6.2.1 最坏时间复杂度

建堆时间复杂度=O(n)
排序的时间复杂度=O(n)+ n l o g 2 n nlog_2n nlog2n= n l o g 2 n nlog_2n nlog2n

6.4 稳定性

堆排序是一个不稳定的排序算法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值