数据结构与算法-排序

在这里插入图片描述
🌞入冬 时寒 添衣 勿病 要开心

排序

  • 🎈1.排序的基本概念
  • 🎈2.排序的分类
    • 🔭2.1插入排序
      • 🔎2.1.1直接插入排序
      • 🔎2.1.2折半插入排序
      • 🔎2.1.3希尔排序
    • 🔭2.2交换排序
      • 🔎2.2.1冒泡排序
      • 🔎2.2.2改进的冒泡排序
      • 🔎2.2.3快速排序
    • 🔭2.3选择排序
      • 🔎2.3.1简单选择排序
      • 🔎2.3.2树形选择排序
      • 🔎2.3.3堆排序
    • 🔭2.4归并排序
    • 🔭2.5基数排序

🎈1.排序的基本概念

排序是计算机程序设计中的重要操作,它将一组数据元素的任意序列,排列成按关键字有序的序列。其确切的定义如下:
设有n个数据元素的序列为{R1,R2,R3,...Rn},其关键字序列为{k1,k2,k3,...kn},排列就是确定1,2,3...n的一种排列p1,p2,p3,...pn,使表中元素相应的关键字满足非递减的关系kp1<=kp2<=kp3<=...kpn,使得序列{R1,R2,...Rn}成为一个按关键字有序的序列Rp1<=Rp2<=Rp3<=...Rpn,这种操作称为排序。
如果待排序的表中,存在多个关键字相同的数据元素,经排序后这些相同的关键字的元素之间的相对次序保持不变,则称这种排序方法是稳定的。若具有相同关键字的数据元素之间的相对次序发生变化,则称这种排序方法是不稳定的。

🎈2.排序的分类

由于待排序数据元素的数量不同,使排序的过程涉及不同的存储器,可将排序分为内部排序和外部排序两大类。
内部排序:待排序数据元素全部存储在计算机内存中进行的排序过程。
外部排序:待排序的数据元素的数量较大,以致内存不能一次容纳全部数据元素,需要借助外存才能完成排序的过程。

🔎数据组织(采用顺序表的存储结构)

#define _CRT_SECURE_NO_WARNINGS 1
#define MaxSize 100
typedef int KeyType;//关键字类型定义为整型
typedef int InfoType;//
typedef struct
{KeyType key;//关键字项InfoType otherinfo;//其他数据项
}ElemType;
typedef struct
{ElemType r[MaxSize];int length;
}SqList;

🔭2.1插入排序

🔎2.1.1直接插入排序

假设待排元素存放在数组r[1...n]中,排序过程中的某一时刻,r划分分成两个子区间r[1..i-1]r[i..n](起始时i=2),其中前一个子区间r[1..i-1]为已排好序的有序子表,后一个子区间r[i..n]为当前为排好序的无序子表。直接插入排序的一趟操作是将当前无序子表的第一个元素r[i]插入到有序子表r[1..i-1]中适当位置上,使r[i..i]变为新的有序子表。依次类推,直到全部元素插入完成为止。

void InsertSort(SqList& L)
{int i, j;for (i = 2; i <= L.length; i++){L.r[0] = L.r[i];//复制哨兵for (j = i - 1; L.r[0].key < L.r[j].key; j--){L.r[j + 1] = L.r[j];//将关键字大于r[i].key的元素后移}L.r[j + 1] = L.r[0];//在j+1处插入元素r[i]}
}

✅例题:
在这里插入图片描述
🔎算法分析
最好情况:正序时插入排序关键字比较次数为:n-1
最坏情况:反序时插入排序关键字的比较次数为:(n+2)(n-1)/2
空间复杂度:直接插入排序算法只使用两个变量i和j两个辅助变量,与问题的规模无关,所以直接插入排序的空间复杂度为O(1).
稳定性:直接插入排序是一种稳定的排序方法。

🔎2.1.2折半插入排序

🔎由于插入第i个元素到r[1]r[i-1]之间时,前i个数据都是有序的,所以可以用折半查找的方法先在r[1]r[i-1]中找到插入位置,再通过移动元素进行插入。具体流程如下:

  1. r[low]r[high](初始时low=1,high=i-1)中采用折半查找方法找到插入位置high+1.
  2. r[high+1]r[i-1]中元素后移一个位置.
  3. r[high+1]=r[i].
void BinsertSort(SqList& L)
{int i, j, low, high, mid;for (i = 2; i <= L.length; i++){L.r[0] = L.r[i];low = 1;high = i - 1;while (low <= high){mid = (low + high) >> 1;if (L.r[0].key < L.r[mid].key)high = mid - 1;elselow = mid + 1;}for (j = i - 1; j >= high + 1; j--){L.r[j + 1] = L.r[j];}L.r[high + 1] = L.r[0];}
}

🔎算法分析
时间复杂度:n2
空间复杂度O(1).
稳定性:折半插入排序是一种稳定的排序方法。

🔎2.1.3希尔排序

📖希尔排序又称缩小增量排序。其基本思路如下:

  1. 取定一个小于nn为表中元素的个数)的整数作为第一个增量d1,把表的全部元素分成d1个组,所有相互之间距离为d1的元素放在同一个组中,各组内采用直接插入排序。
  2. 取第2个增量d2(d2<d1),重复上述分组和排序过程。
  3. 依次类推,直到增量dt=1(dt<dt-1<...d2<d1),此时所有元素在同一组中采用直接插入排序。
    :希尔排序每趟排序不一定产生有序区,在最后排序结束前,希尔排序不能保证在每趟中将一个元素放到最终位置上。
void ShellInSort(SqList& L, int d)
{int i, j;for (i = d + 1; i <= L.length; i++){if (L.r[i].key < L.r[i - d].key){L.r[0] = L.r[i];for (j = i - d; j > 0 && L.r[0].key < L.r[j].key; j -= d){L.r[j + d] = L.r[j];}L.r[j + d] = L.r[0];}}
}
void ShellSort(SqList& L, int da[], int t)
{int i;for (i = 0; i < t; i++){ShellInSort(L, da[i]);}
}

🔎算法分析
时间复杂度:n1.3
空间复杂度O(1).
稳定性:希尔排序是一种不稳定的排序方法。

🔭2.2交换排序

交换排序是一类借助比较和交换来进行排序的方法,其基本思想是两两比较待排序数据元素的关键字,发现两个数据元素的次序相反时就进行交换,直到元素有序为止。交换排序主要有冒泡排序和快速排序

🔎2.2.1冒泡排序

📝冒泡排序又称为起泡排序。其基本思想为:
对于n个待排序的数据元素r[1...n],r[1]r[2]比较,大者放在r[2]中,r[2]r[3]比较,大者放在r[3]中,依次类推,r[n-1]r[n]比较,大者放在r[n],这样经过一趟比较,r[1]r[n]中的最大值放在r[n]中;第二趟,对于n-1个待排序数据元素r[1...n-1],采用上述方法进行比较,r[1]r[n-1]的最大者放在r[n-1]中;依次类推,最后一趟对于两个待排序元素r[1..2],r[1]r[2]进行比较,大者放在r[2]中。上述过程共进行n-1趟完成冒泡排序。

void BubbleSort(SqList& L)
{int i, j;ElemType temp;for (i = L.length; i > 1; i--){for (j = 1; j < i; j++){if (L.r[j].key > L.r[j + 1].key){temp = L.r[j];L.r[j] = L.r[j + 1];L.r[j + 1] = temp;}}}
}

🔎算法分析
时间复杂度:n2
空间复杂度O(1).
查找次数n(n-1)/2
稳定性:冒泡排序是一种稳定的排序方法。

🔎2.2.2改进的冒泡排序

📖从上述算法可知,在某些情况下,第i(2<=i<=n)趟时数据元素已有序,但算法仍然执行后面几趟的比较。事实上,一旦算法中某一趟未出现任何元素交换,说明序列已有序,此时算法可结束。为此,改进的冒泡排序如下:

void BubbleSort(SqList& L)
{int i, j;int tag;ElemType temp;for (i = L.length; i > 1; i--){tag = 0;for (j = 1; j < i; j++){if (L.r[j].key > L.r[j + 1].key){temp = L.r[j];L.r[j] = L.r[j + 1];L.r[j + 1] = temp;tag = 1;}}if (!tag)//该趟没有数据元素的交换则退出循环return;}
}

✅例题:
在这里插入图片描述
🔎算法分析
时间复杂度n
空间复杂度O(1).
查找次数n-1
稳定性:改进后的冒泡排序是一种稳定的排序方法。

🔎2.2.3快速排序

📖快速排序,又称分区交换排序,它是冒泡排序的一种改进排序方式。其基本思想是在待排序的n个数据元素中以某个数据元素(通常为第一个元素)作为支点,将其放在适当的位置,数据元素序列被划分成两个部分,其中左半部分数据元素小于等于支点,右半部分数据元素大于等于支点,该过程称为一趟快速排序。依次类推,对左右两部分分别进行快速排序的递归处理,直至数据元素序列按关键字有序为止。快速排序的划分方法如下:设两个指针i和j,开始分别指向表的开始与结束,任一时刻,支点保存于辅助变量temp,即temp=L.r[i].

  1. j>i&&L.r[j].key>=temp.key,则两种位置合适,j1,重复此过程;否则,两者位置不合适,L.r[i]=L.r[j].
  2. i<j&&L.r[i].key<=temp.key,则两者位置合适,i1,重复该过程;否则,两者位置不合适,L.r[j]=L.r[i].
  3. 重复上述过程,直至ij相等。
  4. L.r[i]=temp.
void QuickSort(SqList& L, int s, int t)
{int i = s, j = t;ElemType temp;if (s < t){temp = L.r[s];while (i != j){while (j > i && L.r[j].key >= temp.key)j--;L.r[i] = L.r[j];while (i < j && L.r[i].key <= temp.key)i++;L.r[j] = L.r[i];}L.r[i] = temp;QuickSort(L, s, i - 1);//左半区递归排序QuickSort(L, i + 1, t);//右半区递归排序}
}

🔎算法分析
最好情况时间复杂度nlog2n
最坏情况时间复杂度:n2,此时,比较次数为n(n-1)/2
空间复杂度O(log2n).
稳定性:快速排序是一种不稳定的排序方法。

🔭2.3选择排序

选择排序的基本思想是每一趟(n个数据元素序列共进行n-1趟排序),从待排序的数据元素中选出最小(或最大)的数据元素,顺序放在已排好序的子表的最后,直至全部元素有序为止。选择排序适合于从大量元素中选择部分排序元素的情形。例如,从10000个数据元素中选择出关键字大小为前20位的数据元素。

🔎2.3.1简单选择排序

简单选择排序思想是第i(1<=i<=n-1)趟排序开始时,从r[i..n]中选出关键字最小(或最大)的数据元素r[k](i<=k<=n)r[i]进行交换,经过n-1趟排序后,表r[1..n]递增(或递减)有序。

void SelectSort(SqList& L)
{int i, j, k;ElemType temp;for (i = 1; i < L.length; i++){k = i;for (j = i + 1; j <= L.length; j++){if (L.r[j].key < L.r[k].key)k = j;}if (k != i)//交换r[k]和r[i]{temp = L.r[i];L.r[i] = L.r[k];L.r[k] = temp;}}
}

🔎算法分析
比较次数n(n-1)/2
时间复杂度:n2
空间复杂度O(1).
稳定性:简单选择排序是一种不稳定的排序方法。

🔎2.3.2树形选择排序

树形选择排序,又称锦标赛排序,它是一种按照锦标赛的思路设计的选择排序方法,其每趟排序过程可用n个叶子结点的完全二叉树表示。每趟排序过程是:将nn一般为2的幂)个数据元素的关键字作为叶子结点,相邻的两个叶子结点进行两两比较,然后在其中n/2上取整个较小者(或较大者)之间再进行比较,重复该过程,直至选出最小(或最大)关键字的数据元素为止(此时完成一趟树形选择排序)。选出最小(后面以最小为例)关键字后,将叶子结点中的最小关键字改为“最大值”(如无穷),重复上述过程,直至所有元素有序为止。
在这里插入图片描述
🔎算法分析
时间复杂度O(nlog2n)
空间复杂度O(n).
稳定性:树形选择排序是一种稳定的排序方法。

🔎2.3.3堆排序

堆排列是一种树形选择排序,主要利用堆的特性进行排序。它的特点是在排序过程中,将r[1…n]看成一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点间的内在关系,在当前无序区中选择关键字最小(或最大)的数据元素。
在这里插入图片描述
✅排序思想:堆排序的关键是用筛选法建立堆,首先对待排序的数据元素序列构造出一个堆,此时选出了堆中所有数据元素的最小者(以小顶堆为例)为堆顶,随后将它从堆中移走(通常是将堆顶数据元素和堆中最后一个数据元素进行交换),并将剩余的数据元素再调整成堆,这样又找出了次小的数据元素,依次类推,直到堆中只有一个数据元素为止。

void SiftAdjust(SqList L, int s, int t)
{int i = s, j = 2 * i;ElemType temp = L.r[i];while (j <= t){if (j<t && L.r[j].key>L.r[j + 1].key)j++;if (temp.key > L.r[j].key){L.r[i] = L.r[j];i = j;j = 2 * i;}else break;}L.r[i] = temp;
}
void HeadSort(SqList& L)
{int i;ElemType temp;for (i = L.length / 2; i >= 1; i--){temp = L.r[1];L.r[1] = L.r[i];L.r[i] = temp;SiftAdjust(L,1, i - 1);}
}

🔎算法分析
时间复杂度O(nlog2n)
空间复杂度O(1).
稳定性:堆排序是一种不稳定的排序方法。

🔭2.4归并排序

归并排序是多次将两个及两个以上的有序表合并成一个新的有序表的排序方法。最简单的归并排序是直接将两个有序的子表归并成一个有序表的2-路归并排序方法。
在这里插入图片描述

🔎算法分析
时间复杂度O(nlog2n)
空间复杂度O(n).
稳定性:归并排序是一种稳定的排序方法。

🔭2.5基数排序

设有n个数据元素序列r[1…n],且每个关键字r[i].key由d位数字Kd-1Kd-2…K0组成(或每个数据元素r[i]中含有d个关键字),其中Kd-1为最高位,K0为最低位,每一位的值都在0<=Ki<r,其中r称为基数。基数排序分为如下两种情形:
在这里插入图片描述

在这里插入图片描述
🔎算法分析
时间复杂度O(d(n+r))(r为基数)
空间复杂度O(r).
稳定性:基数排序是一种稳定的排序方法。


✅总结:
在这里插入图片描述

好啦,关于内部排序的知识到这里就先结束啦,后期会继续更新学习数据结构与算法的相关知识,欢迎大家持续关注、点赞和评论!❤️❤️❤️

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

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

相关文章

07-项目打包 React Hooks

项目打包 项目打包是为了把整个项目都打包成最纯粹的js&#xff0c;让浏览器可以直接执行 打包命令已经在package.json里面定义好了 运行命令&#xff1a;npm run build&#xff0c;执行时间取决于第三方插件的数量以及电脑配置 打包完之后再build文件夹下&#xff0c;这个…

啊?这也算事务?!

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

Spring Boot学习随笔- 集成MyBatis-Plus,第一个MP程序(环境搭建、@TableName、@TableId、@TableField示例)

学习视频&#xff1a;【编程不良人】Mybatis-Plus整合SpringBoot实战教程,提高的你开发效率,后端人员必备! 引言 MyBatis-Plus是一个基于MyBatis的增强工具&#xff0c;旨在简化开发&#xff0c;提高效率。它扩展了MyBatis的功能&#xff0c;提供了许多实用的特性&#xff0c;…

golang第六卷---go命令

go命令 go/go helpgo versiongo envgo buggo buildgo installgo getgo modgo rungo cleango docgo fixgo fmtgo generatego workgo testgo toolgo vet go/go help 通过该命令&#xff0c;我们可以查看go语言中的所有命令&#xff0c;其中go与go help两个命令是等效的 如下&…

实时数仓应用价值(上)

欢迎关注WX公众号&#xff1a;数据运营入表资产化服务 获取更多算法源码材料 2023数据资源入表白皮书&#xff0c;推荐系统源码下载-CSDN博客 浅析研发支出费用化和资本化的区别-CSDN博客 商业银行数据资产估值白皮书&#xff0c;推荐系统源码下载-CSDN博客 用友BIP数据资…

计算机网络【EPoll原理】

预备知识&#xff1a;内核poll钩子原理 内核函数poll_wait 把当前进程加入到驱动里自定义的等待队列上 &#xff1b; 当驱动事件就绪后&#xff0c;就可以在驱动里自定义的等待队列上唤醒调用poll的进程&#xff1b; 故poll_wait作用&#xff1a;可以让驱动知道事件就绪的时…

笔记1:基于锚框(先验框)的目标检测

一、边缘框&#xff08;bounding box&#xff09; 1.1 定义 边缘框&#xff1a;真实标注的物体位置 2.1 表示方式 1、&#xff08;x1,y1)和(x2,y2) 2、&#xff08;x1,y1)和w,h 二、锚框(anchor box)/先验框&#xff08;prior bounding box&#xff09; 2.1 定义 对边缘…

DDC和PLC的区别

前言 PLC与DDC控制器的比较&#xff0c;一直以来在相关领域内受到广泛关注。每个人站在不同的角度分析&#xff0c;都会有不同的结论&#xff0c;我们今天聊聊这个话题。 基本定义和功能 可编程控制器PLC与直接数字控制器DDC&#xff0c;两者都由CPU模块、I/O模块、显示模块…

Python 内置高阶函数练习(Leetcode500.键盘行)

Python 内置高阶函数练习&#xff08;Leetcode500.键盘行&#xff09; 【一】试题 &#xff08;1&#xff09;地址&#xff1a; 500. 键盘行 - 力扣&#xff08;LeetCode&#xff09; &#xff08;2&#xff09;题目 给你一个字符串数组 words &#xff0c;只返回可以使用在…

可移动磁盘上的文件删除了怎么恢复?详细教程介绍

在我们的日常生活和工作中&#xff0c;可移动磁盘作为一种便携式的存储设备&#xff0c;经常被用来备份和传输数据。然而&#xff0c;有时候由于误操作或不小心的删除&#xff0c;导致可移动磁盘上的文件丢失。这些文件可能包含重要的工作资料、个人照片、视频等&#xff0c;一…

小天使的生命之源:新生儿补充铁剂的细致关怀与注意事项

引言&#xff1a; 新生儿是生命的奇迹&#xff0c;而良好的营养对于他们的健康成长尤为关键。铁是新生儿生命早期阶段发育所必需的重要元素之一&#xff0c;然而&#xff0c;在补充铁剂时&#xff0c;家长需要特别注意一系列细节。本文将深入探讨铁的作用、补充时机&#xff0…

在线尺码计算

在线衣服尺码计算 尺码不确定的话&#xff0c;可以填写身高、体重生成可以参考的尺码还是不错的 工具简介 选购时请综合参考尺码表中的各项参数&#xff0c;这有助您选择到更好的尺码。 该尺码计算工具仅供参考&#xff0c;测量脚时请注意用适当力度轻踩水平面上。因测量方法不…