数据结构:选择排序

简单选择排序

选择排序是一种简单直观的排序算法。首先在未排序序列中找到最大(最小)的元素,存放到排序学列的其实位置,然后在剩余的未排序的元素中寻找最小(最大)元素,存放在已排序序列的后面

算法步骤

  1. 在未排序序列中找到最大(小)元素,存放在排序序列的起始位置
  2. 再从剩余的未排序序列中找到最大(小)元素,然后存放在已排序序列的后面
  3. 重复上诉第二步骤,直至排序结束

算法理解

例如对无序表{56,12,80,91,20}采用简单选择排序算法进行排序,具体过程为:

  • 第一次遍历时,从下标为 1 的位置即 56 开始,找出关键字值最小的记录 12,同下标为 0 的关键字 56 交换位置:

    在这里插入图片描述

  • 第二次遍历时,从下标为 2 的位置即 56 开始,找出最小值 20,同下标为 2 的关键字 56 互换位置:

    在这里插入图片描述

  • 第三次遍历时,从下标为 3 的位置即 80 开始,找出最小值 56,同下标为 3 的关键字 80 互换位置:

    在这里插入图片描述

  • 第四次遍历时,从下标为 4 的位置即 91 开始,找出最小是 80,同下标为 4 的关键字 91 互换位置:

    在这里插入图片描述

  • 到此简单选择排序算法完成,无序表变为有序表。

代码实现

#include "iostream"
using namespace std;#define MAX 9
//单个记录的结构体
typedef struct {int key;
}SqNote;
//记录表的结构体
typedef struct {SqNote r[MAX];int length;
}SqList;
//交换两个记录的位置
void swap(SqNote *a,SqNote *b){int key=a->key;a->key=b->key;b->key=key;
}
//查找表中关键字的最小值
int SelectMinKey(SqList *L,int i){int min=i;//从下标为 i+1 开始,一直遍历至最后一个关键字,找到最小值所在的位置while (i+1<L->length) {if (L->r[min].key>L->r[i+1].key) {min=i+1;}i++;}return min;
}
//简单选择排序算法实现函数
void SelectSort(SqList * L){for (int i=0; i<L->length; i++) {//查找第 i 的位置所要放置的最小值的位置int j=SelectMinKey(L,i);//如果 j 和 i 不相等,说明最小值不在下标为 i 的位置,需要交换if (i!=j) {swap(&(L->r[i]),&(L->r[j]));}}
}
int main() {SqList *L = new SqList;L->length=8;L->r[0].key=49;L->r[1].key=38;L->r[2].key=65;L->r[3].key=97;L->r[4].key=76;L->r[5].key=13;L->r[6].key=27;L->r[7].key=49;SelectSort(L);for (int i=0; i<L->length; i++) {cout << L->r[i].key << " ";}return 0;
}

代码实现

13 27 38 49 49 65 76 97

树形选择排序

树形选择排序(又称“锦标赛排序”),是一种按照锦标赛的思想进行选择排序的方法,即所有记录采取两两分组,筛选出较小(较大)的值;然后从筛选出的较小(较大)值中再两两分组选出更小(更大)值,依次类推,直到最后选出一个最小(最大)值。同样可以采用此方式筛选出次小(次大)值等

算法理解

整个排序的过程,可以用一棵具有 n 个叶子结点的完全二叉树表示。例如对无序表{49,38,65,97,76,13,27,49}采用树形选择的方式排序,过程如下:

  • 首先将无序表中的记录采用两两分组,筛选出各组中的较小值(如图 1 中的(a)过程);然后将筛选出的较小值两两分组,筛选出更小的值,以此类推(如图 1 中的(b)(c)过程),最终整棵树的根结点中的关键字即为最小关键字:

在这里插入图片描述

图 1 树形选择排序(一)

  • 筛选出关键字 13 之后,继续重复此方式找到剩余记录中的最小值,此时由于关键字 13 已经筛选完成,需要将关键字 13 改为“最大值”,继续重复此过程,如图 2 所示: 图 2 树形选择排序(二)

    在这里插入图片描述

通过不断地重复此过程,可依次筛选出从小到大的所有关键字。该算法的时间复杂度为O(nlogn),同简单选择排序相比,该算法减少了不同记录之间的比较次数,但是程序运行所需要的空间较多。

代码实现

#include "iostream"
using namespace std;
#define N 8
void TreeSelectionSort(int *mData)
{int MinValue = 0;int tree[N * 4]; // 树的大小int max, maxIndex, treeSize;int i, n = N, baseSize = 1;while (baseSize < n)baseSize *= 2;treeSize = baseSize * 2 - 1;for (i = 0; i < n; i++) {//将要排的数字填到树上tree[treeSize - i] = mData[i];}for (; i < baseSize; i++) {//其余的地方都填上最小值tree[treeSize - i] = MinValue;}// 构造一棵树,大的值向上构造for (i = treeSize; i > 1; i -= 2){tree[i / 2] = (tree[i] > tree[i - 1] ? tree[i] : tree[i - 1]);}n -= 1;while (n != -1){max = tree[1];        //树顶为最大值mData[n--] = max;     //从大到小倒着贴到原数组上maxIndex = treeSize;  //最大值下标while (tree[maxIndex] != max) {maxIndex--;}//找最大值下标tree[maxIndex] = MinValue;while (maxIndex > 1) {if (maxIndex % 2 == 0) {tree[maxIndex / 2] = (tree[maxIndex] > tree[maxIndex + 1] ? tree[maxIndex] : tree[maxIndex + 1]);}else {tree[maxIndex / 2] = (tree[maxIndex] > tree[maxIndex - 1] ? tree[maxIndex] : tree[maxIndex - 1]);}maxIndex /= 2;}}
}
int main()
{int a[N] = {49,38,65,97,76,13,27,49};TreeSelectionSort(a);for (int i = 0; i < N; i++) {cout << a[i] << " ";}return 0;
}

运行结果

13 27 38 49 49 65 76 97

堆排序

堆排序 ( H e a p s o r t ) (Heapsort) (Heapsort)是指利用堆来实现的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。堆排序的平均时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

在这里插入图片描述

算法思想

了解了堆的基本性质之后,我们就可以看堆排序的基本思想。

  1. 将未排序的序列构造成大(或者小)顶堆,根据堆的性质我们可以找到序列中的最大(或者最小)值
  2. 把堆首和堆尾互换,并把堆的大小减 1 1 1
  3. 重复上面的步骤,直到堆的大小为 1 1 1

在这里插入图片描述

在这里插入图片描述

代码实现

#include "iostream"
using namespace std;
#define MAX 9
//单个记录的结构体
typedef struct {int key;
}SqNote;
//记录表的结构体
typedef struct {SqNote r[MAX];int length;
}SqList;
//将以 r[s]为根结点的子树构成堆,堆中每个根结点的值都比其孩子结点的值大
void HeapAdjust(SqList * H,int s,int m){SqNote rc=H->r[s];//先对操作位置上的结点数据进行保存,放置后序移动元素丢失。//对于第 s 个结点,筛选一直到叶子结点结束for (int j=2*s; j<=m; j*=2) {//找到值最大的孩子结点if (j+1<m && (H->r[j].key<H->r[j+1].key)) {j++;}//如果当前结点比最大的孩子结点的值还大,则不需要对此结点进行筛选,直接略过if (!(rc.key<H->r[j].key)) {break;}//如果当前结点的值比孩子结点中最大的值小,则将最大的值移至该结点,由于 rc 记录着该结点的值,所以该结点的值不会丢失H->r[s]=H->r[j];s=j;//s相当于指针的作用,指向其孩子结点,继续进行筛选}H->r[s]=rc;//最终需将rc的值添加到正确的位置
}
//交换两个记录的位置
void swap(SqNote *a,SqNote *b){int key=a->key;a->key=b->key;b->key=key;
}
void HeapSort(SqList *H){//构建堆的过程for (int i=H->length/2; i>0; i--) {//对于有孩子结点的根结点进行筛选HeapAdjust(H, i, H->length);}//通过不断地筛选出最大值,同时不断地进行筛选剩余元素for (int i=H->length; i>1; i--) {//交换过程,即为将选出的最大值进行保存大表的最后,同时用最后位置上的元素进行替换,为下一次筛选做准备swap(&(H->r[1]), &(H->r[i]));//进行筛选次最大值的工作HeapAdjust(H, 1, i-1);}
}int main() {SqList *L = new SqList ;L->length=8;L->r[1].key=49;L->r[2].key=38;L->r[3].key=65;L->r[4].key=97;L->r[5].key=76;L->r[6].key=13;L->r[7].key=27;L->r[8].key=49;HeapSort(L);for (int i=1; i<=L->length; i++) {cout << L->r[i].key << " ";}return 0;
}

运行结果

13 27 38 49 49 65 76 97

注意:堆排序相对于树形选择排序,其只需要一个用于记录交换(rc)的辅助存储空间,比树形选择排序的运行空间更小。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

福利!百度Workshop实战课,即刻搭建AI原生应用!| IDCF

你是否希望掌握大模型开发的秘诀&#xff1f;你是否渴望得到实践操作的机会&#xff1f;如果你的心中充满热情和期待&#xff0c;那么&#xff0c;WAVE SUMMIT 2023特别设置的Workshop将会是你的知识启航站&#xff01; 本次Workshop专注于AI开发与大模型应用&#xff0c;邀请…

岛屿的最大面积(力扣)递归 JAVA

给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0&#xff08;代表水&#xff09;包围着。 岛屿的面积是岛上值为 1 的…

CSS实现左侧固定,右侧自适应(5种方法)

<div class"father"><!-- 左右div不能调换顺序来写 --><div class"left">固定宽度区</div><div class"right">自适应区</div> </div> 一、利用左侧浮动float右侧margin-left /* 利用浮动floatmargin…

java+springboot+mysql智能社区管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的社区住户综合管理系统&#xff0c;系统包含超级管理员、管理员、住户角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;住户管理&#xff1b;房屋管理&#xff08;楼栋、房屋&#xff…

【npm run dev报错】无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。

1.winX键&#xff0c;使用管理员身份运行power shell 2.输入命令&#xff1a;set-executionpolicy remotesigned 3.输入”Y“,回车&#xff0c;问题解决。 文章来源&#xff1a;无法加载文件 C:\Program Files\nodejs\npm.ps1&#xff0c;因为在此系统上禁止运行脚本。 - 前…

Spring(三):Spring中Bean的生命周期和作用域

前言 在 Spring 中&#xff0c;那些组成应用程序的主体及由 Spring IOC 容器所管理的对象&#xff0c;被称之为 bean。简单地讲&#xff0c;bean 就是由 IOC 容器初始化、装配及管理的对象&#xff0c;除此之外&#xff0c;bean 就与应用程序中的其他对象没有什么区别了。而 b…

ASEMI快恢复二极管APT80DQ20BG怎么检查好坏

编辑-Z 二极管APT80DQ20BG是一种高压快恢复二极管&#xff0c;常用于电源和电能质量控制等领域。如果您的二极管出现故障或需要进行维修&#xff0c;以下是一些可能的解决方案。 首先&#xff0c;确保您已经断开了电源&#xff0c;并且具备基本的电子维修知识和技能。如果您不…

【Git】 git push origin master Everything up-to-date报错

hello&#xff0c;我是索奇&#xff0c;可以叫我小奇 git push 出错&#xff1f;显示 Everything up-to-date 那么看看你是否提交了message 下面是提交的简单流程 git add . git commit -m "message" git push origin master 大多数伙伴是没写git commit -m "…

springboot 基础

巩固基础&#xff0c;砥砺前行 。 只有不断重复&#xff0c;才能做到超越自己。 能坚持把简单的事情做到极致&#xff0c;也是不容易的。 SpringBoot JavaEE 简介 JavaEE的局限性&#xff1a; 1、过于复杂&#xff0c;JavaEE正对的是复杂的分布式企业应用&#xff0c;然而现实…

Ajax 笔记(一)—— Ajax 入门

笔记目录 1. Ajax 入门1.1 Ajax 概念1.2 axios 使用1.2.1 URL1.2.2 URL 查询参数1.2.3 小案例-查询地区列表1.2.4 常用请求方法和数据提交1.2.5 错误处理 1.3 HTTP 协议1.3.1 请求报文1.3.2 响应报文 1.4 接口文档1.5 案例1.5.1 用户登录&#xff08;主要业务&#xff09;1.5.2…

二、编写第一个 Spring MVC 程序

文章目录 一、编写第一个 Spring MVC 程序 一、编写第一个 Spring MVC 程序 创建 maven 项目&#xff0c;以此项目为父项目&#xff0c;在父项目的 pom.xml 中导入相关依赖 <dependencies><dependency><groupId>junit</groupId><artifactId>…

Spring Gateway+Security+OAuth2+RBAC 实现SSO统一认证平台

背景&#xff1a;新项目准备用SSO来整合之前多个项目的登录和权限&#xff0c;同时引入网关来做后续的服务限流之类的操作&#xff0c;所以搭建了下面这个系统雏形。 关键词&#xff1a;Spring Gateway, Spring Security, JWT, OAuth2, Nacos, Redis, Danymic datasource, Jav…