排序算法个人总结(2)
2016-05-21 10:35
155 查看
/*
*希尔排序
*/
希尔排序属于内部排序中的插入排序,它是不稳定的排序,时间复杂度为O(n2/3)n的2/3次幂,具体的算法步骤不再赘述,看图说话
比如有一串数字为:9,13,8,2,5,13,7,1,15,11
d1=[10/2]=5 d2=[5/2]=3 d3=[3/2]=1 第一趟五五分,第二趟三三分,第三趟增量必须为1
![](http://img.blog.csdn.net/20160521105750236?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第一趟排序结果为9,7,1,2,5,13,13,8,15,11
![](http://img.blog.csdn.net/20160521105811237?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第二趟排序结果:2 5 1 9 7 13 11 8 15 13
![](http://img.blog.csdn.net/20160521105821956?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第三趟:1 2 5 7 8 9 11 13 13 15
/*
*快速排序
*/
先看一看C程序代码
1.设置两个变量I、J,排序开始的时候I:=1,J:=N;
2.以第一个数组元素作为关键数据,赋值给X,即X:=A[1];
3.从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换;
4.从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换;
5.重复第3、4步,直到I=J;
实战:比如使用快速排序下列一串数组:49 38 65 97 76 13 27
49 38 65 97 76 13 27
i j
j对应的元素比i对应的元素小,所以交换,j不变,i后移
27 38 65 97 76 13 49
i j
i小于j,不能交换,i继续后移
27 38 49 97 76 13 65
i j
i大于j,交换,此时此刻j前移,i不变
27 38 49 97 76 13 65
i j
j小于i,交换,j不变,i后移
27 38 13 97 76 49 65
i j
i大于j,交换,i不变,j前移
27 38 13 49 76 97 65
i j
i小于j,i继续后移与j重合,第一趟排序结束,所以排序结果为
27 38 13 49 76 97 65
保证了49前面的元素都比49小,而49后面的元素都比49大
接下来对49前面的元素和后面的元素分别再次进行快速排序,
{13} 27 {38} 49 {65} 76 {97}
快速排序就是利用栈的递归方法,分治思想,栈的最大深度为log2n取值下限+1
在所有同数量级(O(nlogn))的排序方法中,其平均性能最好,若初始记录基本有序,快排将蜕化为冒泡排序,时间复杂度为O(n²),
接下来我要讲一讲我认为最复杂的一种排序——堆排序
/*
*堆排序(Heap Sort)
*/
首先介绍一下小根堆和大根堆
小根堆:每个节点小于等于左、右孩子,且根节点是序列n个元素的最小值
大根堆:每个节点大于等于左、右孩子,且根节点是序列n个元素的最大值
小根堆
![](http://img.blog.csdn.net/20160521105839878?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20160521105851295?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
性质:
1.堆是一棵采用顺序存储结构的完全二叉树,k是根节点
2.分为大(小)根堆
3.按元素值非递减排序
4.堆中任一子树也为堆
小根堆排序后得到的是非递减序列
大根堆排序后得到非递增序列
堆排序的时间复杂度为O(N*logN)
下面我们来看看堆的建立、插入元素、删除元素的具体操作
堆的建立:
记住建立过程永远是从上到下,从左到右的顺序,先来热个身
初始化序列表为{3,1,4}
![](http://img.blog.csdn.net/20160521105917014)
将1 与3进行替换后实现了堆的建立结果:
![](http://img.blog.csdn.net/20160521105923832)
下面给出以下序列,我将详细讲解如何建立一个小根堆
{49,38,65,97,76,13,27,49}
![](http://img.blog.csdn.net/20160521105934926)
将此序列看成是一棵完全二叉树,最后一个非终端结点是n/2取值下限个元素,那么筛选就从这个元素开始,如图则从第4个元素97开始筛选,97>49,交换
![](http://img.blog.csdn.net/20160521105947567)
接下来从第三个元素65开始:13<65,交换
![](http://img.blog.csdn.net/20160521110017505)
第二个元素为38,不需要调整,第一个元素为49,49<13,交换
![](http://img.blog.csdn.net/20160521110040139)
![](http://img.blog.csdn.net/20160521110056624)
再次进行调整得到了小根堆,这就是堆的建立
堆的元素插入:
如果插入2
![](http://img.blog.csdn.net/20160521110109780)
2与3进行替换得到最终结果为
![](http://img.blog.csdn.net/20160521110116842)
如果初始插入的是0,将进行两次交换,则最终结果为
![](http://img.blog.csdn.net/20160521110125249)
堆的元素删除:
如果删除根节点,将以堆中最后一个元素替代之,此时根节点左、右子树均为堆,则仅需自上至下进行调整即可,
堆排序定义:若在输出堆顶的最小值后,使得n-1个元素的序列又建成一个堆,则得到n个元素中的次小值,如此反复执行,便能得到一个有序序列,这个过程称之为堆排序
假如有以下小根堆:
![](http://img.blog.csdn.net/20160521110138796)
97是最后一个元素,与13进行替换,取出13,
![](http://img.blog.csdn.net/20160521110151030)
![](http://img.blog.csdn.net/20160521110207202)
![](http://img.blog.csdn.net/20160521110237046)
此时27为堆里最小的元素,将27与堆的最后一个元素进行交换,取出27,{13,27} ,此时97为最后一个元素,代替27
![](http://img.blog.csdn.net/20160521110252539)
调整后
![](http://img.blog.csdn.net/20160521110258977)
这种方法叫筛选法,
然后取出38,{13,27,38} 65到根节点进行调整,随后筛选出49,49,65,76,97,这就是堆排序
堆排序适合n较大的文件,深度为k的堆,筛选法关键字比较次数为2(k-1),堆排序在最坏情况下时间复杂度为0(nlogn),相比于快排,这是堆排序最大的优点
*希尔排序
*/
希尔排序属于内部排序中的插入排序,它是不稳定的排序,时间复杂度为O(n2/3)n的2/3次幂,具体的算法步骤不再赘述,看图说话
比如有一串数字为:9,13,8,2,5,13,7,1,15,11
d1=[10/2]=5 d2=[5/2]=3 d3=[3/2]=1 第一趟五五分,第二趟三三分,第三趟增量必须为1
第一趟排序结果为9,7,1,2,5,13,13,8,15,11
第二趟排序结果:2 5 1 9 7 13 11 8 15 13
第三趟:1 2 5 7 8 9 11 13 13 15
/*
*快速排序
*/
先看一看C程序代码
/* 快 速 排 序 */ #include "stdio.h" void QuickSort(int e[], int first, int end) { int i=first,j=end,temp=e[first]; while(i<j) { while(i<j && e[j]>=temp) j--; e[i]=e[j]; while(i<j && e[i]<=temp) i++; e[j]=e[i]; } e[i]=temp; if(first<i-1) QuickSort(e,first,i-1); if(end>i+1) QuickSort(e,i+1,end); } void main() { int arr[] = {49, 38, 65, 97, 76, 13, 27, 49}; int len = 8; int i; printf("before sort\n"); for(i=0; i<len; i++) printf("%d ", arr[i]); printf("\n"); QuickSort(arr, 0, len-1); printf("after sorted\n"); for(i=0; i<len; i++) printf("%d ", arr[i]); printf("\n"); }首先介绍一下思想:
1.设置两个变量I、J,排序开始的时候I:=1,J:=N;
2.以第一个数组元素作为关键数据,赋值给X,即X:=A[1];
3.从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换;
4.从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换;
5.重复第3、4步,直到I=J;
实战:比如使用快速排序下列一串数组:49 38 65 97 76 13 27
49 38 65 97 76 13 27
i j
j对应的元素比i对应的元素小,所以交换,j不变,i后移
27 38 65 97 76 13 49
i j
i小于j,不能交换,i继续后移
27 38 49 97 76 13 65
i j
i大于j,交换,此时此刻j前移,i不变
27 38 49 97 76 13 65
i j
j小于i,交换,j不变,i后移
27 38 13 97 76 49 65
i j
i大于j,交换,i不变,j前移
27 38 13 49 76 97 65
i j
i小于j,i继续后移与j重合,第一趟排序结束,所以排序结果为
27 38 13 49 76 97 65
保证了49前面的元素都比49小,而49后面的元素都比49大
接下来对49前面的元素和后面的元素分别再次进行快速排序,
{13} 27 {38} 49 {65} 76 {97}
快速排序就是利用栈的递归方法,分治思想,栈的最大深度为log2n取值下限+1
在所有同数量级(O(nlogn))的排序方法中,其平均性能最好,若初始记录基本有序,快排将蜕化为冒泡排序,时间复杂度为O(n²),
接下来我要讲一讲我认为最复杂的一种排序——堆排序
/*
*堆排序(Heap Sort)
*/
首先介绍一下小根堆和大根堆
小根堆:每个节点小于等于左、右孩子,且根节点是序列n个元素的最小值
大根堆:每个节点大于等于左、右孩子,且根节点是序列n个元素的最大值
小根堆
性质:
1.堆是一棵采用顺序存储结构的完全二叉树,k是根节点
2.分为大(小)根堆
3.按元素值非递减排序
4.堆中任一子树也为堆
小根堆排序后得到的是非递减序列
大根堆排序后得到非递增序列
堆排序的时间复杂度为O(N*logN)
下面我们来看看堆的建立、插入元素、删除元素的具体操作
堆的建立:
记住建立过程永远是从上到下,从左到右的顺序,先来热个身
初始化序列表为{3,1,4}
将1 与3进行替换后实现了堆的建立结果:
下面给出以下序列,我将详细讲解如何建立一个小根堆
{49,38,65,97,76,13,27,49}
将此序列看成是一棵完全二叉树,最后一个非终端结点是n/2取值下限个元素,那么筛选就从这个元素开始,如图则从第4个元素97开始筛选,97>49,交换
接下来从第三个元素65开始:13<65,交换
第二个元素为38,不需要调整,第一个元素为49,49<13,交换
再次进行调整得到了小根堆,这就是堆的建立
堆的元素插入:
如果插入2
2与3进行替换得到最终结果为
如果初始插入的是0,将进行两次交换,则最终结果为
堆的元素删除:
如果删除根节点,将以堆中最后一个元素替代之,此时根节点左、右子树均为堆,则仅需自上至下进行调整即可,
堆排序定义:若在输出堆顶的最小值后,使得n-1个元素的序列又建成一个堆,则得到n个元素中的次小值,如此反复执行,便能得到一个有序序列,这个过程称之为堆排序
假如有以下小根堆:
97是最后一个元素,与13进行替换,取出13,
此时27为堆里最小的元素,将27与堆的最后一个元素进行交换,取出27,{13,27} ,此时97为最后一个元素,代替27
调整后
这种方法叫筛选法,
然后取出38,{13,27,38} 65到根节点进行调整,随后筛选出49,49,65,76,97,这就是堆排序
堆排序适合n较大的文件,深度为k的堆,筛选法关键字比较次数为2(k-1),堆排序在最坏情况下时间复杂度为0(nlogn),相比于快排,这是堆排序最大的优点