冒泡排序+快速排序

冒泡排序

特点

不断比较两个相邻的元素,将值较大的元素交换到右边,如果遇到相等的值就不进行交换

大/小元素经过不断的交换浮到顶端。

思路

以[10,1,35,61,89,36,55]为例

1)第一轮排序:

  1.首先比较第一个值10和第二个值1,大小逆序了,所以交换.得到[1,10,35,61,89,36,55]

  2.再比较当前第二个值10和第三个值35,不需要交换。仍为[1,10,35,61,89,36,55]

  3.直到比较89与36,逆序,交换,得到[1,10,35,61,36,89,55]

  4.比较89与55,逆序,交换,得到[1,10,35,61,36,55,89].此时比较到最后两个数,这一轮排序完成,最后一个数一定是数组中最大的数。因此比较第二趟的时候,最后一个数不需要参与比较。

2)第二轮排序:

  1.首先比较第一个值1和第二个值10,不需要交换.得到[1,10,35,61,36,55,89]

  2.再比较当前第二个值10和第三个值35,不需要交换。仍为[1,10,35,61,36,55,89]

  3.直到比较61与36,逆序,交换,得到[1,10,35,36,61,55,89]

  4.比较61与55,逆序,交换,得到[1,10,35,36,55,61,89].此时比较到最后两个数,这一轮排序完成,最后两个数一定是数组中最大的两个数。因此比较第三趟的时候,最后两个个数不需要参与比较。

3)第三轮排序:

  以此比较相邻的数字,都不需要交换。

4)每一轮排序的次数都在减少。直到没有可以交换的元素,排序就完成了。

复杂度

冒泡排序,每一轮比较都比上一轮,少比较一次。一定程度上减少了算法量。因为每一轮排序都会找出一个较大值。

N个数字要排序完成,总共需要进行N-1轮排序。每i轮的排序次数为(N-i)次。(由于第i轮时,已有i-1个数固定在最大值部分)。

当数据正序时,只需要一轮比较就可以完成排序。最好的时间复杂度为O(n)

当数据反序时,需要进行n-1轮排序,每轮排序都需要n-i次比较,并且每次比较都必须移动记录三次来实现交换位置的效果,因此最坏的时间复杂度为O(n^2).比较次数=[n*(n-1)]/2=O(n^2)、记录移动次数=[3n*(n-1)]/2=O(n^2)

总体来说,冒泡排序的时间复杂度为O(n^2).

实现

private static void bubbleSort(int[] array){
//要遍历的次数
for(int i=0;i<array.length-1;i++){
//依次比较相邻的两个数。遍历依次过后,最大的i个数已经放在前i个位置。因此需要比较的数字-i
for(int j=0;j<array.length-i-1;j++){
//优化2:把最后一次交换的位置给len,从而减少内循环的次数。for(int j=0;j<len;j++){
//比较相邻的数字,如果逆序,则交换
if(array[j]>array[j+1]){ int t=array[j]; array[j]=array[j+1]; array[j+1]=t; //flag=0;//优化1:设置一个标志位
                            //tempPosition=j;//优化2:记录交换的位置 } }
//优化1:判断flag是否更改了值,如果没有经过交换的过程,那么flag!=0.就已经有序了
             //优化2:len=tempPosition } }

优化

1.由于思路部分,无论排序是否已经完成,都需要进行n-1次排序。

那么我们可以设置一个标志位,来表示当前数据是否已经有序(当前第i轮排序是否有交换)。减少了当数据已经有序后,没必要的排序。

2.冒泡排序中还存在,第 i 趟排的第 i 小或者大的元素已经在第 i 位上了,甚至可能第 i-1 位也已经归位了 的情况。因此再一次循环时,有许多不产生交换动作的 比较,这些都是很多余的。

同样可以设置一个标志位,记录当前第i轮排序所交换的最后一个位置的下标。在进行第i+1轮排序时,只要内循环到该下标就可以。因为后面位置的数据在上一轮排序就没有交换位置了,这一次也不会换位置了。

 

快速排序

特点

分治。

从数列中取出一个基准数;然后进行分区操作,将比这个数大的全放在它的右边,小于或等于这个数的全放在它的左边;然后对左右分区不断重复分区操作,直到各区间中只有一个数。

思路

依旧以[10,1,35,61,89,36,55]为例。

1)取第一个数10为基准数.

  1.初始时,i=0,j=6,X=a[i]=10.

    由于已将a[0]中的数保存到X,相当于在数组中a[0]的位置挖了个坑。可以将其它数据填充过来。

  2.从j开始向前找一个比X小或者等于X的数,当j=1时,符合条件。因此将a[1]挖出,再填到上一个坑a[0]中。a[0]=a[1];i++;这样a[0]坑就被填满了。此时i=1,j=1。i==j,将基准数填入a[i]中。此时数组为[1,10,35,61,89,36,55]。

  3.可以看出此时a[1]前面的数字都小于它,a[1]后面的数字都大于它。因此再对a[0]和a[2...6]两个子区间重复上述步骤。

2)对后面的区间[1,10,||35,61,89,36,55],取第一个数35为基准数。

  1.初始时,i=2,j=6,X=a[i]=35.

    将a[2]数字挖出来,留一个坑。

  2.从j开始往前找一个比X更小或等于X的数,那么直到找到j=2,才得到该数。有i==j。将基准数填入a[i]。此时数组仍为[1,10,35,61,89,36,55]。

3)对后面的区间[1,10,35,||61,89,36,55],取第一个数61为基准数。

  1.初始时,i=3,j=6,X=a[i]=61.

    将a[3]数字挖出来,留一个坑。

  2.从j开始往前找一个比X更小或等于X的数,找到j=6时,a[6]=55。将a[6]挖出,填入a[3]坑中。a[3]=a[6];i++;

    此时i=4,j=6,X=a[i]=61.

  3.从i开始往后找一个比X更大的数,找到i=4时,a[4]=89。将a[4]挖出,填入a[6]坑中。a[6]=a[5];j--;

    此时i=4,j=5,X=a[i]=61.

  4.从j开始往前找一个比X更小或等于X的数,找到j=5时,a[5]=36。将a[5]挖出,填入a[4]坑中。a[4]=a[5];i++;

    此时i=j=5。将基准数填入到a[5]坑中,数组为[1,10,35,||55,36,||61,||89].

  可以看出此时a[5]前面的数字都小于它,后面的数字都大于它。

4)接下来应该就是划分[55,26]这个区间。

复杂度

1.快速排序最优的情况是:每一次取到的元素都刚好平分整个数组。此时时间复杂度为T[n]=2T[n/2]+f(n);T[n/2]为平分后的子数组的时间复杂度,f[n]为平分整个数组所花的时间。O(nlogn)

2. 最差的情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序)。此时时间复杂度为O(n^2)

3.平均时间复杂度为O(nlogn)

实现

private static void quickSort(int[] array, int left, int right){
       if(left<right){
            //设置i,j和基准值
            int i=left,j=right,x=array[left];
            while(i<j){
                   //从右到左找到第一个小于或等于x的值
                   while(i<j && array[j]>x)
                           j--;
                   if(i<j){
                           array[i]=array[j];//将array[j]的值填到array[i]的坑中,array[j]形成新的坑
                            i++;
                   }
                   //从左到右找到第一个大于x的值
                   while(i<j && array[j]<=x)
                           i++;
                   if(i<j){
                           array[j]=array[i];//将array[i]的值填到上一步留出的array[j]的坑中,array[i]形成新的坑
                            j--;
                   }
             }      
             array[j]=x;//退出时,i==j,将x填入坑中
             quickSort(array,left,i-1);//递归左半部分
             quickSort(array,i+1,right);  //递归右半部分
     }
}                                                       

 

posted @ 2020-03-10 13:42  闲不住的小李  阅读(269)  评论(0编辑  收藏  举报