常用排序算法

 

一、交换排序

1、冒泡排序:冒泡排序是交换排序的一种,对于一个需要进行排序的数组来说,冒泡排序从头开始对相邻的两个数之间进行比较,将较大(或较小)的数通过交换往后移动,也就是说第一次将最大(或最小)的那个数移动到最后,第二次将第二大(或第二小)的数移动到最后。

例如: 4 2 3 1 

第一次:2 3 1 4

第二次:2 1 3 4

第三次:1 2 3 4

冒泡排序需要使用两个for循环,假如数组a有n个数:

for(int i=0;i<n-1;i++)

  for(int j=0;j<n-i-1;j++)

    if(a[j]>a[j+1])

    {

      int temp=a[j];

      a[j]=a[j+1];

      a[j+1]=temp;

    }

时间复杂度:如果采用上述的代码,使用了两个for循环,时间复杂度计算为(n-1)+(n-2)+(n-3)+……+1=n*(n-1)/2,即O(n*n)。最坏和平均时间复杂度都是O(n*n),最好的时间复杂度是O(n),这时候需要具备两个条件,一个是数组本身已经排好序,同时算法进行了优化,如果数组本身已经是排好序了,那么不管怎么循环,都不会出现交换的情况,所以可以在外层循环中的第一次循环的时候判断是否有发生交换,如果没有发生交换,那么表示数组已经排好序了,这时候就退出不再循环,那么就只执行了n-1次代码,时间复杂度是O(n)。

2、快速排序:快速排序是采用分治法,从数组中取出一个基准数,将比基准数小的放左边,大的放右边,再采用递归分别对两边进行同样的操作。至于怎么把小的放左边,大的放右边,时间复杂度是O(nlog2 n),最坏是O(n*n),基本思路是这样的:

下标:   0     1      2     3

数值:   3     4      2     1

从后往前遍历第一次: 

    0    1      2     3

    1  4   2     3

从前往后遍历第一次:

    0    1     2     3

    1    3     2     4

从后往前遍历第二次: 

    0    1      2     3

    1  2   3     4

 

(1)定义三个参数,第一个数的下标i,最后一个数的下标j,基准数s,i和j表示需要去遍历的区间,在i下标之前的数都小于基准数,j下标之后的数都大于基准数,i和j在遍历的过程是变化的,当i和j碰头的时候,表示基准数左边的都小于它,右边的都大于它

(2)取第一个数作为基准数,从 j 开始向 i 遍历,找到第一个比基准数小的数,然后交换位置,更新 j 的值,这时候下标 j 后面的数都比基准数大

(3)接下来从 i 向 j 遍历,找到第一个比基准数大的数,再交换位置,更新 i 的值,这时候 i 下标之前的数都比基准数小

(4)重复(2)(3)步的操作,对 i 到 j 的区间进行遍历,直到 i 和 j 碰头,这时候基准数左边的数都比它小,后边的都比它大

(5)对左右两个区间执行同样的操作,直到各区间只有一个数

二、插入排序

1、插入排序:插入排序将要排列的数组分成已排序的部分和未排序的部分,将未排序部分的数拿出来,插入到已排序部分中的合适位置中,插入的时候,需要去移动排序部分的数。基本思路如下:

(1)将第一个数作为已排序的部分,将后面的数作为未排序的部分。取出第二个数,判断和第一个的大小关系,如果第一个数比第二个数大,那么将第一个数后移,然后将第二个数放在第一个的位置。这时候已排序部分就有两个数了。

(2)接着取出第三个数,在已排序部分找到合适的插入位置,将已排序部分该位置以及之后的数都往后移动,然后将取出的数放入该位置。

(3)重复操作,直接将未排序部分的数全都插入到已排序部分。

 

时间复杂度:在最坏的情况下,每次插入都要去遍历所有的已排序部分,时间复杂度计算为:1+2+3+……+n-1,和冒泡算法一样,因此,最坏和平均时间复杂度是O(n*n)。当数组是倒序的,这时候每次从未排序部分取出一个数到已排序部分中去比较都只需要比较一次,总共插入n-1次,比较的次数是n-1,所以最好的时间复杂度是O(n)

 

2、希尔排序:插入排序的改进版,希尔排序实际上就是分组去执行插入排序,比方说:

(1)数组个数为 n ,初始增量为n/2,增量就是要分成多少组,这里分成n/2组,对每个组进行插入排序之后

(2)缩小增量为(n/2)/2,然后继续执行插入排序,直到只剩下一组。

最坏时间复杂度是O(n*n),跟插入排序一样,最好是O(n),平均是O(n1.5),增量的大小定义会直接影响排序

 

三、选择排序

1、选择排序:选择排序和插入排序类似,同样将数组分成已排序和未排序两部分,每次从未排序中找到最大的或者最小的数去放在已排序部分的末尾。时间复杂度是O(n*n)。

2、堆排序:假如要构造一个从上往下升序的二叉树

(1)先将数组写成二叉树的格式(建堆)

(2)从下往上,把最大的数往上交换到根节点,然后交换根节点和最深处的叶子节点的元素(构造大跟堆,交换堆顶元素和末尾元素)

(3)从下往上,把第二大的数往上升到根节点,再往下替换,以此类推(继续调整堆结构,交换元素)。

时间复杂度为:O(nlogn)

 

四、归并排序

1、二路归并排序:将一个待排序的数组分成两个组,分别对每个组继续分组,直到每组只剩下一个,这样每个组都是有序的,然后一直往上合并相邻的组。思路是分组排序再合并。

 

posted @ 2018-04-22 23:16  ST没有C  阅读(282)  评论(0编辑  收藏  举报