8大排序算法图文讲解转

本文链接:http://www.cricode.com/3212.html

作者:快课网——Jay13  转载请务必保留作者出处,谢谢!

 

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。

本文将依次介绍上述八大排序算法。

算法一:插入排序

 

插入排序示意图

插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

算法步骤

1)将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

2)从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)


 

算法二:希尔排序

希尔排序示意图

 

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
  • 但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

算法步骤

1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;

2)按增量序列个数k,对序列进行k 趟排序;

3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

 


 

算法三:选择排序

选择排序示意图

选择排序(Selection sort)也是一种简单直观的排序算法。

算法步骤

1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

2)再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

3)重复第二步,直到所有元素均排序完毕。

 


 

算法四:冒泡排序

冒泡排序示意图

 冒泡排序Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

算法步骤

1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

3)针对所有的元素重复以上的步骤,除了最后一个。

4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

 


 

算法五:归并排序

归并排序示意图

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

算法步骤:

1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4. 重复步骤3直到某一指针达到序列尾

5. 将另一序列剩下的所有元素直接复制到合并序列尾

详细介绍:归并排序

 


 

算法六:快速排序

快速排序示意图

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

算法步骤:

1 从数列中挑出一个元素,称为 “基准”(pivot),

2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

详细介绍:快速排序

 


 

算法七:堆排序

堆排序示意图

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

堆排序的平均时间复杂度为Ο(nlogn) 。

算法步骤:

1)创建一个堆H[0..n-1]

2)把堆首(最大值)和堆尾互换

3)把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置

4) 重复步骤2,直到堆的尺寸为1

详细介绍:堆排序

 


 

算法八:基数排序

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

说基数排序之前,我们简单介绍桶排序:

算法思想:是将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
简单来说,就是把数据分组,放在一个个的桶中,然后对每个桶里面的在进行排序。

例如要对大小为[1..1000]范围内的n个整数A[1..n]排序

首先,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储   (10..20]的整数,……集合B[i]存储(   (i-1)*10,   i*10]的整数,i   =   1,2,..100。总共有  100个桶。

然后,对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。  再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任  何排序法都可以。

最后,依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这  样就得到所有数字排好序的一个序列了。

假设有n个数字,有m个桶,如果数字是平均分布的,则每个桶里面平均有n/m个数字。如果

对每个桶中的数字采用快速排序,那么整个算法的复杂度是

O(n   +   m   *   n/m*log(n/m))   =   O(n   +   nlogn   –   nlogm)

从上式看出,当m接近n的时候,桶排序复杂度接近O(n)

当然,以上复杂度的计算是基于输入的n个数字是平均分布这个假设的。这个假设是很强的  ,实际应用中效果并没有这么好。如果所有的数字都落在同一个桶中,那就退化成一般的排序了。

前面说的几大排序算法 ,大部分时间复杂度都是O(n2),也有部分排序算法时间复杂度是O(nlogn)。而桶式排序却能实现O(n)的时间复杂度。但桶排序的缺点是:

1)首先是空间复杂度比较高,需要的额外开销大。排序有两个数组的空间开销,一个存放待排序数组,一个就是所谓的桶,比如待排序值是从0到m-1,那就需要m个桶,这个桶数组就要至少m个空间。

2)其次待排序的元素都要在一定的范围内等等。

 

 总结

各种排序的稳定性,时间复杂度、空间复杂度、稳定性总结如下图:

 

关于时间复杂度:

(1)平方阶(O(n2))排序
各类简单排序:直接插入、直接选择和冒泡排序;

(2)线性对数阶(O(nlog2n))排序
  快速排序、堆排序和归并排序;
(3)O(n1+§))排序,§是介于0和1之间的常数。

       希尔排序
(4)线性阶(O(n))排序
基数排序,此外还有桶、箱排序。

 

关于稳定性:

稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序

 

本文链接:http://www.cricode.com/3212.html

作者:快课网——Jay13  转载请务必保留作者出处,谢谢!

转载于:https://www.cnblogs.com/yzmb/p/3920709.html

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

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

相关文章

与Linux系统相关的面试题

摘自微信公众号:嵌入式ARM 1、TASK有几种状态? 运行、就绪、等待、睡眠、挂起 2、TASK有几种通讯方式? 共享内存、信号量、消息队列、管道、socket 3、sysfs的主要作用? (1)可以把设备和驱动程序的信…

linux pmap was java,jvm 《九》pmap linux 命令介绍 及使用

用法pmap [ -x | -d ] [ -q ] pids...pmap -V选项含义-x extended Show the extended format. 显示扩展格式-d device Show the deviceformat. 显示设备格式-q quiet Do not display some header/footerlines. 不显示头尾行-V show version …

Immutable Collections(3)Immutable List实现原理(中)变化中的不变

Immutable Collections(3)Immutable List实现原理(中)变化中的不变 文/玄魂 前言 在上一篇文章&#xff08;Immutable Collections&#xff08;2&#xff09;ImmutableList<T>实现原理.&#xff08;上&#xff09;&#xff09;,分析了&#xff09;ImmutableList<T>…

大话Fragment管理

大话Fragment管理 上一个项目遇到了一个Activity 管理30个Fragment的情况&#xff0c;刚开始的时候真的管理的焦头烂额&#xff0c;但是后来不停的研究api文档&#xff0c;渐渐的明白了android的Fragment管理 体系。下面用…

c语言例题功能作用,一篇C语言面试题的汇总

2015-03-21 06:30:02阅读( 107 )1&#xff0e; 找错void test1(){char string[10]; //string的长度应该设为11&#xff0c;要给”留出位置char* str1”0123456789″;strcpy( string, str1);}void test1(){char string[10], str1[10];for(I0; I<10&#xff1b; I ) //变量…

第一季4:Hi3518E_SDK_Vx.x.x.x的SDK目录结构

一、Hi3518E_SDK_V1.0.3.0.tgz的位置 “Hi3518E_SDK_V1.0.3.0.tgz”位于“Hi3518E V200R001C01SPC030”中&#xff0c;其目录包含关系如下。 Hi3518E_SDK_V1.0.3.0.tgz 解压后内部文件组织如下。 二、执行SDK展开脚本sdk.unpack后的目录关系 将Hi3518E_SDK_V1.0.3.0.tgz拷贝到…

第一季6:海思方案中uboot、kernel和rootfs的烧写方法

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、概述 因为所用的板子默认从SPI Flash启动&#xff0c;因此本文主要讲如何“使用tftp&#xff0c;烧写映像文件&#xff08;uboot、kernel、rootfs&#xff09;到SPI Flash”。另外海思还提供了“…

CSS如何正确显示人民币符号¥

我们做网页时要正确显示人民币符号可以用如下办法&#xff1a;CSS&#xff1a;在中文输入法下用shift4输出的&#xffe5;在微软雅黑&#xff08;Microsoft YaHei&#xff09;&#xff0c;华文细黑&#xff08;STXihei&#xff09;&#xff0c;&#xff08;MingLiu&#xff09;…

java模式之装饰模式

1. 什么叫装饰模式? 根据业务的需求&#xff0c;需要对一个类的方法进行增强的处理。 2. 为什么需要装饰模式&#xff1f; 拓展性更加的好&#xff0c;当觉得这个装饰不好的时候&#xff0c;可以直接拿下&#xff0c;不需要改变任何的代码。 3. 装饰模式的一个具体的应用&…

字体文件解析 c语言,如何正确地从C语言的文件中读取某些字符串?

您试图从文件中读取的内容并不简单,但可以通过设置一个标志来处理,该标志告诉您是否已经看到a或b,跳过所有空白和:字符,将所有其他字符存储在缓冲区中,根据需要重新分配,然后在第二个“A”或“B”找到了,把那个角色放回FILE*流与ungetc,nul终止并返回缓冲区。听起来很简单——对…

如何判断linux系统是32位还是64位的?

最简单的是输入命令&#xff1a;uname -m 查看输出&#xff0c;如果输出是i686这种ixxx系列的&#xff0c;都是32位系统&#xff0c;如果出现x86_64这样的&#xff0c;就是64位。

02 - 替换SetInput方法 VTK 6.0 迁移 (2013-06-30 16:22)

VTK6 引入了许多不兼容的变化&#xff0c;这其中就包括用SetInputData()和SetInputConnection()替换SetInput()方法。在先前的版本中&#xff0c;VTK4 引入了SetInput()方法&#xff0c;VTK5中引入了SetInputConnection()。 下面举一些例子&#xff1a;在如下例子中&#xff0c…

c语言中怎么 写子程序,哪位师傅知道51单片机怎样编写子程序?C语言的。在主程序里调...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼/*************************************************************************************** 外部中断0实验 *实现现象&#xff1a;下载程序后按下K3按键可以对D1小灯状态取反。注意事项&#xff1a;无。***********************…

Java Web笔记之Struts2.1 +Hibernate3.3 +Spring3.0

2019独角兽企业重金招聘Python工程师标准>>> 1、Struts2 1.1、了解Struts2 Struts2是基于MVC设计模式的Java Web框架技术之一&#xff0c;按照MVC设计思想把Java Web应用程序分为&#xff1a; 控制器层&#xff0c;包括核心控制器FilterDispatcher和业务控制器Actio…

高地址和低地址、高字节与低字节、大小端模式的转换、存储顺序

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 一、高地址和低地址 二、高字节低字节 如int a16777220&#xff0c;化为十六进制是0x01 00 00 04&#xff0c;则04属于低字节&#xff0c;01属于高字节。 三、大小端模式 &#xff08;1&#xff09;如果a在内…

漫谈数据挖掘从入门到进阶

入门&#xff1a;数据挖掘入门的书籍&#xff0c;中文的大体有这些&#xff1a;Jiawei Han的《数据挖掘概念与技术》Ian H. Witten / Eibe Frank的《数据挖掘 实用机器学习技术》Tom Mitchell的《机器学习》TOBY SEGARAN的《集体智慧编程》Anand Rajaraman的《大数据》Pang-Nin…

C语言程序设计二期末考试,C语言程序设计期末考试试卷2.doc

C语言程序设计期末考试试卷2选择题(单选题&#xff0c;每小题2分&#xff0c;共15题&#xff0c;30分)注意&#xff1a;请将答案写在每小题的题号左边1&#xff0e;一个C程序由若干个C函数组成&#xff0c;各个函数在文件中的位置为_____A______。A) 任意B) 第一个函数必须是主…

(转)Asp.Net生命周期系列一

原文地址&#xff1a;http://www.cnblogs.com/skm-blog/archive/2013/07/07/3176713.html Asp.Net生命周期对于初级甚至中级程序员来说&#xff0c;一直都是一个难题&#xff0c;很多程序员不了解生命周期&#xff0c;导致使用Asp.Net做开发感觉很不灵活&#xff0c;感觉太多东…

c语言枚举法礼泡声次数,C语言枚举类型举例

C语言枚举类型举例注&#xff1a;以下全部代码的执行环境为VC 6.0宏和枚举的区别宏和枚举之间的差别主要在作用的时期和存储的形式不同&#xff0c;宏是在预处理的阶段进行替换工作的&#xff0c;它替换代码段的文本&#xff0c;程序运行的过程中宏已不存在了。而枚举是在程序运…