插入排序,希尔排序,冒泡排序,快速排序之间的比较

1.快速排序和希尔排序不是稳定的排序方式,冒泡排序和插入排序是稳定的排序方式;

2.各种排序算法的分析和说明?

2.1-----冒泡排序

 

冒泡排序就是把小的元素往前调(或者把大的元素往后调)。注意是相邻的两个元素进行比较,而且是否需要交换也发生在这两个元素之间。

所以,如果两个元素相等,我想你是不会再无聊地把它们俩再交换一下。

如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个元素相邻起来,最终也不会交换它俩的位置,所以相同元素经过排序后顺序并没有改变。

所以冒泡排序是一种稳定排序算法。

public static int[] bubbleSort(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;  
				temp=arr[j]; 
				arr[j]=arr[i];
				arr[i]=temp;  
			}  
		}  
	}  
	return arr; 
}


2.2--------快速排序    快速排序有两个方向,左边的i下标一直往右走(当条件a[i] <= a[center_index]时),其中center_index是中枢元素的数组下标,一般取为数组第0个元素。

而右边的j下标一直往左走(当a[j] > a[center_index]时)。

如果i和j都走不动了,i <= j, 交换a[i]和a[j],重复上面的过程,直到i>j。交换a[j]和a[center_index],完成一趟快速排序。

在中枢元素和a[j]交换的时候,很有可能把前面的元素的稳定性打乱,比如序列为 5 3 3 4 3 8 9 10 11 

现在中枢元素5和3(第5个元素,下标从1开始计)交换就会把元素3的稳定性打乱。

所以快速排序是一个不稳定的排序算法,不稳定发生在中枢元素和a[j]交换的时刻。 

 


 

publicstaticvoidquickSort(inta[],intstart,intend)
{inti,j;
i=start;
j=end;
if((a==null)||(a.length==0))
return;
while(i<j){
while(i<j&&a[i]<=a[j]){//以数组start下标的数据为key,右侧扫描
j--;
}
if(i<j){//右侧扫描,找出第一个比key小的,交换位置
inttemp=a[i];
a[i]=a[j];
a[j]=temp;
}
while(i<j&&a[i]<a[j]){//左侧扫描(此时a[j]中存储着key值)
i++;
}
if(i<j){//找出第一个比key大的,交换位置
inttemp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
if(i-start>1){
//递归调用,把key前面的完成排序
quickSort(a,start,i-1);
}
if(end-i>1){
quickSort(a,i+1,end);//递归调用,把key后面的完成排序
}
}
 
 


2.3----------插入排序

 

     插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,也就是第一个元素(默认它有序)。

比较是从有序序列的末尾开始,也就是把待插入的元素和已经有序的最大者开始比起,如果比它大则直接 插入在其后面。

否则一直往前找直到找到它该插入的位置。如果遇见一个与插入元素相等的,那么把待插入的元素放在相等元素的后面。

所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序仍是排好序后的顺序,所以插入排序是稳定的。 

---------------------------直接插入排序

每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序属于稳定的排序,最坏 时间复杂性为O(n^2), 空间复杂度为O(1);
public class MainTest {
public static void main(String[] args) {
int [] a = { 46 , 58 , 15 , 45 , 90 , 18 , 10 , 62 };
int n = a.length;
int i, j;
for (i = 0 ; i < n; i++) {
int temp = a[i];
for (j = i; j > 0 && temp < a[j- 1 ]; j--) {
a[j] = a[j - 1 ];
}
a[j] = temp;
}
for (i= 0 ;i<n;i++){
System.out.print(a[i]+ "\t" );
}
}
 
-----------------折半插入排序
          在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素大,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。[1]
     折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为O(n^2),与直接插入排序算法相同。附加空间O(1)。[1]
 
public class MyBinaryInsertionSort
{
public static void main(String[] args)
{
// 待排序的数组
int[] array = { 1, 0, 2, 5, 3, 4, 9, 8, 10, 6, 7};
binaryInsertSort(array);
// 显示排序后的结果。
System.out.print("排序后: ");
for(int i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
}
// Binary Insertion Sort method
private static void binaryInsertSort(int[] array)
{
for(int i = 1; i < array.length; i++)
{
int temp = array[i];
int low = 0;
int high = i - 1;
while(low <= high)
{
int mid = (low + high) / 2;
if(temp < array[mid])
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
for(int j = i; j >= low + 1; j--)
{
array[j] = array[j - 1];
}
array[low] = temp;
}
}
} [2]

2.4   希尔排序

 

先取一个小于n的整数d1作为第一个 增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行 直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

该方法实质上是一种分组插入方法

  比较相隔较远距离(称为 增量)的数,使得数移动时能跨过多个元素,则进行一次比 [1] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的 排序算法中实现了这一思想。算法先将要排序的一组数按某个 增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当 增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为 增量,以后每次减半,直到增量为1。

     由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

 

package com.sort;
//不稳定
public class 希尔排序 {
     
     public static void main(String[] args) {
         int [] a={ 49 , 38 , 65 , 97 , 76 , 13 , 27 , 49 , 78 , 34 , 12 , 64 , 1 };
         System.out.println( "排序之前:" );
         for ( int i = 0 ; i < a.length; i++) {
             System.out.print(a[i]+ " " );
         }
         //希尔排序
         int d = a.length;
         while ( true ){
             d = d / 2 ;
             for ( int x= 0 ;x<d;x++){
                 for ( int i=x+d;i<a.length;i=i+d){
                     int temp = a[i];
                     int j;
                     for (j=i-d;j>= 0 &&a[j]>temp;j=j-d){
                         a[j+d] = a[j];
                     }
                     a[j+d] = temp;
                 }
             }
             if (d == 1 ){
                 break ;
             }
         }
         System.out.println();
         System.out.println( "排序之后:" );
         for ( int i = 0 ; i < a.length; i++) {
             System.out.print(a[i]+ " " );
         }
     }
}

 

  

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值