排序算法

来源:互联网 发布:网络歌手兼职 编辑:程序博客网 时间:2024/06/14 16:40

一、排序

1、任何排序的通用算法均需要Ω(NlogN)次比较。

2、被排序的对象属于Comparable类型,因此我们使用CompareTo方法对输入数据施加相容的排序。除(引用)赋值运算外,这是仅有的允许对输入数据进行的操作。在这些条件下的排序叫做基于比较的排序。

二、插入排序

1、基本思想

将n个待排序的元素看成是一个有序表和一个无序表,初始时假定第一个数为有序表,无序表中包含n-1个元素,排序过程中从无序中取一个与有序的进行比较。

2、最简单的排序算法之一是插入排序。插入排序由N-1趟排序组成,对于p=1到N-1趟,插入排序保证从位置0到位置p上的元素为已排序状态。

3、插入排序的分析

(1)由于嵌套循环的每一个都花费N次迭代,因此插入排序为O(N²),而且这个界是精准的,因为以反序的输入可以达到该界。

(2)如果输入数据已预先排序,那么运行时间为O(N),因为内层for循环的检测总是立即判定不成立而终止。

4、一般简单排序算法的下界

(1)成员是数的数组的逆序即具有性质i<j但a[i]>a[j]的序偶(a[i],a[j])。

例:输入数据34,8,64,51,32,21有6个逆序,即(34,8),(34,32),(34,21),(64,51),(64,32),(64,21),(51,32),(51,21),(32,21)。

(2)交换两个不按顺序排列的相邻元素恰好消除一个逆序,而一个排过序的数组没有逆序。

(3)插入排序的运行时间是O(I+N),I为原始数组中的逆序数。

(4)若逆序数是O(N),则插入排序以线性时间运行。

(5)可以通过计算排列中的平均逆序数得出插入排序平均运行时间精准的界。

(6)假设不存在重复元素

定理1:N个互异数的数组的平均逆序数是N(N-1)/4。

定理2:通过交换相邻元素进行排序的任何算法平均都需要Ω(7)(N²)时间。(经验上不被认可)

(7)为了使一个排序算法以亚二次或O(N²)时间运行,必须执行一些比较,特别是要对相距较远的元素进行交换。一个排序算法通过删除逆序得以向前进行,而为了有效的进行,它必须使每次交换删除不止一个逆序。


三、希尔排序

1、通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到比较相邻元素的最后一趟排序为止。

2、希尔排序使用一个序列h1,h2,…,hi,叫做增量序列。只要h1=1,任何增量序列都是可行的,在使用增量hk的一趟排序后,对于每一个i都有a[i]<=a[+hk](此时该不等式才有意义),所有相隔hk的元素都被排序,此时称文件是hk排序的。

3、一个hk排序的文件(然后将是hk-1排序的)保持它的hk排序性

4、希尔排序的最坏情形分析

(1)希尔排序的运行时间依赖于增量序列的选择。

(2)定理1:使用希尔增量时希尔排序的最坏情形运行时间为H(N²)。

(3)带有增量hk的一趟排序由hk次关于N/hk个元素的插入排序完成。

(4)使用Hibbard增量的希尔排序的最坏情形运行时间为H(N3/2)。

5、基本思想

将待排序的数组元素分成多个子序列,使每个子序列的元素个数相对较少,然后对每个子序列分别进行直接插入排序,待整个待排序列基本有序后,最后再对所有元素进行一次直接插入排序。

6、具体流程

(1)将包含n个元素的数组,分成n/2个数组序列,第一个数与第n/2 +1个数成一对。

(2)对每对数据排序。

(3)分成N/4个序列,再次排序。

(5)序列为1,排序完成。


四、堆排序

1、优先队列可以用于以O(NlogN)时间的排序,基于该思想的算法叫做堆排序,它给出了我们至今所见到的最佳的大O运行时间。

2、堆排序是一种树型选择排序方法,它的特点是:在排序过程中,将arr[0,…,n-1]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲节点与孩子节点之间的内在关系,在当前无序区中选择关键字最大(最小)的元素。

3、堆的定义

n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆。

(1)情形1:ki<=k2i且ki<=k2i+1(最小化堆或小顶堆)

(2)情形2:ki>=k2i且ki>=k2i+1(最大化堆或大顶堆)

若将和此序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端节点的值均不大于(或不小于)其左、右孩子节点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

4、堆的存储

一般用数组来表示堆,若根节点存在序号0处,i节点的父节点下标就为(i-1)/2,节点的左右子节点下标为2i+1和2i+2。

5、在我们的实现方法中将使用一个堆,但由于速度的原因避免了实际的ADT。按照通常的习惯,每一件事都是在数组中完成。第一步以线性时间建立一个堆,然后通过每次将堆中的最后元素与第一个元素交换,执行N-1次deleteMax操作,每次将堆的大小缩减1并进行下滤。当算法终止时,数组则以排好的顺序包含这些元素。

6、堆排序的分析

(1)在最坏情形下堆排序最多使用2NlogN-O(N)次比较。

(2)堆排序是一个非常稳定的算法:它使用的比较平均只比最坏情形界指出的略小。


五、归并排序

1、归并排序以O(NlogN)最坏情形时间运行,而所使用的比较次数几乎是最优的。

2、归并排序基本的操作是合并两个已排序的表,因为这两个表是已排序的,所以若将输出放到第三个表中,则该算法可以通过对输入数据一趟排序来完成。基本你的合并算法是指取两个输入数组A和B,一个输出数组C,以及三个计数器Actr、Bctr、Cctr,它们初始置于对应数组的开始端,A[Actr]和B[Bctr]中的较小者拷贝到C中的下一个位置,相关的计数器向前推进一步。当两个输入表有一个用完时,则将另一个表中剩余部分拷贝到C中。

3、合并两个已排序的表的时间是线性的,因为最多进行N-1次比较,其中N是元素的总数。

4、归并排序算法是经典的分治策略,它将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段解得的各答案修补在一起。

5、归并排序的分析

(1)归并排序的运行时间是O(NlogN)。

(2)合并两个已排序的表用到线性附加内存。

(3)归并排序的运行时间严重依赖于比较元素和在数组(以及临时数组)中移动元素的相对开销。这些开销是与语言相关的。


六、快速排序

1、快速排序是实践中的一种快速的排序算法。

2、快速排序的平均运行时间是O(NlogN),它的最坏情形性能为O(N²)。

3、快速排序之所以特别快,主要是由于非常精炼和高度优化的内部循环。

4、分治的递归算法。

5、将数组S排序的基本算法

(1)如果S中元素个数是0或1,则返回。

(2)将S中任一元素v,称之为枢纽元。

(3)将S-{v}(S中其余元素)划分成两个不相交的集合:S1={x∈S-{v}|x<=v}和S2={x∈S-{v}|x>=v}。(不是唯一)

(4)返回{quicksort(S1)}后跟v,继而返回{quicksort(S2)}.

6、选取枢纽元

(1)不选取第一个元素作为枢纽元。

(2)不选取前两个互异的关键字中的较大者作为枢纽元。

(3)随机选取枢纽元。(生成开销大)。

(4)枢纽元的最好选择是数组的中值。(难算出并且会明显减慢快速排序的速度)。

(5)一般的做法是使用左端、右端和中心位置上的三个元素作为枢纽元。


7、分割策略

(1)第一步是通过将枢纽元与最后的元素交换使得枢纽元离开要被分割的数据段。i从第一个元素开始而j从倒数第二个元素开始。

(2)在分割阶段要做的就是把所有小元素移到数组的左边而把所有的大元素移到数组的右边。小和大是相对枢纽元而言。

(3)当i在j的左边时,将i右移,移过那些小于枢纽元的元素,并将j左移,

移过那些大于枢纽元的元素。当i和j停止时,i指向一个大元素而j指向一个小元素。如果i在j的左边,那么将这两个元素互换,其效果是把一个大元素推向右边而把一个小元素推向左边。

(4)在最后一步当枢纽元与i所指向的元素交换时,在位置p<i的每一个元素都必然是小元素,这是因为或者位置p包含一个从它开始移动的小元素,或者位置p上原来的大元素在交换期间被置换了。

(5)如果i和j遇到等于枢纽元的关键字,那么就让i和j都停止。

8、小数组

对于很小的数组(N<=20)快速排序不如插入排序。

9、快速排序的分析

(1)快速排序的运行时间等于两个递归调用的运行时间加上花费在分割上的线性时间(枢纽元的选取仅花费常数时间)。

(2)最坏情况:枢纽元适中是最小元素。

(3)最好情况:枢纽元最好位于中间。

10、选择问题的线性期望时间

(1)可以修改快速排序以解决选择问题

(2)快速选择问题

①如果|S|=1,那么k=1并将S中的元素作为答案返回。如果正在使用小数组的截止方法且|S|=CUTOFF,则将S排序并返回第k个最小元素。

②选取一个枢纽元v∈S。

③将集合S-{v}分割成S1和S2

④如果k<=|S1|,那么第k个最小元必然在S1中,在这种情况下,返回quickselect(S1,k)。如果k=1+|S1|,那么枢纽元就是第k个最小元,将它作为答案返回。否则,这第k个最小元就在S2中,它是S2中的(k-|S1|-1)个最小元,我们将进行一次递归调用并返回quickselect(S2,k-|S2|-1)

(3)只做一次递归调用。

(4)最好情况和最坏情况:O(N²)。

七、桶式排序(基数排序)

输入数组A1,A2,…,An必须只由小于M的正整数组成:使用一个大小为M的称为count的数组,它被初始化为全0。于是,count有M个单元或称桶,这些桶初始化为空。当读Ai时,count[Ai]增1。在所有的输入数据读入后,扫描数组count,打印出排序后的表。


八、冒泡排序

1、基本思想

两个数比较大小,较大数下沉,较小的数冒起来。

2、过程

(1)比较相邻的两个数,如果第二个数小,就交换位置。

(2)从后向前两两比较,一直到比较最前两个数,最终最小数被交换到起始位置。

(3)重复以上过程,直到所有数排好顺序。


九、选择排序

1、基本思想

在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换。第二次遍历n-2个数,找到最小的数与第二个元素交换。第n-1次遍历,找到最小的数值与第n-1个元素交换。排序完成。




代码:点击打开链接

原创粉丝点击