【六大排序详解】中篇 :选择排序 与 堆排序

news2024/9/25 17:15:47

选择排序 与 堆排序

选择排序

  • 选择排序 与 堆排序
    • 1 选择排序
      • 1.1 选择排序原理
      • 1.2 排序步骤
      • 1.3 代码实现
    • 2 堆排序
      • 2.1 堆排序原理
        • 2.1.1 大堆与小堆
        • 2.1.2 向上调整算法
        • 2.1.3 向下调整算法
      • 2.2 排序步骤
      • 2.3 代码实现
    • 3 时间复杂度分析
  • Thanks♪(・ω・)ノ
    • 下一篇文章见!!!

1 选择排序

1.1 选择排序原理

选择排序可以用扑克牌理解,眼睛看一遍所有牌,选择最小的放在最左边。然后略过刚才排完的那张,继续进行至扑克牌有序。这样一次一次的挑选,思路很顺畅。总结为:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
在这里插入图片描述

1.2 排序步骤

  1. 从头开始遍历数组,设置mini指向最小值下标(先指向首元素)。
  2. 遇到比a[mini]小的值,mini改变为新下标。直到遍历到结尾。
  3. 将数组首元素与mini指代元素交换位置。
  4. 从排好序的下一个元素开始,重复 1-3 步骤。
  5. 直到排序完成。
    在这里插入图片描述

1.3 代码实现

void SelectSort(int* a, int n) {
	int begin = 0;//无序部分开头
	int mini = 0;//先设置mini指向开头
  //直到begin = n ,都有序。
	while (begin<n) {
  		//从无序部分开始,选择最小值。
		for (int i = begin; i < n; i++) {
			if (a[i] < a[mini]) //如果小则下标更新。
				mini = i;
		}
		//将选择出来的最小值放置到无序部分开头。
		swap(a, begin, mini);
		begin++;//begin向后推进
		mini = begin;//mini更新
	}
}

排序功能实现,效果非常棒!
排序结果
直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

2 堆排序

2.1 堆排序原理

堆排序是一种特殊的选择排序,堆排序以二叉树为基础。选择两个子元素其一,然后逐层上升或下沉,直到有序。在认识理解堆排序之前,我们需要了解如何建堆。这里我们由于是学习堆排序,所以下面我只介绍堆的大小堆建立,向上调整算法,向下调整算法。其余堆相关知识会在另一篇文章详细介绍。

2.1.1 大堆与小堆

首先:堆 是一种特殊的树,满足以下条件即为堆,是二叉树的顺序结构。

在这里插入图片描述

二叉树内容见:二叉树解释
根据二叉树的知识,堆一定是完全二叉树(除了最后一层,其他层的节点个数都是满的,最后一层的节点都集中在左部连续位置)
堆分为大小堆
即 :堆中每一个节点的值都必须大于等于或小于等于其左右子节点的值
每个节点的值都大于等于其子树节点的堆叫“大堆“,根是所有数据的最大值
每个节点的值都小于等于其子树节点的堆叫“小堆“,根是所有数据的最小值

2.1.2 向上调整算法

我们如何把基本的数组变成大堆和小堆呢?这里就需要向上调整算法。
向上调整顾名思义,就是从尾部开始,一层一层向上调整。

以建大堆为例

  1. 从尾节点开始,如果该孩子节点大于父母节点,则向上调整(上浮)。
  2. 直到调整到合适的位置。
  3. 尾节点向前推移,继续重复 1 - 2 步骤。
  4. 直到遍历所有元素,完成建堆。
void adjustup(int* a, int child) ;
int main(){
//...
	for (int i = n - 1; i > 0; i--) {
		adjustup(a, i);//逐个遍历
	}
//...
}
//建堆


void adjustup(int* a, int child) {

	int parent = (child - 1) / 2;//根据二叉树知识取父母节点

	while (child > 0) {
		if (a[child] > a[parent]) {
			swap(a, child, parent);
			//如果该孩子节点大于父母节点,则向上调整(上浮)
		}

		child = parent;//孩子节点迭代
		parent = (child - 1) / 2;//父母节点迭代
	}

}

这样就建立了大堆。小堆原理相同,只需更改大于号和小于号。

2.1.3 向下调整算法

建立好堆之后,如何进行排序呢?这时就需要向下调整算法。首先我们要有一个共识:
排升序建大堆;排倒序建小堆。
之所以这样是因为向下调整算法的缘故,下面我们来看向下调整算法,之后解释原因。
以排升序为例

  1. 首先头元素与尾元素交换位置。
  2. 然后从头开始向下调整,如果父母节点大于孩子节点中较大的,则交换。
  3. 调整完成后,尾向前推进。继续重复 1 - 2 步骤。
  4. 直到遍历所有元素。
void adjustdown(int* a, int parent,int size);
int main(){
//...
	int end = n - 1;
	while (end > 0) {
		swap(a, end, 0);
		adjustdown(a,0,end);
		end--;
	}
//...
}
void adjustdown(int* a, int parent,int size) {
	int child = parent * 2 + 1;
	while (child < size) {
		if (child + 1 < size && a[child + 1] > a[child]) {
			child++;
		}

		if (a[child] > a[parent]) {
			swap(a, child, parent);
			
		}
		parent = child;
		child = parent * 2 + 1;
	}
	
}

这样遍历一遍向下调整就可以完成排序。我们理解向下调整算法之后就可以发现
**排升序建大堆;排倒序建小堆。**是非常巧妙的,
以排升序为例,每次放在交换到首元素 的都是最小值(最大值),然后向下调整,把它放到该放在的位置上。

2.2 排序步骤

我们理解上述两种算法之后,就可以非常顺畅理解堆排序。

  1. 向上调整建堆
  2. 向下调整排序
    在这里插入图片描述
    理解向上调整算法和向下调整算法之后,堆排序就迎刃而解。

2.3 代码实现

void adjustup(int* a, int child) {

	int parent = (child - 1) / 2;

	while (child > 0) {
		if (a[child] > a[parent]) {
			swap(a, child, parent);
		}

		child = parent;
		parent = (child - 1) / 2;
	}

}

void adjustdown(int* a, int parent,int size) {
	int child = parent * 2 + 1;
	while (child < size) {
		if (child + 1 < size && a[child + 1] > a[child]) {
			child++;
		}

		if (a[child] > a[parent]) {
			swap(a, child, parent);
			
		}
		parent = child;
		child = parent * 2 + 1;
	}
	
}
void HeapSort(int* a, int n) {
	assert(a);

	for (int i = n - 1; i > 0; i--) {
		adjustup(a, i);//逐个遍历
	}
	int end = n - 1;
	while (end > 0) {
		swap(a, end, 0);
		adjustdown(a,0,end);
		end--;
	}
}

这里我们是可以进一步优化的,因为向上调整算法可以有向下调整算法来代替。
算法优化就交给你完成了。

3 时间复杂度分析

让我们和之前的排序算法来比较一下。依然是10万组数据,让我们看一下运行时间。(以冒泡排序为对照)
在这里插入图片描述

显然选择排序和插入排序是一个级别,堆排序和希尔排序都非常快速。
我们再来比较一下希尔排序与堆排序。100万组数据
在这里插入图片描述
这里希尔貌似更快,但其实希尔排序与堆排序是一个量级,甚至在更多数据下,堆排序会更优。

Thanks♪(・ω・)ノ

下一篇文章见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1334640.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧交通应用钡铼技术无线工业边缘路由网关R10A

智慧交通应用中&#xff0c;无线工业边缘路由网关扮演着至关重要的角色。在这方面&#xff0c;钡铼技术无线工业边缘路由网关R10A被广泛应用于交通管理系统中&#xff0c;它具备一路RS485、一路WAN、一路LAN、4G和WiFi等功能。本文将详细介绍R10A的参数以及在智慧交通领域的应用…

蓝桥题库(X图形(矩阵))

题目剖析&#xff1a; 简单来说就是找到一个由字母组成的X图形&#xff0c;且每个边上的字母都与中心点的字母相同 算法设计&#xff1a; 1.从中心点向外辐射&#xff0c;每找到一个这样的图形&#xff0c;则次数加一 2.从最外层向中心点靠拢&#xff0c;如果中间遇到不满足…

Unity Shader Early-Z技术

Unity Shader Early-Z技术 Early-Z技术Unity渲染顺序总结Alpha Test&#xff08;Discard&#xff09;在移动平台消耗较大的原因 Early-Z技术 传统的渲染管线中&#xff0c;ZTest其实是在Blending阶段&#xff0c;这时候进行深度测试&#xff0c;所有对象的像素着色器都会计算一…

外汇天眼:交易高手!是这样炼成的!

在外汇市场中&#xff0c;那些总是赚的“盆满钵满”的外汇投资高手实在是让人羡慕不已&#xff0c;他们能够准确预测市场走势&#xff0c;抓住每一个交易机会&#xff0c;实现高收益&#xff0c;很多投资新手因此也想入市&#xff0c;但即使是这样&#xff0c;还是有很多新手对…

关于标准那些事——第五篇 两仪

国家标准的编写&#xff0c;对于标准的名称和结构&#xff0c;很多人往往是不那么在意的&#xff0c;但这恰恰也是非常重要的点&#xff0c;今天就给大家分享一下这太极所生的“两仪”。我会用最精简的文字概括出核心内容&#xff0c;让大家有一个初步且完整的概念&#xff0c;…

规律生活指南:数据可视化助你游刃有余

随着信息时代的到来&#xff0c;我们生活在一个数据海洋中&#xff0c;每天都会面对大量的信息和数字。在这个信息过载的时代&#xff0c;如何从杂乱的数据中找到规律&#xff0c;让生活更加有序成为了一项挑战。而数据可视化作为一种强大的工具&#xff0c;不仅能够帮助我们理…

算法基础之数字三角形

数字三角形 核心思想&#xff1a;线性dp 集合的定义为 f[i][j] –> 到i j点的最大距离 从下往上传值 父节点f[i][j] max(f[i1][j] , f[i1][j1]) w[i][j] 初始化最后一层 f w #include <bits/stdc.h>using namespace std;const int N 510;int w[N][N],f[N][…

ACM模式Java输入输出模板

输入输出练习网站&#xff1a;https://kamacoder.com/ Java读写模板 Scanner 方式一&#xff1a;Scanner&#xff08;效率不高&#xff09; public class Main {public static void main(String[] args) {// 第一个方式ScannerScanner sc new Scanner(System.in);String s …

SpringMVC核心处理流程梳理

1、处理流程图展示 当我拿出这张图&#xff0c;阁下又该如何应对呢&#xff1f;执行流程是不是一目了然了。 2、DispatcherServlet&#xff1a;中央处理器或者中央调度器 下图官方的解释应该最完善了。 3、SpringMVC三大核心组件 HandlerMapping 处理器映射器&#xff0c;…

vue使用ElementUI搭建精美页面入门

ElementUI简直是css学得不好的同学的福音 ElementUI官网&#xff1a; Element - The worlds most popular Vue UI framework 安装 在vue文件下&#xff0c;用这个命令去安装Element UI。 npm i element-ui -S step1\先切换到vue的目录下去&#xff0c;注意这里面的WARN不是…

Ubuntu系统如何安装SVN服务端并通过客户端无公网ip实现远程访问?

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

Unity重写Inspector简化分组配置文件

Unity重写Inspector简化分组配置文件 重写Inspector创建分组管理配置文件创建修改参数参数对应类工程在我的资源中名为CreateConfig&#xff0c;免费下载 重写Inspector创建分组管理配置文件 创建 修改参数 参数对应类 using UnityEngine;public class GameConfig : Scriptab…

CSS样式斜切边

html部分 <div class"rectangle"></div> 样式一&#xff1a; .rectangle { width: 251px; height: 75px; background: linear-gradient(-135deg, transparent 52px, #ffffff 0) top right; background-size: 100% 100%; background-repeat: no-repeat; b…

Mybatis的关联查询(association和collection)

关联查询 实体间的关系&#xff08;拥有 has、属于 belong&#xff09; OneToOne&#xff1a;一对一关系&#xff08;account ←→ user&#xff09; OneToMany&#xff1a;一对多关系&#xff08;user ←→ account&#xff09; ManyToMany&#xff1a;多对多关系&#xff0…

windows中python3创建虚拟环境

当我们在创建一个python项目时&#xff0c;经常需要安装一堆库&#xff0c;然后转到另一个项目&#xff0c;却发现依赖冲突了&#xff0c;人都麻了。所以创建虚拟环境就是解决这个大麻烦的。 什么是虚拟环境&#xff1f; 虚拟环境是Python的一个工具&#xff0c;支持我们在一…

kubectl 删除 namespace 卡住

执行删除 namespace 后处于卡顿已经3个多小时了 按照网上的 --force 和 --force --grace-period0 都没用&#xff0c;还是删不掉 在外面看到了一篇文章&#xff0c;试了之后有效&#xff0c;原文地址 懒得跳转也可以看我这个&#xff0c;一样的 删除步骤 首先将 namespace 的信…

50 个具有挑战性的概率问题 [01/50]:袜子抽屉

一、说明 我最近对与概率有关的问题产生了兴趣。我偶然读到了弗雷德里克莫斯特勒&#xff08;Frederick Mosteller&#xff09;的《概率论中的五十个具有挑战性的问题与解决方案》&#xff08;Fifty Challenge Problems in Probability with Solutions&#xff09;一书。我认为…

如何使用Docker部署Dashy并无公网ip远程访问管理界面

文章目录 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 简介 Dashy 是一个开源的自托管的导航页配置服务&#xff0c;具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一些网站聚合起来放在一起&#xff0c;形成自己的导航…

调用哪些API可以实现批量抓取京东平台商品详情数据?

前段有客户提出需求&#xff0c;说需要批量抓取京东的商品数据&#xff0c;需要我们将代码对接好。实现批量抓取商品数据&#xff0c;主要是用到关键字搜索接口item_search和获取商品详情数据item_get、获取店铺所有商品item_search_shop。 item_search-按关键字搜索商品 请求…

C++ Qt开发:Charts折线图绑定事件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍QCharts折线图的常用方法及灵活运用。 在上一…