Java-冒泡排序

1.原理

比较两个相邻的元素,将值大的元素交换至右端。

2.思路

依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,
将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,
直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。

分析:N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,
所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数

3.代码实现

/**
  * 算法一
  */
 public int[] bubbleSort(int[] arr){
     //比较趟数
     for (int i = 0; i < arr.length - 1; i++) {
         System.out.println("第"+(i+1)+"次排序");
         //每一趟比较的次数
         for (int j = 0; j < arr.length - 1 - i; j++) {
             System.out.println(arr[j] +" 和 "+arr[j+1]+" 比较");
             if(arr[j] > arr[j+1]){
                 int temp = arr[j];
                 arr[j] = arr[j+1];
                 arr[j+1] = temp;
             }
         }
         System.out.print("第"+(i+1)+"次排序后:");
         printArr(arr);
         System.out.println();
     }
     return arr;
 }


 /**
  * 冒泡排序优化算法1
  * 设置一个标志,如果这一趟发生了交换,则为true,否则为false。
  * 明显如果有一趟没有发生交换,说明排序已经完成。
  * @param arr
  * @return
  */
 public int[] bubbleSort1(int[] arr){

     //比较趟数
     int n = arr.length - 1;
     //发生了交换就为true, 没发生就为false,第一次判断时标志位必须为true。
     boolean flag = true;
     for (int i = 0; i < n; i++) {
         System.out.println("第"+(i+1)+"次排序");
         if(!flag){
            continue;
         }
         flag = false;
         for (int j = 0; j < n - i; j++) {
             System.out.println(arr[j] +" 和 "+arr[j+1]+" 比较");
             if(arr[j] > arr[j+1]){
                 int temp = arr[j];
                 arr[j] = arr[j+1];
                 arr[j+1] = temp;
                 //交换过数据
                 flag = true;
             }
         }
         System.out.print("第"+(i+1)+"次排序后: ");
         printArr(arr);
         System.out.println();
     }
     return arr;
 }

  /**
  * 现在有一个包含1000个数的数组,仅前面100个无序,后面900个都已排好序且都大于前面100个数字
  * 那么在第一趟遍历后,最后发生交换的位置必定小于100,且这个位置之后的数据必定已经有序了,也就是这个位置以后的数据
  * 不需要再排序了,于是记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。如果是对于上面的冒泡排序算法2来说,
  * 虽然也只排序100次,但是前面的100次排序每次都要对后面的900个数据进行比较,而对于现在的排序算法3,
  * 只需要有一次比较后面的900个数据,之后就会设置尾边界,保证后面的900个数据不再被排序。
  * 冒泡排序优化算法2
  */
  public int[] bubbleSort2(int[] arr){

      //flag来记录最后交换的位置,也就是排序的尾边界
      int flag = arr.length - 1;
      int i = 0;
      while (flag > 0){
          int k = flag;
          System.out.println("尾边界值: "+k);
          System.out.println("第"+(i+1)+"次排序");
          flag = 0;
          for (int j = 0; j < k; j++) {
              System.out.println(arr[j] +" 和 "+arr[j+1]+" 比较");
              //前面的数字大于后面的数字就交换
              if(arr[j] > arr[j+1]){
                  int temp = arr[j];
                  arr[j] = arr[j+1];
                  arr[j+1] = temp;
                  //表示交换过数据,记录最新的尾边界
                  flag = j + 1;
              }
          }
          System.out.print("第"+(i+1)+"次排序后: ");
          printArr(arr);
          System.out.println();
          i++;
      }
      return arr;
  }

4.测试

  @Test
  public void test(){
  //  int arr[] = {0,1,1,2,3,3,4,8,7,6,12,22,65};
      int arr[] = {6,3,8,2,9,1};
      System.out.println("排序前");
      printArr(arr);

      int[] data = bubbleSort2(arr);

      System.out.println("排好序后");
      printArr(data);
  }

  public void printArr(int[] arr){
      for (int i = 0; i < arr.length; i++) {
          System.out.print(arr[i]+" ");
      }
      System.out.println();
  }

5.总结

冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。
如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较
除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,
第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,
每进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。

用时间复杂度来说:
1.如果我们的数据正序,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,
即:Cmin=n-1;Mmin=0;所以,冒泡排序最好的时间复杂度为O(n)。

2.如果很不幸我们的数据是反序的,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),
且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
冒泡排序的最坏时间复杂度为:O(n2)。  
综上所述:冒泡排序总的平均时间复杂度为:O(n2)。

猜你喜欢

转载自blog.csdn.net/rjgcszlc/article/details/79749010