一、概念
输入:一个算法必须有0个或以上的输入量
输出:一个算法应该有一个或以上的输出量,输出量是算法计算的结果
明确性:算法的描述必须无歧义,以保证算法的实际执行结果是精确匹配要求或期望,通常要求实际运行结果是确定的
有限性:依据图灵的定义,一个算法是能够被任何图灵完备系统模拟的一串运算,而图灵机只有有限个状态,有限个输入符号和有限个转移函数(命令),而一些定义更规定算法必须在有限个步骤内完成
有效性:可行性,能够实现,算法中操作都是可同过已实现的基本运算执行有限次来实现的
我们接下来排序所使用的算法大类似分治法:把一个问题分区成互相独立的多个部分分别求解的思路,以便于进行并行计算。
二、排序算法
1、冒泡排序(Bubble sort)
重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
比较相邻的两个元素。如果第一个比第二个大,就交换它们两个;
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样最大值就被固定到了最后;
重头开始新的一轮的两两比较,被固定的不比较,得到一个新最大值,固定到倒数第二位;
重复步骤1~3,直到排序完成。
作者想你扔了一个链接并不想告诉你这是动画可视化数据结构和算法~
伪代码:
流程图:
2、选择排序(selection sort)
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
以此类推,直到所有元素均排序完毕。
如图所示,是寻找最小值,相当于每轮都要和每一个元素进行对比得出最小值放入有序区。
伪代码:
流程图:
3、扑克牌算法(insertion sort)
插入排序:每一趟将一个待排序的记录,按照其关键字的大小插入到有序队列的合适位置里,知道全部插入完成。
插入排序,为啥我们叫它扑克牌算法,来我们想一下我们打扑克牌的过程:
摸牌,摸到牌Q,拿在手里
然后摸牌,摸到牌10,比Q小,插到牌Q前面,
摸牌,摸到牌K,比Q大,排到Q后
摸牌摸到牌J,比K小,比Q小,比10大,放到10后
摸牌摸到A,比K大,放到K后面
豁 我们的同花顺10JQKA就出现了,开不开森~
换成我们的语言也一样
第一步将第一个元素划分到有序区
取第二个元素和有序区的元素从后往前的进行对比
如果新元素小于有序区里被比较的元素,那么新元素移动到被比较元素的前面去
新元素依次跟有序元素对比,直到插入到合适位置
再取新元素,重复步骤2-4,直到排序完成
结合动图一起看,是不是那么一回事~
4、快排法(Quick sort)
快速排序是目前在实践中非常高效的一种排序算法,它不是稳定的排序算法,平均时间复杂度为O(nlogn),最差情况下复杂度为O(n^2)。
基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
我们先取出一个元素,称为 “基准”(pivot)
然后对数列进行一次比较排序,与基准作比较,比基准值小的摆放在基准前面,比基准值大的摆在基准的后面(相同的数可以到任一边)。这次操作结束之后,这个基准就基本位于数列的中间位置。这个称为分区(partition)操作;
然后我们在对基准两边的区,分别进行1-2操作,取出不同的基准,分成不同区,最终达成有序排列。
根据动图我们很好理解,第一次以15为基准,分了左右两个区,接着是5,4,3依次为基准,最终确定了右边的序列,接着在来分左边区,步骤一样。排序就完成啦。
5、计数排序(Counting Sort)
我在此之前介绍的排序是比较排序,需要两两比较的,但是计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外的桶内。
- 如图,我们根据最大值做了1-9的桶,然后将数列按照对应数值进桶,桶里进行记次,进来几个就几次,出桶也一样,有几次就出几次桶,这样一次进桶出桶操作就排完序了。
伪代码:
6、 桶排序 (Bucket sort)
桶排序的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序。
设置空桶的范围,比如1-100,101-200这样子的范围;
接着遍历all输入数据,并且把数据一个一个放到对应的桶里去;
对每个不是空的桶进行排序;
从不是空的桶里把排好序的数据拼接起来,排序就完成了。
和计数排序的区别就在于桶,桶排序是每个桶是一个值,而这里是一个范围,同时桶排序还需要在桶内进行二次排序。
7、基数排序(Radix sort)
我们设想一下,假如我们要排序1-10万,难道我们还要排10万个桶吗?
所以我们就可以使用基数排序,它是基于进制的一个排序。
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。
先分配所有元素的个位,按照个位分配到0-9
先入先出,这样有了第一次基于个位数的排序
接着分配十位,百位,直到当前进制所有元素都为0
通过多次的进桶出桶保证了当前进制的大小排序,通过每一次进桶出桶均是先进先出,因而保证了每一次的排序是基于前一次排序的。
8、堆排序
我们先来了解一下几个概念
最大堆:
最大堆中的最大元素出现在根节点即堆顶
堆中每个父节点的元素值都大于等于其孩子的节点(若存在)
最大堆调整:保持最大堆性质,是创建最大堆的核心子程序
堆排序则是利用了最大堆可以记录最大值这样一个特性。
最初将待排序序列(R1,R2,……Rn)进行一次最大堆调整,得到一个堆顶(最大值)
将堆顶R1与最后一个元素Rn交换,分成一个新的完全二叉树(R1-Rn-1)和一个有序区(Rn)
对新的完全二叉树继续最大堆调整,得到新的最大堆后重复第二个步骤,如此反复执行,直到有序区里n-1个元素,此时排序完成。
以上~~ 欢迎纠错~