数据结构七大常见的排序

数据结构七大常见的排序

  • 常见排序算法分类
  • 1.插入排序
  • 2.希尔排序(缩小增量排序)
  • 3.选择排序
  • 4.堆排序
  • 5.冒泡排序
  • 6.快速排序
  • 7.归并排序

常见排序算法分类

在这里插入图片描述

1.插入排序

基本思想:把待排序的数组按大小逐个插入到一个已经排好序的有序序列中,直到所有的数据插入完为止,得到一个新的有序序列 。
动图解析:
在这里插入图片描述

代码实现思路:
定义一个临时变量tmp来遍历待排数组,定义一个end作为有序数组的最后一个下标,然后end遍历有序数组。在排序中有以下几种情况:
1.最初开始的时候第一趟排序tmp直接从第二个数据开始遍历即可。
在这里插入图片描述
2.tmp<a[end]
在这里插入图片描述
3.tmp>a[end]
在这里插入图片描述
代码实现:

void InsertSort(int* a, int n)//插入排序 最好为O(N) O(N2)
{//思路:把数组中一个一个的插入,然后进行比较,把它们放到自己的位置for (int i = 1; i < n; i++){int end = i - 1;//end为控制数组的下标,使他放在temp的前一个int temp = a[i];//一趟插入一个数组,如果temp比a[end]小就放在a[end]左边,如果temp比a[end]大的话就放在,a[end]的右边while (end >= 0){if (temp < a[end])//如果temp小于a[end],那么tempd肯定插入到a[end],之前,那么就让a[end]向后移动一位//接下来就拿temp和前面的比较,看是否小于a[end]前面的数{a[end + 1] = a[end];end--;}else {break;//如果temp>a[end]的话就跳出循环,将temp放在a[end]后面,插入的精髓就在于此temp永远在a[end]的后面}}a[end + 1] = temp;//这种写法temp大于或小于a[end]两种情况都符合,temp放在左(小)右(大)边都符合}
}

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

2.希尔排序(缩小增量排序)

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有数据分成个gap组,所有距离为gap的数据分在同一组内,并对每一组内的数据进行排序,单趟排序的思路和直接插入排序一样。然后取重复上述分组和排序的工作。当到达gap=1时,所有数据在同一组内排序,gap=1是也就相当于直接插入排序。
在这里插入图片描述

代码实现:

void ShellSort(int* a, int n)//希尔排序
{int gap = n;//gap在这里是一个不断变化的值while (gap > 1){gap = gap / 3 + 1;//保证gap最后一次为1,当gap等于1的时候相当于简单插入排序,就可以直接排序出来了for (int i = 0; i < n - gap; i++){int end = i;int temp = a[end + gap];//将数组分为gap组,当gap较大的时候,也就是第一循环gap为n/3+1,将数组分成gap(大约n/3)组,那么一组就有3个数据,// 最差的情况while循环也只需要1+2次,外循环n,所以gap较大的时候的时间复杂度为O(N)//当gap较小的时候,即gap为1的时候,这时候就是插入排序,但是因为gap越小数组就越接近有序,//所以这时候的时间复杂度为O(N)//所以希尔排序的时间复杂度的量级为 logN*N   大约为n^1.3while (end >= 0){if (temp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = temp;}}
}

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就
    会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的
    希尔排序的时间复杂度都不固定:
    在这里插入图片描述
    在这里插入图片描述
  4. 稳定性:不稳定

3.选择排序

基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据排完 。我们实现的是单趟排序中选出最大值和最小值,分别放在数组的最右边和最左边。
动图实现的是将数组中最小的放在最左边:
在这里插入图片描述
代码实现:

void SelectSort(int* a, int n)//选择排序(升序)   最坏为O(N2) 最好O(N2)
{int left = 0;int right = n - 1;while (left < right){//一趟选出一个最大和最小的值然后放在数组的两边int mini = left;//最小数的下标int maxi = left;//最大数的下标for (int i = left+1; i <= right; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[left], &a[mini]);//最小的放在左边if (maxi == left)//如果刚好最大值再最左边,则会导致最大值交换到mini下标的位置{maxi = mini;}Swap(&a[right], &a[maxi]);left++;right--;}
}

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

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

4.堆排序

升序堆排序的一般思路就是将给定的一组数据放在堆的数据结构当中去,然后进行不断被的取堆顶元素放在数组当中,不断地pop(删除)。但是这种方法太麻烦了,自己还要手写一个堆的数据结构以及一些接口函数,还要创建数组等,显然不是最优解。
接上文的写的两种调整方式,向上调整和向下调整。 详细见数据结构二叉树顺序结构——堆的实现
思路:
①可以用向上调整或者向下对原数组进行调整,也就是建一个大堆(排升序大堆后面讲为啥)
②接下来利用堆删除的原理,将堆顶的数据和数组最后一个交换(也就是将堆顶和堆尾的数据进行交换),然后就相当于最大的数放在了最后一个位置,所以最后一个位置的数据确定了,接下来对剩下的数据进行向下调整,再重复以上操作。
在这里插入图片描述

ps:排升序建大堆而不是小堆的原因,反证思路来看,若建小堆的话,最小的数据在第一个,第一个数据确定了,但是剩下的数据很暖再重新调整成为一个新的小堆的数据结构,所以排升序建小堆很难实现。

向上调整和向下调整都可以完成建堆的操作,但是他们的时间复杂度有所不同,接下来讲一下他们的取舍。
向上调整建堆(时间复杂度:O(N * logN) )

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

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):
在这里插入图片描述

向下调整建堆(时间复杂度:O(N) )

for (int i = (n - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);//a是堆的数组,n是防止数组越界的数组数据个数,i是开始向下调整的位置}

向下调整建堆得思路:从第一个非叶子结点开始从数组得后面向前面一个一个进行调整
在这里插入图片描述

复杂度证明:
在这里插入图片描述

看到这里很容易发现向下调整方法建堆得时间复杂度更加合适
代码实现:


void AdjustDown(int* a, int parent, int n)//向下调整
{int child = parent * 2 + 1;while (child < n)//这里child会先越界到达临界点,所以不用判断parent{//默认child是左右孩子中较大的值if (child + 1 < n && a[child] < a[child + 1]){child = child + 1;}if (a[parent] < a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;//符合堆的性质则跳出循环}}
}// 对数组进行堆排序
void HeapSort(int* a, int n)
{//思路:向上调整方法建堆建堆//>这里排升序要建大堆,因为建小堆的话,接下来排升序第一个数据好处理,//但是剩下的数据重新排成堆的话关系全都乱了//所以这时候建大堆,和删除的思路一样,首先交换堆顶和堆尾,这时候最大的数据放到了最后一个位置//然后将前面n-1个数据看成新的堆进行向下调整,然后再找次大的数放在倒数第二的位置//建堆有两种方式 向上调整建堆和向下调整建堆,时间复杂度分别为O(N*logN)和O(N)//向上调整建堆 建堆时间复杂度 O(N*logN)/*for (int i = 1; i < n; i++){AdjustUp(a, i);}*///向下调整建堆  时间复杂度为O(N)//向下调整的条件是调整节点的左右子树都为大堆或者小堆//所以从下边开始进行向下调整(大堆),这时候大的数会慢慢上浮,最先调整的位置不能是叶子节点,那样会重复很多操作//应该从最后一个父亲节点开始进行向下调整 最后一个父亲节点的下标为 (n-1)/2,然后按数组下标的顺序递减进行调整for (int i = (n - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);//a是堆的数组,n是防止数组越界的数组数据个数,i是开始向下调整的位置}while (--n)  //排序的时间复杂度为O(N*logN){//此处为--n的原因:一共有n个数据,循环一次确定一个数据的位置,循环n-1次之后就可以确定n-1个数据的位置,// 前面已经确定了n-1个位置,最后一个数据的位置也已经确定,所以当n=0的时候的那一次循环可以不需要进行就可以// //此时n已经自减1,所以此时n就为堆尾数据,且n为下一个新堆的数据个数,所以后面向下调整直接传参nSwap(&a[0], &a[n]);//交换堆顶和堆尾的数据AdjustDown(a, n, 0);//n为新堆的数据个数}//总结:堆排序的时间复杂度为O(N*logN),因为堆排序有两个步骤①建堆②排序//建堆向上调整建堆的时间复杂度为O(N*logN),向下调整建堆的时间复杂度为O(N),相对较快,//但是排序的时间复杂度都为O(N*logN),所以决定了堆排序的时间复杂度为O(N*logN)。
}

堆排序的特性总结:

  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

5.冒泡排序

基本思路:两两数据相比,大的元素向后移,也就是前一个数据大于后一个数据就交换,一趟能保证最大的数据放在数组的最右边。
在这里插入图片描述
代码实现:

void BUbbleSort(int* a, int n)//冒泡排序   最坏O(N2)  最好O(N)
{//这里起始位置如果i=0;那么就是a[i]和a[i+1]进行比较,i作为下标最后的位置落在n-2的位置,和n-1去比较//这里起始位置如果i=1;那么就是a[i-1]和a[i]进行比较,i作为下标最后的位置落在n-1的0位置,和n-1-1去比较int i = 0;for (i = 1; i < n; i++){//创建一个标记来记录两两比较是否进行了交换//如果遍历一遍没有交换的话就证明该数组有序bool exchange = false;if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = true;}if (exchange == false){break;}}
}

6.快速排序

详细见数据结构——快速排序的三种方法和非递归实现快速排序

7.归并排序

基本思想:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:
在这里插入图片描述
动图详解:
在这里插入图片描述
代码实现思路:

子规模:
将数组分为两部分,然后分别把这两部分数据排成有序部分,然后将两组有序数组分别进行遍历比较,较小的数据放在临时数组tmp中,其中一个数组遍历结束后将另一组未比较的数据直接赋值到临时数组tmp,最后用memcpy函数将临时数组tmp的值拷贝放到指定数组中;
递归:
先将给定数组不断递归,直到数组中只有一个数据,也就代表有序,不需要进行排序,然后返回。
代码实现:

void MergeSort(int* a, int n)//归并排序
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("tmp malloc failed\n");return;}_MergeSort(a, 0, n - 1, tmp);free(tmp);
}void _MergeSort(int* a, int left, int right, int* tmp)//归并排序的排序部分
{//思路:将数组分为左右两部分,并且每组内是有序的,然后再将有序的两组分别遍历相比较,//较小的放在临时数组中,一个数组遍历结束后,另一个数组的所有值直接赋值给临时数组//最后用memcpy将临时数组的值拷贝到原数组if (left >= right){return;}int mid = (left + right) / 2;int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;//递归到一组为一个值的时候开始比较_MergeSort(a, begin1, end1, tmp);_MergeSort(a, begin2, end2, tmp);//比较int i = begin1;//这里i的值必须是begin1,当递归到右半边的数据的时候,给tmp赋值的时候必须对应的也应该是右半边的空间while (begin1 <= end1 && begin2 <= end2)//两组数据都没遍历结束的时候都可以进循环比较{if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}//将没有遍历完的数组赋值到临时数组tmp中while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}//这里memcpy中数组的起始地址要加上left的,因为我们每次只需要将递归中重新排序的那个组的数值拷贝到原来的数组即可memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}

归并排序的特性总结:

  1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(N)
  4. 稳定性:稳定

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

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

相关文章

Django 评论楼创建

Django 评论楼创建 【零】最终效果预览 【一】介绍 &#xff08;1&#xff09;情况说明 在Django模型层中有这么个字段 parent models.ForeignKey(toself, on_deletemodels.CASCADE, verbose_name"父评论ID", nullTrue, blankTrue)这个字段是一对多的外键字段 其…

linux中查看内存占用空间

文章目录 linux中查看内存占用空间 linux中查看内存占用空间 使用 df -h 查看磁盘空间 使用 du -sh * 查看每个目录的大小 注意这里是当前目录下的文件大小&#xff0c;查看系统的可以回到根目录 经过查看没有发现任何大的文件夹。 继续下面的步骤 如果您的Linux磁盘已满&a…

快速上手Spring Cloud 十五:与人工智能的智慧交融

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

【scala】使用gradle和scala构建springboot程序

零、版本说明: springboot: 2.7.18 使用log4j2&#xff0c;不使用springboot自带的logback scala版本&#xff1a;2.11 jackson版本&#xff1a;2.16.0 一、依赖&#xff1a; buildscript {dependencies {// using spring-boot-maven-plugin as package toolclasspath("…

FIBEX文件详细解析

文件概况 FIBEX文件是flexray的数据库文件&#xff0c;相当于CAN的DBC。 首先得了解这种文件的架构&#xff0c;就像下图那样&#xff0c;所以本文也是按照这个架构来进行展开讲解。project和PROCESSING-INFORMATION都是次要的&#xff0c;最重要的是ELEMENTS里面的5个元素。…

【Redis教程0x08】详解Redis过期删除策略内存淘汰策略

引言 Redis的过期删除策略和内存淘汰策略是经常被问道的问题&#xff0c;这两个机制都是做删除操作&#xff0c;但是触发的条件和使用的策略是不同的。今天就来深入理解一下这两个策略。 过期删除策略 Redis 是可以对 key 设置过期时间的&#xff0c;因此需要有相应的机制将…

SPDZ基础使用手册(深度学习视角)

基本类型 深度学习中最常使用的便是秘密定点数sfix&#xff0c;有关定点数的高级运算协议请参阅Paper: Secure Computation With Fixed-Point Numbers. 容器类型 SPDZ的深度学习框架主要基于TensorFlow实现&#xff0c;其中使用的容器是张量Tensor&#xff0c;在库中的定义如下…

[LeetCode]516. 最长回文子序列[记忆化搜索解法详解]

最长回文子序列 LeetCode 原题链接 题目 给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 示例 1&#xff1a…

java回溯算法笔记

回溯算法综述 回溯用于解决你层for循环嵌套问题&#xff0c;且不剪枝的回溯完全等于暴力搜索。 回溯算法模板https://blog.csdn.net/m0_73065928/article/details/137062099?spm1001.2014.3001.5501 组合问题 不能重复使用的组合问题&#xff08;startindex i1&#xff09…

centos7.9安装mysql

1. 概述 官网&#xff1a;https://www.mysql.com/ MySQL是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL AB 公司开发&#xff0c;MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的RDBMS (Relational Database Management S…

Kubernetes Gateway API 介绍

Kubernetes Gateway API 诞生背景 在 kubernetes 中&#xff0c;流量的治理主要分为两个部分&#xff1a; 南北向流量东西向流量 南北向流量&#xff08;NORTH-SOUTH traffic&#xff09; 在计算机网络中&#xff0c;南北向流量通常指数据流量从一个**内部网络&#xff08;…

鸿蒙--DevEco Studio安装步骤及配置

1.华为开发者联盟文档网站&#xff1a;文档中心 2.打开网页后&#xff0c;找到工具准备 (1). (2). (3). (4). (5).压缩包下载完成后解压 3.双击打开应用程序&#xff0c;进行如下操作&#xff1a; 以上步骤完成后&#xff0c;桌面上显示应用&#xff0c;双击打开&#xff1a;…

STM32G071 从 standby 模式退出后的 SRAM 数据保留

1.问题的描述 某客户使用 STM32G071 芯片从 standby 模式下唤醒&#xff0c;想要 SRAM 的数据在退出 standby模式后得以保持。根据手册的描述&#xff0c;配置了相应的比特位&#xff0c;但是发现数据仍然保持不了。 2.问题的复现 根据客户的描述&#xff0c;以及 STM32G071…

Excel:使用VLOOKUP函数,抓取指定数据,后一个列

Excel:使用VLOOKUP函数&#xff0c;抓取指定数据&#xff0c;后一个列 我们有这样一个数据源 要是实现这个页面的赋值 就是对应关系映射 使用 VLOOKUP(A2,Sheet2!$A$2:$B$9,2,FALSE)第一个参数是需要匹配的单元格。 第二个参数是数据源&#xff0c;我这里数据源用的是shee…

基于微信小程序的民宿短租系统设计与实现(论文+源码)_kaic

摘 要 随着社会的发展&#xff0c;出差、旅游成为常态&#xff0c;也就造成民宿短租市场的兴起。人们新到陌生的环境里找民宿一般都是通过中介。中介虽然可以快速找到合适的民宿但会收取大量的中介费用&#xff0c;这对刚到新环境里的人们来说是一笔大的资金支出。也有一些人通…

CMOS逻辑门电路

按照制造门电路的三极管不同&#xff0c;分为MOS型、双极性和混合型。MOS型集成逻辑门有CMOS、NMOS、PMOS&#xff1b;双极型逻辑门有TTL&#xff1b;混合型有BiCMOS。 CMOS门电路是目前使用最为广泛、占主导地位的集成电路。早期CMOS电路速度慢、功耗低&#xff0c;后来随着制…

小程序利用WebService跟asp.net交互过程发现的问题并处理

最近在研究一个项目&#xff0c;用到asp.net跟小程序交互&#xff0c;简单的说就是小程序端利用wx.request发起请求。获取asp.net 响应回来的数据。但经常会报错。点击下图的测试按钮 出现如下错误&#xff1a; 百思不得其解&#xff0c;试了若干方法&#xff0c;都不行。 因为…

Golang-Gin光速入门

安装 go get -u github.com/gin-gonic/gin初始化项目并启动服务 go mod init gin-project package mainimport "github.com/gin-gonic/gin"func main() {r : gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message"…

成都市酷客焕学新媒体科技有限公司:实现品牌的更大价值!

成都市酷客焕学新媒体科技有限公司专注于短视频营销&#xff0c;深知短视频在社交媒体中的巨大影响力。该公司巧妙地将品牌信息融入富有创意和趣味性的内容中&#xff0c;使观众在轻松愉悦的氛围中接受并传播这些信息。凭借独特的创意和精准的营销策略&#xff0c;成都市酷客焕…

常用植被物候提取方法 (TIMESATE/R语言/Python)-3.0

文章内容仅用于自己知识学习和分享&#xff0c;如有侵权&#xff0c;还请联系并删除 &#xff1a;&#xff09; 常用植被物候提取方法 (TIMESATE/R语言/Python)-1.0见 link常用植被物候提取方法 (TIMESATE/R语言/Python)-2.0见 link 这里主要介绍一下自己读到的论文&#xff…