选择排序和冒泡排序小议

来源:互联网 发布:如何使用万德数据库 编辑:程序博客网 时间:2024/06/14 10:51
 

百度百科

选择排序:     每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。

冒泡排序:     依次比较相邻的两个数,将小数放在前面,大数放在后面。第一趟结束,将最大的数放到了最后。第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。 由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。

从以上说明我们看到,选择排序和冒泡排序,其思想方法相似,即每一趟就找到了为排序元素的最值(最大值或最小值),然后使其就位,不再予以考虑; 进行下一趟循环。

其初始源代码如下:

//选择排序 最小值

public static void select_sort(int[] arr)
{
  for(int i=0; i<arr.length-1; i++)
  {
   for(int j=i+1; j<arr.length; j++)
   {
    if(arr[i]>arr[j])
    {
     int temp = arr[i];
     arr[i] = arr[j];
     arr[j] = temp;
    }
   }
  }
}

//冒泡排序 最大值
public static void bubble_sort(int[] arr)
 {
  for(int i=0; i<arr.length; i++)
  {
   for(int j=0;j<arr.length-i-1; j++)
   {
    if(arr[j]>arr[j+1])
    {
     int temp = arr[j];
     arr[j] = arr[j+1];
     arr[j+1] = temp; 
    }
   }
  }
 }
 
我们可以对其稍加优化:
//选择排序 最小值
public static void select_sort(int[] arr)
 {
  for(int i=0; i<arr.length-1; i++)
  {
   int min = i;
   for(int j=i+1; j<arr.length; j++)
   {
    if(arr[min]>arr[j])
    {
     min = j;
    }
   }
   if(min!=i)
   {
    int temp = arr[min];
    arr[min] = arr[i];
    arr[i] = temp;
   }
  }
 }
 
//冒泡排序 最大值
public static void bubble_sort(int[] arr)
 {
  for(int i=0; i<arr.length; i++)
  {
   int max = 0;;
   for(int j=0;j<arr.length-i-1; j++)
   {
    if(arr[max]<arr[j+1])
    {
     max = j+1;
    }
   }
   if(max!=arr.length-i-1)
   {
    int temp = arr[max];
    arr[max] = arr[arr.length-i-1];
    arr[arr.length-i-1] = temp;
   }
  }
 }
如果我们认真的看一下上面稍微优化后的程序就会知道,他们都是每一趟定义了一个变量用以存储最值的角标。他们虽然表面看是一个用首元素和之后的每一个元素进行比较,求得最值;一个用相邻元素比较,求得最值。但是当我们定义了一个临时存储最值的变量时,我们发现但是最值变量在和后面的每一个元素比较,最终找出最值。所以我不得不遗憾的说:选择排序和冒泡排序实质上是同一种算法。我们不管用哪种算法,只要都以升序或降序排序,其空间复杂度和时间复杂度是完全相同的。
 
下面我们来研究一个简单需求: 求得一个给定数组的最小值和最大值。
//求得一个数组中元素的最大值和最小值
public static String getMaxAndMin(int[] arr)
 {
  int min = 0;
  int max = 0;
  for(int i=1; i<arr.length; i++)
  {
   if(arr[min]>arr[i])
   {
    min = i;
   }
   if(arr[max]<arr[i])
   {
    max = i;
   }
  }
  
  return "max="+arr[max]+", min="+arr[min];
 }
 
我们发现,从一个数组中获得最大值和最小值,只需遍历数组一次即可。我们试想一下我们再对数组排序的时候是不是我们遍历数组一次,把最大值或最小值取得,放到首位获末位。那么我们何不像上面一样遍历数组一次同时取得数组的最大值和最小值,然后一个放首位,一个放末位呢?这样我们遍历数组一次就排好了两个值,岂不是更快?
 
但是我们实现后会发现数组被我们排的乱七八糟的,这是怎么回事,我们的理论应该是正确的啊,正确的理论得到了错误的结果?其实不然,有时候,同一种东西给我们带来便利的同时,也带来了麻烦。我们想象一下,如果max和min都在对方的位置上,我们的代码首先要min就位(我们把min和max交换了一下),然后我们要max就位(我们又把max和min交换了一下),结果??我们什么都没干!还有一种情况,max和min有一方在对方的位置上,我们就要注意谁先就位谁后就位的问题了;不然你交换的数据很可能在你不知道的情况下已经改变。
 
看下面的代码:
 
//基于选择和冒泡的双向排序算法
public static void arraySort(int[] arr)
 {

  for(int j=0; j<(arr.length-1)/2;j++)
  {
//min记录最小值角标,max记录最大值角标;min就位角标为j,max就位角标为arr.length-1-j;由于当min>=max时排序已完成,即
//可退出;即j>=arr.length-1-j得到j<(arr.length-1)/2。
   int min = j;
   int max = j;
//内循环完成一次,起始位置+1,末位置-1
   for(int i=j+1; i<=arr.length-1-j; i++)
   {
//两个if语句取得最大值和最小值角标。
    if(arr[min]>arr[i])
    {
     min = i;
    }
    if(arr[max]<arr[i])
    {
     max = i;
    }
   }
//如果min和max都在就位位置上,不必移动,本次排序结束。
   if(min==j && max==arr.length-j-1)
   {
    continue;
   }
//只有min在就位位置上,只需使max就位即可。
   else if(min==j)
   {
    int temp = arr[max];
    arr[max] = arr[arr.length-1-j];
    arr[arr.length-1-j] = temp;
    continue;
   }
//只有max在就位位置上,只需使min就位即可。
   else if(max==arr.length-j-1)
   {
    int temp= arr[min];
    arr[min] = arr[j];
    arr[j] = temp;
    continue;
   }
//min和max都在对方就位位置上,交换位置。
   if(min==arr.length-j-1 && max==j)
   {
    int temp = arr[min];
    arr[min] = arr[max];
    arr[max] = temp;
   }
//只有一方在对方就位位置上或都不在对方就位位置上。
   else
   { 
//只有max在min就位位置上,必须先max就位,然后min就位。
    if(max==j)
    {
     
     int temp = arr[max];
     arr[max] = arr[arr.length-1-j];
     arr[arr.length-1-j] = temp;
     
     temp= arr[min];
     arr[min] = arr[j];
     arr[j] = temp;
    }
//1.只有min在max就位位置上,必须先min就位,然后max就位。
//2.min和max都不在对方就位位置上,就位先后皆可。
    else
    {
     int temp= arr[min];
     arr[min] = arr[j];
     arr[j] = temp;
     
     temp = arr[max];
     arr[max] = arr[arr.length-1-j];
     arr[arr.length-1-j] = temp;
    }
   }
  }
 }
 
我们看到,上面的双向排序算法由于循环次数更少,优于单独的选择排序或冒泡排序,但是其逻辑设计却稍加复杂。所以我们看待事情,要从优劣两个方面权衡考虑。
原创粉丝点击