插入排序-希尔排序-选择排序-冒泡排序-快速排序-基数排序-外部排序-归并排序[数据结构与算法]

文章详细总结了插入排序、希尔排序、选择排序、归并排序、交换排序(冒泡排序、快速排序)、基数排序、外部排序。从`思想`到`代码实现`。 大三党,大数据专业,正在为面试准备,欢迎学习交流`。
摘要由CSDN通过智能技术生成

    大三党,大数据专业,正在为面试准备,欢迎学习交流
    文章详细总结了插入排序、希尔排序、选择排序、归并排序、交换排序(冒泡排序、快速排序)、基数排序、外部排序。从思想代码实现

往期文章
绪论-数据结构的基本概念
绪论-算法
线性表-顺序表和链式表概念及其代码实现
查找-顺序+折半+索引+哈希

1 排序的基本概念

1.1 何为排序

    将一组数据元素序列重新排列,使得数据元素序列按某个数据项(关键字)有序。

1.2 稳定排序和不稳定排序

    对于任意的数据元素序列,若排序前后所有相同关键字的相对位置都不变,则称该排序方法称为稳定的排序方法。
    若存在一组数据序列,在排序前后,相同关键字的相对位置
发生了变化,则称该排序方法称为不稳定的排序方法。

1.3 内部排序和外部排序

    若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序;
在这里插入图片描述

    反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中 完成,则称此类排序问题为外部排序。

2 插入排序

2.1 基本思想

在这里插入图片描述

2.2 插入排序三步曲

定位->挤空->插入

  • 在R[1…i-1]中查找R[i]的插入位置,
    R[1…j].key  R[i].key < R[j+1…i-1].key;
  • 将R[j+1…i-1]中的所有记录均后移 一个位置;
  • 将R[i] 插入(复制)到R[j+1]的位置上

2.3 举例

排序过程:整个排序过程为n-1趟插入,即先将序列中第
1个记录看成是一个有序子序列,然后从第2个记录开始,
逐个进行插入,直至整个序列有序
在这里插入图片描述

2.4 算法的代码描述

  • 两层循环外层控制无序序列的取值 内层控制岗哨在有序的排序 找到位置跳出插入
  • r[0] 作为岗哨 每次从无序依次取出放入 用来和有序序列比较插入
  • j控制有序序列 j=i-1 每次都从有序的最后一个开始
  • i控制无序序列 从前往后取 和 j顺序相反
  • 代码中从小到大排序
  • 需要注意第二个循环如果岗哨比所有的值都要小最后会r[0] 和r[0]自己比较一样能够跳出循环

补充 重要 岗哨的目的也是为了防止覆盖 可以思考 如果先移动有序序列就会把无序序列的第一个值覆盖

typedef struct
{
    int key;//关键字
  float info;//该成员的其他信息
}JD;

void straisort(JD r[],int n)//对长度为n的序列
{
   
 int i,j;
 for(i=2;i<=n;i++)
 {
   
  r[0]=r[i]//第一个需要排序的设为岗哨 不取因为1看做有序 其余n-1看做无序序列 
  j=i-1;//从后往前
  //需要注意第二个循环如果岗哨比所有的值都要小最后会r[0] 和r[0]自己比较一样能够跳出循环
  while(r[0].key<r[j].key)
  {
   
     r[j+1]=r[j]
     j--;
  }
  r[j+1]=r[0]
 }
}

2.5 时间复杂度

最好情况分析:如果n个值比较。开始1个为有序 n-1为无序。需要进行n-1趟的排序。当序列为初始就是顺序排列。那么每次取出放入岗哨的值都比有序的大,那么每趟只需要比较一次。比较次数为n-1。由于需要放入岗哨再移动到有序的最后所以每趟移动2次。
最坏情况分析:当序列为初始就是逆序排列。一样是n-1趟排序,第1趟比较次数为2(特别注意 岗哨除了跟第一个值比较 还要跟自己比较一次才能跳出循环 回头看代码 )所以应该是 2,3,4…n 等差数列相加。第1趟移动为3次(1是移动到岗哨 2是有序值后移 3 是岗哨移到有序值之前的位置)所以应该是 3,3,4…n+1 等差数列相加

2.6 性能总结+改进直接插入的方法

在这里插入图片描述简单插入排序的本质比较和交换
简单插入排序复杂度由逆序个数决定
如何改进简单插入排序复杂度?

  • 分组,比如C(n,2)/2>2C((n/2),2)/2
  • 3,2,1有3组逆序对(3,1)(3,2)(2,1)需要交换3次。但相隔较远的3,1交换一次后1,2,3就没有逆序对了。
  • 基本有序的插入排序算法复杂度接近O(n)

3 希尔排序(插入排序的改进方法)

3.1 基本思想

    分割成若干个较小的子文件,对各个子文件分别进行直接插入排序,当文件达到基本有序时,再对整个文件进行一次直接插入排序。

对待排记录序列先作“宏观”调整,再作“微观”调整

3.2 排序过程

  1. 首先将记录序列分成若干子序列,
  2. 然后分别对每个子序列进行直接插入排序,
  3. 最后待基本有序时,再进行一次直接插入排序

如下 在这里插入图片描述
其中,d 称为增量,它的值在排序过程中从大到小逐渐缩小,直至最后一趟排序减
为 1。

3.3 数值演示

记住思想,若干个部分有序最后达到整体有序,使得复杂度最低。
在这里插入图片描述

3.4 算法的代码描述

注意看注释,特别注意d[ ]是什么
1三个循环嵌套
2最外循环控制选择不同的d
3二层循环控制依次取出间隔为d的两个值,比较后后移一位
4最内层循环控制 2个值之间的比较换位置

//r[]表示待排序的序列 n表示个数 
//d[]表示增量序列 就是d的取值 7 6 5 ..这样
// T表示几种增量序列  d[]的元素个数   
void shellsort(JD r[],int
n,int d[]int T)
 
  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Windalove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值