排序排序的概念及其运用和选择排序

排序排序的概念及其运用和选择排序

  • 7. 排序
    • 7.1 排序的概念及其运用
    • 7.2 选择排序算法——直接选择排序
      • 选择排序基本思想:
      • 直接选择排序
        • 选择排序原理
        • 参考程序
      • 如何交换数据
      • 直接选择排序的特性总结:

7. 排序

7.1 排序的概念及其运用

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]==r[j],且r[i]r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

举个例子,同一张试卷,分数相同的情况下,谁先交卷,谁排在前面。

或者总分相同,谁的语文成绩更好,谁排在前。此时对这种特殊需求,排序算法的稳定性就很有必要。

内部排序:数据元素全部放在内存中的排序。(下文也称内排序)

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。(下文也称外排序)

例如 1 G = = 102 4 3 b y t e 1G==1024^3 byte 1G==10243byte,一个int型整数4byte,100亿( 1 0 10 10^{10} 1010)个int型整数占用空间为37G左右,针对这100亿个数据的排序已无法用常见的排序算法去操作。

排序的算法先考虑可行性,再考虑效率。

排序要掌握的点:

  1. 不同排序算法的时间复杂度和空间复杂度
  2. 排序的思想
  3. 排序的实现

排序主要学习这几种:
请添加图片描述

如果是参加算法竞赛,则只需要学习堆排序、快速排序和归并排序即可,遇到竞赛题除非有特殊需求,否则一律用库函数sort解决。

7.2 选择排序算法——直接选择排序

选择排序基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

直接选择排序

选择排序原理
  • 在元素集合array[i]array[n-1]中选择关键码最大(小)的数据元素。

  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换。

  • 在剩余的array[i]array[n-2]array[i+1]array[n-1])集合中,重复上述步骤,直到集合剩余1个元素。

排序动图示例:
请添加图片描述

参考程序

以升序排序为例。

根据原理分析,得到的未优化选择排序:

//选择排序,因为传递的是指针,要另外传递元素个数 
void selectSort(int b[],int n) {int i=0,j=0,k=0;for(i=0;i<n;i++) {k=i;//每次更新第一个(或最后一个)元素的位置 for(j=i+1;j<n;j++)if(b[j]<b[k])//遍历寻找最小值k=j;if(k!=i) {//找到的最小值没有放在第一个位置int temp=b[k];b[k]=b[i];b[i]=temp;}}
}

尝试优化:我们在每次遍历数据时,同时找到最大值和最小值的位置并分别放在开头和结尾,还能再减少一半的整体遍历次数。这个思路需要两个起到指针作用的变量分别标记开头和结尾。

这个思路很像双指针,但并不是,只是用到了双指针的思路进行优化。

在实现时我们先看一组样例:

int a[]={7,4,3,6,5,2,3};

我们发现,最大值7和开头位置重合。若按照思路进行枚举,则交换最小值到开头时,数据变化:

(7) 4 3 6 5 (2) 3  ==>  (2) 4 3 6 5 (7) 3

此时2莫名其妙的被判断成最大值和3进行交换。

(2) 4 3 6 5 (7) 3  ==>  3 4 3 6 5 (7) (2)

到这里可以看出,排序没能使数组有序。

解决方法:优化方案会进行两次数据交换,在第一次交换时判断找到的最值是否与开头、结尾重叠,重叠的话进行修正即可。

优化后的选择排序参考程序

//经优化的选择排序,每次同时选出最小的和最大的
void selectSortplus(int* a, int n) {int begin = 0, end = n - 1;//起标记作用的两个变量while (begin < end) {//能不能加等于,取决于交换数据时用的方法int maxi = begin, mini = begin;for (int i = begin; i <= end; i++) {if (a[i] > a[maxi])maxi = i;if (a[i] < a[mini])mini = i;}Swap(&a[begin], &a[mini]);if (begin == maxi)//处理begin和maxi重叠时的情况maxi = mini;Swap(&a[end], &a[maxi]);++begin;//双指针思路--end;}
}

如何交换数据

在优化的选择排序中,有提到为啥这句能不能用<=取决于交换数据的方法。

程序设计语言进行交换数据的方法有3种:

  1. 设置中间变量

这个是最基础、最常用的方法。但会额外开一个临时变量的空间。若交换的数据比较庞大的话可能需要将庞大的数据分成若干份分别进行交换。

void Swap(Datatype* a,Datatype* b){int tmp = *a;*a = *b;*b = tmp;
}
  1. 三次异或

我们知道,c语言有一个按位异或操作符^,而异或操作的真值表:
请添加图片描述

尽管按位异或是针对二进制位的操作,但如果是两个相同的数据进行异或操作,结果是0。例如:3^3==0的结果为真,因为两个3在内存中存储的二进制形式完全相同,这就使得每一个bit位进行异或时的结果都是0,得到的补码也是0,对应的真实数据自然也是0。

利用这个特点,我们也可以设计出一种不用额外申请空间的数据交换方式:

void Swap(Datatype* a,Datatype* b){Datatype aa=*a,bb=*b;//先进行演示,后进行优化//交换a、b的数据*a=aa^bb^aa;*b=aa^bb^bb;
}

其中aa^bb我们可以用另一个变量进行存储:

void Swap(Datatype* a,Datatype* b){Datatype aa=*a,bb=*b;//先进行演示,后进行优化//交换a、b的数据Datatype tmp=aa^bb;*a=tmp^aa;*b=tmp^bb;
}

我们将tmp更换成aa也没关系,因为此时bb还没发生变化,即使aa的值变成了aa^bb,我们还可以再通过aa^bb^bb的方式重新拿回aa的数据。

void Swap(Datatype* a,Datatype* b){Datatype aa=*a,bb=*b;aa=aa^bb;*b=aa^bb;*a=aa^*b;//运行到这里时,*b已经变成了*a的样子
}

第3行:此时aa存储的数据是*a^*b

第4行:此时bb还未发生改变,aa存储的数据是*a^*b,因此=右边的表达式相当于是*a^*b^*b*b已经变成了*a的样子。

第5行:*b的内容已经变成了*a的数据,而aa存储的数据依旧是*a^*b,所以*a变成了*b

到这里,其实aa和bb作为中间变量的功能已经可以被取代。所以我们得到了一个新的交换数据的方式:

void Swap(Datatype* a,Datatype* b){*a=*a^*b;*b=*a^*b;*a=*a^*b;
}

第2行:*a自己作为中间变量存储*a^*b的数据

第3行:运行完这一句后,*b存储了*a的数据

第4行:*a存储的数据依旧是*a^*b的值,而*b存储的是*a的数据,所以*a存储的数据也变成了*b的值。

例如:

void f00(){int a=3,b=4;printf("%d %d\n",a,b);a=a^b;b=a^b;a=a^b;printf("%d %d\n",a,b);
}

输出:

3 4
4 3
  1. 作差

利用数值都有大小的特点,我们可以通过作差得到两数差的部分,再将这部分填到另一部分,这样也能做到交换数据的目的:

void f01(int a,int b){a=a-b;//获得差值b=a+b;//差值填给aa=b-a;//b已变成a,砍掉差值变成b
}

这种交换方式不能用于a和b都代表同一空间的情况,否则数据会丢失(这也是为什么while(begin<end)不加等号的原因,但没多少人会用这种方式进行数据交换,加不加取决于个人爱好)。此外不清楚比较规则的自定义类型也不能用这种数据交换方式。

例如:

void f02(int x){int* a=&x,*b=&x;printf("%d\n",*a,*b);*a=*a-*b;*b=*a+*b;*a=*b-*a;printf("%d\n",*a,*b);
}

输出:

6 6
0 0

直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

  2. 时间复杂度: O ( N 2 ) O(N^2) O(N2)(两层循环)

  3. 空间复杂度: O ( 1 ) O(1) O(1)

  4. 稳定性:不稳定(要与当前的第一个和最后一个数据进行数据交换,即使是相同的数据也不知道会被移动到哪里)。

例如这个样例:[5,5,3],第一次选择最小数的3时候,不可避免的和第1个5进行交换,这时数组变成了[3,5,5]

我们还可以通过下列代码测试稳定性。只要找到值相同但次序不同的数的位置即可发现算法是否稳定。

#include<stdio.h>typedef struct Num {int x;int i;
}Num;
typedef Num DataType;void Swap(DataType* a, DataType* b) {DataType t = *a;*a = *b;*b = t;
}void selectSort(DataType b[],int n) {int i=0,j=0,k=0;for(i=0;i<n;i++) {k=i;//每次更新第一个(或最后一个)元素的位置 for(j=i+1;j<n;j++)if(b[j].x<b[k].x)//遍历寻找最小值k=j;if(k!=i) {//找到的最小值没有放在第一个位置DataType temp=b[k];b[k]=b[i];b[i]=temp;}}
}//经优化的选择排序,每次同时选出最小的和最大的
void selectSortplus(DataType* a, int n) {int begin = 0, end = n - 1;//起标记作用的两个变量while (begin < end) {//能不能加等于,取决于交换数据时用的方法int maxi = begin, mini = begin;int i=0;for (i = begin; i <= end; i++) {if (a[i].x > a[maxi].x)maxi = i;if (a[i].x < a[mini].x)mini = i;}Swap(&a[begin], &a[mini]);if (begin == maxi)//处理begin和maxi重叠时的情况maxi = mini;Swap(&a[end], &a[maxi]);++begin;//双指针思路--end;}
}void f() {srand((size_t)time(0));//随机数的种子Num a[30] = { {0,0} },b[30] = { {0,0} };int i=0;for (i = 0; i < 30; i++) {a[i].x = rand()%100+1;a[i].i = i + 1;b[i] = a[i];}for (i = 0; i < 30; i++)printf("%d %d,",a[i].x,a[i].i);printf("\n\n");selectSort(a, 30);selectSortplus(b, 30);for (i = 0; i < 30; i++)printf("%d %d,", a[i].x, a[i].i);printf("\n\n");for (i = 0; i < 30; i++)printf("%d %d,", b[i].x, b[i].i);
}int main(){f();return 0;
}

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

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

相关文章

【目标检测】用YOLOv8-Segment训练语义分割数据集(保姆级教学)

前言 这篇教程会手把手带你用 YOLOv8-Segment 搭建一个属于自己的分割任务项目。从环境配置到数据集准备&#xff0c;再到模型训练和测试&#xff0c;所有步骤都有详细说明&#xff0c;适合初学者使用。你将学会如何安装必要的软件&#xff0c;标注自己的数据&#xff0c;并使…

爬虫开发工具与环境搭建——开发工具介绍

第二章&#xff1a;爬虫开发工具与环境搭建 第一节 开发工具介绍 爬虫开发需要一些合适的工具和框架来高效地抓取网页数据。在这节中&#xff0c;我们将介绍常用的开发工具&#xff0c;帮助开发者快速搭建爬虫开发环境。 1. Python与爬虫框架选择 Python因其简洁、易学的语法…

类和对象——拷贝构造函数,赋值运算符重载(C++)

1.拷⻉构造函数 如果⼀个构造函数的第⼀个参数是自身类类型的引用&#xff0c;且任何额外的参数都有默认值&#xff0c;则此构造函数也叫做拷贝构造函数&#xff0c;也就是说拷贝构造是⼀个特殊的构造函数。 // 拷贝构造函数//d2(d1) Date(const Date& d) {_year d._yea…

高级数据结构——hash表与布隆过滤器

文章目录 hash表与布隆过滤器1. hash函数2. 选择hash函数3. 散列冲突3.1 负载因子3.2 冲突解决3. STL中的散列表 4. 布隆过滤器4.1 背景1. 应用场景2. 常见的处理场景&#xff1a; 4.2 布隆过滤器构成4.3 原理4.4 应用分析4.5 要点 5. 分布式一致性hash5.1 缓存失效问题 6. 大数…

xcode-select: error: tool ‘xcodebuild‘ requires Xcode, but active developer

打开 .sh 文件所在的终端窗口&#xff0c;执行终端命令&#xff1a;sh 文件名.sh&#xff0c;出现如下错误&#xff1a; 解决办法&#xff1a;

java中volatile 类型变量提供什么保证?能使得一个非原子操作变成原子操作吗?

大家好&#xff0c;我是锋哥。今天分享关于【java中volatile 类型变量提供什么保证&#xff1f;能使得一个非原子操作变成原子操作吗&#xff1f;】面试题。希望对大家有帮助&#xff1b; java中volatile 类型变量提供什么保证&#xff1f;能使得一个非原子操作变成原子操作吗&…

candence : 通孔焊盘、插装器件封装绘制

通孔焊盘、插装器件封装绘制 以2.54mm 2x10的 排针为例绘制封装 一、 flash 热风焊盘制作 1、新建 2、选择 flash SYMBOL&#xff0c;并设置保存路径 3、add flash 具体参数 花焊盘参数 Inner diameter 通孔直径(1.0mm) 圆形补偿值(0.4mm)1.4mm Outer diameter 通孔直径…

VSCode设置

打开设置页 VSCode打开配置页面&#xff0c;有多种方式&#xff1a; a. 点击左上角 File(文件) -> Preferences (首选项) -> Settings(设置)。 b. 使用快捷键 Ctrl ,(Windows) 或 Cmd ,(Mac)。 c. 点击左下角 Manage(管理) -> Settings(设置)。 VSCode设置页面打…

SpringMVC数据校验、数据格式化处理、国际化设置

SpringMVC数据校验、数据格式化处理、国际化设置 1.数据验证 &#xff08;1)使用JSR-303验证框架 JSR&#xff08;Java Specification Requests&#xff09;&#xff0c;意思是Java 规范提案。JSR-303是JAVA EE 6中的一项子规范&#xff0c;叫做Bean Validation。JSR 303&am…

加速 AI 创新:引入 Elastic AI 生态系统

作者&#xff1a;来自 Elastic Alyssa Fitzpatrick, Steve Kearns 生成式人工智能 (Generative AI - GenAI) 正在改变我们所熟知的商业格局。为了简化和加速开发人员构建和部署检索增强生成 (retrieval augmented generation - RAG) 应用程序的方式&#xff0c;Elastic 自豪地宣…

SpringSecurity 鉴权认证入门讲解

​ Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 ​ 一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多&#xff0c;因为相比与Sp…

# ubuntu 安装的pycharm不能输入中文的解决方法

ubuntu 安装的pycharm不能输入中文的解决方法 一、问题描述&#xff1a; 当在 ubuntu 系统中&#xff0c;安装了 pycharm&#xff08;如&#xff1a;pycharm2016, 或 pycharm2018&#xff09;,打开 pycharm 输入代码时&#xff0c;发现不能正常输入中文&#xff0c;安装的搜狗…

小白进!QMK 键盘新手入门指南

经常玩键盘的伙伴应该都知道&#xff0c;现在的键盘市场可谓是百花齐放&#xff0c;已经不是之前的单一功能产品化时代。我们可以看到很多诸如&#xff1a;机械轴键盘、磁轴键盘、光轴键盘、电感轴键盘&#xff0c;以及可能会上市的光磁轴键盘&#xff0c;更有支持屏幕的、带旋…

EXCEL 或 WPS 列下划线转驼峰

使用场景&#xff1a; 需要将下划线转驼峰&#xff0c;直接在excel或wps中第一行使用公式&#xff0c;然后快速刷整个列格式即可。全列工下划线转为格式&#xff0c;使用效果如下&#xff1a; 操作步骤&#xff1a; 第一步&#xff1a;在需要显示驼峰的一列&#xff0c;复制以…

微信小程序:vant组件库安装步骤

前言&#xff1a;在微信小程序中引用vant组件报错&#xff0c;提示路径不存在&#xff0c;这很有可能是因为没有安装构建vant组件库导致。下面是我整理的安装vant组件库的步骤: 第一步&#xff1a;安装node.js(执行完第一步请重启小程序) 具体步骤请看链接&#xff1a;node.js…

vue3【实战】切换全屏【组件封装】FullScreen.vue

效果预览 原理解析 使用 vueUse 里的 useFullscreen() 实现 代码实现 技术方案 vue3 vite UnoCSS vueUse 组件封装 src/components/FullScreen.vue <template><component:is"tag"click"toggle":class"[!isFullscreen ? i-ep:full-sc…

GPIO相关的寄存器(重要)

目录 一、GPIO相关寄存器概述 二、整体介绍 三、详细介绍 1、端口配置低寄存器&#xff08;GPIOx_CRL&#xff09;&#xff08;xA...E&#xff09; 2、端口配置高寄存器&#xff08;GPIOx_CRH&#xff09;&#xff08;xA...E&#xff09; 3、端口输入数据寄存器&#xff…

【Hadoop实训】Hive 数据操作②

延续上一篇文章&#xff0c;不懂的宝子们请看以下链接&#xff1a; 【Hadoop实训】Hive 数据操作①-CSDN博客 目录 一、Group by 语句 (1)、计算emp表每个部门的平均工资 (2)、计算emp表每个部门中每个岗位的最高工资 二、Having 语句 (1)、求每个部门的平均工资 (2)、求每个…

Vulhub漏洞复现---solr---CVE-2019-17558

漏洞描述 Apache Solr 5.0.0到Apache Solr 8.3.1容易受到通过VelocityResponseWriter执行的远程代码的攻击。Velocity模板可以通过configset ’ Velocity / 目录中的Velocity模板或作为参数提供。用户定义的configset可以包含可呈现的、潜在的恶意模板。参数提供的模板在默认情…

ADS学习笔记 5. 微带天线设计

基于ADS2023 update2 参考书籍&#xff1a;卢益锋老师《ADS射频电路设计与仿真学习笔记》 更多笔记&#xff1a;ADS学习笔记 1. 功率放大器设计ADS学习笔记 2. 低噪声放大器设计ADS学习笔记 3. 功分器设计ADS学习笔记 4. 微带分支定向耦合器设计 目录 0、设计指标 1、微带…