排序算法之冒泡,选择,插入,快排

例如:待排序序列     5,4,3,7,2,7,(目的是升序排列)

1,冒泡排序:

排n趟,每趟只是将原序列变得相对有序,随着趟数的增加,有序性也得到提升,最终完全有序

 5,4,3,7,2,7

第一趟,5>4,交换---》   4,5,3,7,2,7

               5>3 ,交换---》 4,3,5,7,2,7

               5<=7,不交换

              7>2  ,交换,---》4,3,5,2,7,7

第一趟冒泡结果:4,3,5,2,7,7 , (其中  4,5,7,7有序)

第二趟冒泡结果(重复第一次的比较方式):3,4,2,5,7,7(其中3,4,5,7,7有序

第三趟冒泡结果:3,2,4,5,7,7(其中3,4,5,7,7和2,4,  有序

第四趟冒泡结果:2,3,4,5,7,7(其中2,3,4,5,7,7有序

第五趟冒泡:没有发生交换,冒泡到此结束

规律:每趟比较都是将大的元素交换到后面

   第一趟比较,就能将最大元素交换到最后

   第二趟比较,就能将第二大元素交换到倒数第二个位置

   ******

   那么每趟比较的元素数量是呈现 --1的趋势,这和插入排序有点像

java代码实现:


    public int [] testBubbleSort(int []data){
    
     int maxPos=0;
     for(int i=0;i<data.length;i++)
     {
//         data.length-1-i及其之后的元素是排好序的
         for(int j=0;j<data.length-i-1;j++)
         {
             if(data[j]>data[j+1])
             {
                 //将最大位置与i交换
                 int temp =data[j];
                 data[j]=data[j+1];
                 data[j+1]=temp;
             }
         }

     }
        return data;

    }

2,选择排序:

使用一个单位的空间来存放当前比较对象序列中的第一个元素,该趟的目标是找出这段比较序列中的最小元素及其下标,将其交换这段比较序列头部

第一趟:比较序列是  5,4,3,7,2,7

初始minPos=0;

   minVal=array[0]=5

在这一趟比较中,会出现  4<minVal=5   需要更新最小值:minVal=4,minPos=1

                                               3<minVal=4 需要更新最小值:minVal=3,minPos=2

                                                2<minVal=3 需要更新最小值:minVal=2,minPos=4

第一趟比较完之后,将第一趟找出的最小元素交换到序列头部

也就是 第一趟比较之前:   5,4,3,7,2,7,

第一趟比较之后交换结果:2,4,3,7,5,7

第二趟比较序列是:2, 4,3,7,5,7

比较交换后结果: 2,3,4,7,5,7

第三趟比较序列是:2,3,4,7,5,7

第i趟比较序列是:

array[i-1],array[i],....,array[array.length-1]

每比较完一趟,下一趟比较的元素数量比上一趟少一个

java代码实现

 private  int [] selectSort(int []array){
// 额外空间 1,这里未开辟新数组
       if(null==array||1==array.length){
           return array;
       }
       int minPos=0;
       int minVal=array[0];

       for(int i=0;i<array.length-1;i++){

           for(int j=i+1;j<array.length;j++){
               if(array[j]<=minVal){
                   minVal=array[j];
                   minPos=j;

               }
           }
           //找到这一次的最小值,此趟的第一个元素交换 i
           array[minPos]=array[i];
           array[i]=minVal;
           //更新最小值为下一趟的第一个元素  i+1
            minPos=i+1;
            minVal=array[i+1];
       }



        return array;
   }

3,插入排序:

模拟摸牌的过程,手中的牌始终是有序的,需要申请空间array.length

java代码实现:

  //插入排序:相当于摸牌

    private int[] insertSort(int [] array){
        if(null==array||0==array.length){
            return array;
        }
        int []sorted=new int[array.length];//记录有序数组
        sorted[0]=array[0];
        int itemSortedCount=1;//记录已经排好序的元素个数
        for(int i=1;i<array.length;i++){
            if(sorted[itemSortedCount-1]<=array[i]){
                sorted[itemSortedCount]=array[i];
                itemSortedCount++;
            }
            else{
                //将排好序的数组元素往后挪动,插入新元素
             int j=itemSortedCount;
             while(j>0 &&(sorted[j-1]>array[i]) ){
                 sorted[j]=sorted[j-1];
                 j--;

             }
             sorted[j]=array[i];
             itemSortedCount++;

            }
        }
        return sorted;
    }

生成随机数组的代码:

 public static  int []getArrayRand(int length)
    {
        int []result=new int[length];
        for(int i=0;i<result.length;i++)
        {
            result[i]=(int)(Math.random()*10000);
        }
        return result;
    }

此时速率比较:快排>插入排序>选择排序>冒泡排序

20万条元素排序时间(毫秒):

插入: 5593

选择:1,6547(冒泡的改良,避免了大量无效的交换)

冒泡:8,2772(慢如蜗牛,主要原因是大量无效的交换)

快速:47(飞一样的感觉)

4,快速排序:

两个标记i,和j分别指向数组两端

选取一个k值,表示比较的对象

目的是为了将比k小的元素,放到k的左侧,比k大的元素放在k的右侧

待排序数组:

  i         j      
下标 0 1 2 3 4 5      
元素 5 4 3 7 2 7      

i=0,j=5

k=array[i]=5;

part1 从右往左比较:

j=5时,array[ j ]=7>k,不交换

j--;

j=4时,array[ j ]=2<k=5,交换

目前数组:

  i       j        
下标 0 1 2 3 4 5      
元素 2 4 3 7 5 7      

k=array[ j ] =5;

part2  从左往右比较

此时:i=0;j=4

k=5>array[i]=2,不交换

i++

k=5>array[i]=array[1]=4,不交换

i++

k=5>array[i]=array[2]=3,不交换

i++

k=5<=array[i]=array[3]=7,交换

交换结果:

        i j        
下标 0 1 2 3 4 5      
元素 2 4 3 5 7 7      

现在从右往左比较,回到part1

k=array[i]=array[3]=5

k=5<array[j]=7,不交换

j--

出现i和j碰头,结束以k=5的比较,对k=5这一元素的左右两侧分别执行上述操作,part1+part2

第一次快排的结果:

        i j        
下标 0 1 2 3 4 5      
元素 2 4 3 5 7 7      

数组1:2,4,3

数组2:7,7

5,4,3,7,2,7,

java代码实现

 public void quickSort(int []array,int from,int to){
       if(from<0||to>=array.length){
           return;
       }
        int kVal=array[from];
        int kPos=from;
        int low=from;
        int high=to;
      while(low<high){
          //从右往左找比kVal小的元素
          while(low<high && array[high]>=kVal ){
              high--;
          }
          //从右往左出现比kVal小的元素了,交换
          if(high>low ){
              array[kPos]=array[high];
              array[high]=kVal;
              kPos=high;
              low++;
          }
          //从左往右,找比kVal大的元素
          while(low<high && array[low]<=kVal ){
              low++;
          }
          //找到比kVal大的元素,交换
          if(low<high ){
              array[kPos]=array[low];
              array[low]=kVal;
              kPos=low;
              high--;
          }
      }


      //到此时,kPos左边全是比kVal小的元素
       //           右边全是比kVal大的元素
       //怎样判断是否需要继续对子分组是否进行快排呢?如果low与high还是在数组的两端,说米此次快排,未发生排序,自然就是有序了
          if(low>from){
              quickSort(array,from,kPos-1);
          }
      if(high<to){
           quickSort(array,kPos+1,to);
       }




   }

猜你喜欢

转载自blog.csdn.net/qq_36922927/article/details/81606809