一、概述

排序是数据处理中十分常见且核心的操作,虽说实际项目开发中很小几率会需要我们手动实现,毕竟每种语言的类库中都有n多种关于排序算法的实现。但是了解这些精妙的思想对我们还是大有裨益的。

1.1 排序的基本概念和分类

假设含有n个记录的序列为{r1,r2,…,rn},其相应的关键字分别为{k1,k2,…,kn},需确定1,2,。。。。,n的一种排列p1,p2,…,pn,使其相应的关键字满足kp1<=kp2<=kp3…<=kpn非递减(或非递增)关系,即使得序列成为一个按关键字有序的序列,这样的操作就称为排序

1.1.1 排序的稳定性

腾讯校招2016笔试题曾考过

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

通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。

常见稳定排序算法:
基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序

常见不稳定排序算法:
堆排序、快速排序、希尔排序、直接选择排序

稳定排序算法优点:
排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就 是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。

1.1.2 内排序与外排序

根据排序过程中,待排序的记录是否被全部放置在内存中,排序分为:内排序外排序
内排序:在排序整个过程中,待排序的所有记录全部被放置在内存中
外排序:由于排序的记录个数太多,不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能进行。我们主要介绍的内排序的多种算法。
根据排序过程中借助的主要操作,我们把内排序分为:插入排序、交换排序、选择排序和归并排序。

1.2 排序用到的结构与函数

1.2.1 数据结构

为了讲清楚排序算法的代码,我们就先提供一个用于排序的顺序表结构,以后的排序算法也会用到这个结构


#define MAXSIZE 10      //用于要排序数组个数最大值,可根据需要修改typedef struct
{int r[MAXSIZE +1];  //用于存储要排序的数组,r[0]用于哨兵或临时变量int length;         //用于记录顺序表的长度
}SqList;

1.2.2 交换函数

由于排序最常用到的函数就是数组交换,所以我们就把它单独提出来作为一个函数

/* 交换 L 中数组r的下标为 i 和 j 的值 */
void swap(SqList *L, int i, int j)
{int temp = L->r[i];L->r[i] = L->r[j];L->r[j] = temp;
}

二、冒泡排序

2.1 基本思想

冒泡排序(Bubble Sort) 是一种极其简单的排序算法,也是我所学的第一个排序算法。它重复地走访过要排序的元素,依次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。

冒泡排序算法的运作如下:
1. 比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3. 针对所有的元素重复以上的步骤,除了最后一个。
4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

假设L = { 6, 5, 3, 1, 8, 7, 2, 4 }进行冒泡排序的实现过程如下

2.2 核心实现

void BubbleSort(SqList * L)
{int i,j;for (i = 1; i < L->length; i ++){for (j = L->length - 1; j >= i; j --)   // 注意 j 是从后往前循环{if (L->r[j] > L->r[j + 1])          // 如果前者大于后者{swap(L, j, j + 1);              // 进行交换}}}
}

三、简单选择排序

3.1 基本思想

选择排序(Selection Sort) 也是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

注意选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。
比如对L = { 8, 5, 2, 6, 9, 3, 1, 4, 0, 7 }进行选择排序的实现过程如下所示

使用选择排序为一列数字进行排序的宏观过程:

选择排序是不稳定的排序算法,不稳定发生在最小元素与A[i]交换的时刻。

比如序列:{ 5, 8, 5, 2, 9 },一次选择的最小元素是2,然后把2和第一个5进行交换,从而改变了两个元素5的相对次序。

3.2 核心实现

/* 简单选择排序 */
void SelectSort(SqList * L)
{int i,j,min;for (i = 1; i < L->length; i ++){min = i;                                /* 将当前下标定义为最小值下标 */for (j = i+1; j <= L->length; j ++){if (L->r[min] > L->r[j])            /* 如果有小于当前最小值的关键字*/min = j;                        /* 将此关键字的下标赋值给min */}if (i != min)                           /* 若min不等于i,说明找到最小值,交换 */swap(L, i, min);}
}

四、插入排序

4.1 基本思想

插入排序是一种简单直观的排序算法。它的工作原理非常类似于我们抓扑克牌。
对于未排序数据(右手抓到的牌),在已排序序列(左手已经排好序的手牌)中从后向前扫描,找到相应位置并插入。
插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

具体算法描述如下:

1. 从第一个元素开始,该元素可以认为已经被排序
2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5. 将新元素插入到该位置后
6. 重复步骤2~5

插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。

假设对L = { 6, 5, 3, 1, 8, 7, 2, 4 }进行插入排序的实现过程如下:

使用插入排序为一列数字进行排序的宏观过程:

4.2 核心实现

/* 直接插入排序 */void InsertSort(SqList * L)
{int i,j;for (i = 2; i <= L->length; i ++) {if (L ->r[i] < L->r[i-1]){L->r[0] = L->r[i];                          /* 设置哨兵 */for (j = i-1; L->r[j] > L->r[0]; j --)L->r[j+1] = L->r[j];                    /* 记录后移 */L->r[j+1] = L->r[0];                        /* 插入到正确的位置 */}}
}

虽然这三个排序的时间复杂度都为 O(n2),但是,简单选择排序的性能上略优于冒泡排序,直接插入排序比冒泡和简单选择排序的性能要更好一些。

今天时间关系先给大家介绍这三种最基本也是最简单的排序算法,以后再给大家介绍希尔排序、堆排序等等

相关连接:基础算法(1) — 快速排序算法

参考文档

[1]严蔚敏、吴伟民. 数据结构(C语言版). 北京:清华大学出版社,1997
[2]程杰. 大话数据结构. 北京:清华大学出版社,2011

排序算法(01)— 三种简单排序(冒泡、插入、选择)相关推荐

  1. 算法:三种简单排序算法

    排序算法比較常见的有:冒泡排序.简单选择排序.直接插入排序:希尔排序.堆排序.归并排序和高速排序算法等. 今天先学习一下前面三种比較简单的算法.排序的相关概念: ①排序的稳定性:两个或多个元素相等.排 ...

  2. 图解排序算法之3种简单排序(选择,冒泡,直接插入)

    排序是数据处理中十分常见且核心的操作,虽说实际项目开发中很小几率会需要我们手动实现,毕竟每种语言的类库中都有n多种关于排序算法的实现.但是了解这些精妙的思想对我们还是大有裨益的.本文简单温习下最基础的 ...

  3. 一学就废的三种简单排序【冒泡、插入、选择】

    文章目录 其他排序算法 冒泡排序 算法实现 代码实例 插入排序 算法实现 代码实例 选择排序 算法实现 代码实例 其他排序算法 一学就废的归并排序 冒泡排序 排列顺序从前到后或者从后往前都可,本文选择 ...

  4. [ 数据结构 -- 手撕排序算法第三篇 ] 希尔排序

    手撕排序算法系列之:希尔排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算法:排序算 ...

  5. php 各种排序算法,PHP四种常见排序算法

    一.冒泡排序: 冒泡排序可以说是最常见,也是最简单,最经典的排序算法了. 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换 ...

  6. 排序算法(三)—— 插入法排序算法

    1.插入法排序算法介绍 插入法是一个比较常用的排序方法.插入法排序的思路就是将要排序的数组分两个区间,一个是已排序区间,一个是未排序区间.初始时,默认第一个元素是已排序区间的,后面的所有元素为未排序区 ...

  7. JS三种简单排序算法

    冒泡排序:最简单.最慢.长度小于7的时候最优  插入排序:比冒泡要快比快速排序和希尔排序慢,数据量小的时候优势大  快速排序:速度很快  //js利用systemSort进行排序 systemSort ...

  8. 三种简单排序算法---冒泡排序,简单选择排序,直接插入排序

    冒泡排序 核心思想:类似水泡一样,一趟比较,通过相邻元素的交换,冒出当前序列的最小值(最大值)到相应位置 复杂度分析 最好的情况:序列本身有序,只要进行n-1次比较,无需交换,时间复杂度为O(n) 最 ...

  9. 简单选择排序_Python3三种简单排序(冒泡、插入、选择)的比较

    冒泡排序 相邻的两个元素对比,大的数后推,遍历整个列表一次后,将最大项以冒泡的方式排列到列表末尾. 简易版冒泡排序示例如下 def bubble(sl): """ 冒泡排 ...

最新文章

  1. ffmpeg frei0r filter 参数及效果
  2. Haar小波变换的快速实现
  3. MXNET:深度学习计算-GPU
  4. Android Configuration change引发的问题及解决方法
  5. 前端常见知识点四之webscoket
  6. Windows 11 预览版 Build 22000.120 发布
  7. ceph编译_Ceph编译安装教程
  8. 如法炮制的意思,成语如法炮制的炮什么意思?
  9. Ajax实现搜索提示框~超级详细
  10. 云网络开山之作,揭秘云上高速公路的十年技术成果!
  11. 运维,请警惕脚本灾难!
  12. double转换long的疑问
  13. netbeans使用教程
  14. win7 配置jdk
  15. 对话框的数据交换--MFC深入浅出
  16. 离线中技术方案的场景
  17. 【control】模型预测控制(MPC)
  18. ArcGIS提取道路中心线数据制图
  19. 自动驾驶基础——惯性测量单元(IMU)
  20. 多线程支持断点续传的文件传输--(摘自大富翁)

热门文章

  1. ChatGPT+Word的智能化文字生成和应用
  2. HTTP代理如何解决爬虫请求受限
  3. php制作特效文字,Photoshop制作漂亮的水滴字特效
  4. ios上架图片在线制作_ios签名企业证书
  5. phpstorm 2017激活
  6. ios 位置服务器,关于 iOS 和 iPadOS 中的隐私与定位服务
  7. cocos creator学习(七)音乐
  8. 【Spring】SpringBoot 配置MySql和Doris多数据源
  9. 趣味程序设计_抢n游戏(总结规律)
  10. 为什么宝宝腹泻就一定要用中性乳糖酶?