数据结构之选择排序

目录

直接选择排序

选择排序的时间复杂度

堆排序

向上调整算法

向下调整算法

向上调整算法建立堆

向下调整算法建立堆

堆排序整体代码

堆排序的时间复杂度


直接选择排序

在之前讲插入排序时,我们讲了这样的一个应用场景,我们在斗地主摸牌时,会一张一张的摸,然后采用插入排序的方法将手中的牌变得有序,但是还有一种摸牌的方式,就是将所有的牌先发到手里,然后在所有牌中找出最大的和最小的放到牌的两端,重复上述步骤,依次挑选最大的和最小的放到两端,直到将手中的牌排好序,这其实就是生活中直接选择排序的应用。在数据结构中,直接选择排序又是怎样实现的呢?

 直接插入排序的思想:先进行单趟的排序,找出最小和最大的两个数,并且将最小的数和最大的数依次交换到数组的头部和尾部,然后重复单趟排序的操作,直到将数组整个排有序。

直接选择排序图示如下:

直接选择排序代码如下:

void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}void SelectSort(int* a, int size)
{int begin = 0, end = size - 1;while (begin < end){int max = begin, min = begin;//先进行单趟排序,遍历每个元素,找出最大最小的两个数的位置for (int i = begin+1; i <= end; i++)//这里让begin+1的原因是,自己没有必要和自己比较{if (a[i] < a[min]){min = i;}if (a[i] > a[max]){max = i;}}
//单趟排序找到最大和最小的元素之后,将最小的值与begin位置上的元素交换,将最大的值与end位置上的元素交换Swap(&a[begin], &a[min]);
//当begin位置上的元素就是最大的元素时,将最小的元素和begin位置上的元素交换之后,最大的元素的位置就会发生改变
//max位置上的元素并不是最大的元素,min位置上的元素就是最大的元素,所以我们得把此时的min赋值给max,然后再做交换if (max == begin)max = min;Swap(&a[end], &a[max]);//让begin++,end--,再进行下一趟排序,找出最大的和最小的放置在两端begin++;end--;}
}
int main()
{int arr[] = {100,99,27,92,99,220,28,78,18,8 };SelectSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;
}

 大家有没有注意到这样一段代码:

我们进行了一趟排序,找出了最大的元素和最小的元素,直接将最大的元素和最小的元素分别与end位置和begin位置上的元素交换即可,为什么还要把进行一次判断呢?

因为我们要排除一种极端的情况:

看下图:

其实对于上述情况,我们还有一种解决办法,如果begin位置的元素就是最大的元素,我们可以先让大的元素和end位置上的元素进行交换,然后再让最小的元素和begin位置上的元素进行交换,但是,上述情况只是在先交换最小元素的基础上修正的代码,大家可以根据自己情况进行选择。

选择排序的时间复杂度

时间复杂度:最好最坏都是O(N^2)

因为即使数组已经有序了编译器是无法分辨的,还是得每次找出最大的数和最小的数,第一趟比较每个元素比较2次所以总共比较2*(size-1)次,第二趟比较比较2*(size-3)次,所以其复杂度为等差数列的前n项求和,不管最好最坏,选择排序都是这个执行流程,所以直接选择排序的时间复杂度为O(N^2)。

稳定性:不稳定

堆排序

堆排序其实最重要的就是两个算法,向上调整和向下调整算法,先通过向上调整和向下调整算法建立堆,然后建好堆之后,再次采用向下调整算法调整元素的位置,最终实现排序。 

以下给出具体的代码,对代码不理解的小伙伴可以去看堆那几期的内容。点击这里 and 这里

向上调整算法

void AdjustUp(int* a, int child)
{assert(a);int parent = (child - 1) / 2;while (child > 0){//因为是大堆,所以父亲节点的值大于孩子节点的值,如果父亲节点的值小于孩子节点的值,就需要交换if (a[parent] < a[child]){int tmp = a[parent];a[parent] = a[child];a[child] = tmp;child = parent;parent = (child - 1) / 2;}else{break;}}
}

向下调整算法

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){//因为是大堆,向下调整时,为了避免从堆顶继续调整,所以必须选最大的孩子作为childif (child + 1 < n && a[child + 1] > a[child]){++child;}//因为是大堆,所以,如果父亲小于孩子,需要进行交换if (a[parent] < a[child]){int tmp = a[parent];a[parent] = a[child];a[child] = tmp;parent = child;child = parent * 2 + 1;}else{break;}}
}

向上调整算法建立堆

for (int i = 1; i < n; i++){AdjustUp(a, i);}

向上调整算法建堆,这里的i表示的就是向上调整算法里的child,对某个元素采用向上调整算法的前提是这个元素的前面的所有元素必须构成大堆或者小堆,对于一个数组而言,如果数组只有一个元素,我们就可以将这个数组看成大堆或者小堆,所以我们可以单独将第一个元素看成是一个大堆或者小堆,所以就可以从第二个元素要开始进行向上调整算法,然后后面的依此逻辑,直到将整个数组建成堆,与其说是建堆,不如说是调堆。

向下调整算法建立堆

	for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}

向下调整算法建堆,这里的i可以看做向下调整算法里的parent,一个元素要采用向下调整算法,必须保证当前元素所在节点的左右子树都必须为大堆或者小堆。叶子节点没有左右子树,所以不能对叶子节点采用向下调整算法, 但是可以对最后一个叶子节点的父亲节点进行向下调整算法,因为最后一个叶子节点的父亲节点的左右子树都是叶子节点,叶子节点可以看成是一个大堆或者小堆,所以我们要从最后一个叶子节点的父亲节点开始进行向下调整算法。

堆排序整体代码

void HeapSort(int* a,int n)
{for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}for (int end = n - 1; end >= 0; end--){HPDataType tmp = a[0];a[0] = a[end];a[end] = tmp;AdjustDown(a, end, 0);}
}
int main()
{int arr[] = { 1000,999,27,9,99,20,28,78,18,88 };HeapSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;
}

运行截图:

堆排序的时间复杂度

时间复杂度:O(N*logN)

稳定性:不稳定

注意:虽然向上调整算法和向下调整算法都可以建立堆,但是我们建议使用向下调整算法建立堆,因为向上调整算法的时间复杂度为O(N*logN),而向下调整算法建立堆的时间复杂度为O(N)。

以上便是选择排序的所有内容。

本期的内容到此结束。^_^

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

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

相关文章

银行数据分析进阶篇:银行外呼业务数据分析与客户精准营销优化研究

上次和大家分享了“信用卡全生命周期分析”的案例&#xff0c;不少朋友都有正向的反馈&#xff0c;今天继续和大家分享我之前看到的银行数据分析的案例&#xff0c;这个案例结构清晰&#xff0c;内容详细&#xff0c;相信朋友们能很快掌握&#xff01; 01 需求痛点 我们先来了…

计算机网络:应用层(一)

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

LLM之RAG理论(一)| CoN:腾讯提出笔记链(CHAIN-OF-NOTE)来提高检索增强模型(RAG)的透明度

论文地址&#xff1a;https://arxiv.org/pdf/2311.09210.pdf 检索增强语言模型&#xff08;RALM&#xff09;已成为自然语言处理中一种强大的新范式。通过将大型预训练语言模型与外部知识检索相结合&#xff0c;RALM可以减少事实错误和幻觉&#xff0c;同时注入最新知识。然而&…

【Spring教程17】Spring框架实战:实例详解解读AOP通知类型的使用

欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》&#xff0c;本文的上一篇为《AOP配置管理中AOP切入点表…

现代雷达车载应用——第2章 汽车雷达系统原理 2.2节

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.2 汽车雷达架构 从顶层来看&#xff0c;基本的汽车雷达由发射器&#xff0c;接收器和天线组成。图2.2给出了一种简化的单通道连续波雷达结构[2]。这…

[湖湘杯 2021 final]MultistaeAgency

文章目录 题目是给了源码&#xff0c;我们先来看web的main.go package mainimport ("bytes""crypto/md5""encoding/json""fmt""io""io/ioutil""log""math/rand""net/http""o…

存储成本降71%,怪兽充电历史库迁移OceanBase

怪兽充电作为共享充电宝第一股&#xff0c;业务增长迅速&#xff0c;以至于业务架构不停地增加组件。在验证 OceanBase 可以简化架构并带来更大的业务价值后&#xff0c;首次尝试在历史库中使用 OceanBase 替代 MySQL&#xff0c;存储成本降低 71%。本文为怪兽充电运维架构部王…

odoo自定义提示性校验

背景: 在odoo16的原生的代码里&#xff0c;可以给按钮添加一个 confirm属性&#xff0c;从而达到 提示性校验的效果。 问题&#xff1a; 这个属性加了之后一定会弹出提示性校验的对话框&#xff0c;于是如何根据我们的实际业务&#xff0c;从后端返回提示性信息&#xff0c;…

ubuntu 20.04.6 server 服务器 下载与安装(配置静态IP)

下载地址&#xff1a;https://releases.ubuntu.com/20.04.6/ubuntu-20.04.6-live-server-amd64.iso 第一步&#xff1a; 准备U盘&#xff0c;使用软碟通将下载好的镜像写入到U盘中 软碟通网址&#xff1a;https://www.cn.ultraiso.net/xiazai.html 点击&#xff1a;文件 ->…

matlab 最小二乘拟合空间直线(方法三)

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示四、相关链接博客长期更新,GPT与爬虫自重,你也未必能爬到最新版本。 一、算法原理 1、算法过程 空间直线的点向式方程为:

远程服务器QEMU+Ubuntu+GRUB+VNC最佳实践

远程服务器QEMUUbuntuGRUBVNC最佳实践 1. 准备2. QEMU启动安装Ubuntu2.1 服务器端2.2 本地端 3. 从服务器终端控制虚拟机GRUB与虚拟机终端 这段时间参与大量内核切换测试工作&#xff0c;实体机需要硬件自检太过笨重&#xff0c;因此主要通过QEMU验证正确性。有一个很大的问题是…

OpenSSL 编程指南

目录 前言初始化SSL库创建SSL 上下文接口(SSL_CTX)安装证书和私钥加载证书(客户端/服务端证书)加载私钥/公钥加载CA证书设置对端证书验证例1 SSL服务端安装证书例2 客户端安装证书创建和安装SSL结构建立TCP/IP连接客户端创建socket服务端创建连接创建SSL结构中的BIOSSL握手服务…

Reinfocement Learning 学习笔记PartⅠ

文章目录 Reinfocement Learning一、基本概念二、贝尔曼公式&#xff08;bellman equation&#xff09;2.1 为什么return重要2.2 state value function的定义2.3 贝尔曼公式推导2.4 如何求解贝尔曼公式2.5 Action value的定义 三、贝尔曼最优公式&#xff08;bellman optimalit…

1841_在Windows上安装emacs irony server

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1841_在Windows上安装emacs irony server emacs有很多优点&#xff0c;配置出来不仅用着顺手而且有一定的成就感。但是&#xff0c;对于大多数人来说或…

将单体应用程序迁移到微服务

多年来&#xff0c;我处理过多个单体应用&#xff0c;并将其中一些迁移到了微服务架构。我打算写下我所学到的东西以及我从经验中用到的策略&#xff0c;以实现成功的迁移。在这篇文章中&#xff0c;我将以AWS为例&#xff0c;但基本原则保持不变&#xff0c;可用于任何类型的基…

【动态规划精选题目】1、斐波那契数列模型

此动态规划系列主要讲解大约10个系列【后续持续更新】 本篇讲解入门级&#xff1a;斐波那契模型&#xff0c;会在讲解题目同时给出AC代码 为什么叫斐波那契数列模型&#xff1f;因为本篇4道题的状态转移方程都跟斐波那契递推方程差不多&#xff0c;但这点不重要&#xff0c;请往…

【C++】:set和map

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

补充回答一些关于枚举类型的问题

补充回答一些关于枚举类型的问题 1.枚举类型在什么时候使用 枚举类型在以下情况下特别有用&#xff1a; 有限的离散值集合&#xff1a; 当变量的取值只有有限且离散的几个选项时&#xff0c;使用枚举类型能够提高代码的可读性。例如&#xff0c;星期几、月份、颜色等。 enum W…

Uncaught ReferenceError: jQuery is not defined解决方法

当我在写java的Maven项目时&#xff0c;出现了这样的一个报错信息&#xff1a; 我一直找代码&#xff0c;抓包&#xff0c;调试&#xff0c;比对代码 jQuery未定义就是指JS的导包没有导进来&#xff01;&#xff01;&#xff01;&#xff01; 导进来就运行正常啦

Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 is available

记录一次服务调用中的错误 背景&#xff1a;我使用了nacos2.x的版本&#xff0c;同时在同一台服务器的三个docker容器中部署了nacos1、2、3&#xff0c;并将它们连接到了同一个docker网络 错误&#xff1a;Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 …