排序算法系列第一篇

         写程序时,经常会需要对数组进行排序。为了节省上网查找的时间,笔者花费了一些时间,专门对一些排序算法做了分析,并在本文中给出了总结,一方面方便自己日后使用,同时也方便大家用的时候能够在这里就找到合适自己的方法。

一、鸽巢排序

算法步骤:

1) 给定一个待排序数组,创建一个备用数组(鸽巢),并初始化元素为0,备用数组的索引即是待排序数组的值。

2)把待排序数组的值放入“鸽巢”里,即备用数组的索引

3)把鸽巢里的值再次送回到待排序数组

//鸽巢排序
  public static	void PigeonholeSort(int[]array) //用N表示array.length
	{ 
		int n = 256;//这里本应该是待排序数组的最大值+1,作为测试所以假设备用数组的长度为256
		int j = 0;
		int[] b = new int[n];
	    for(int i = 0; i < array.length; i++){
	    	  b[array[i]]++; //备用数组的索引即是待排序数组的值
	    }
	    for(int i = 0; i <b.length; i++){
	    	  for(int k = 0; k < b[i]; k++) {
	    		    array[j] = i; //把鸽巢里的值再次送回到待排序数组
	    		    j++;
	    	  }
	    	 
	    }
	} 

鸽巢排序的平均时间复杂度为O(N+n).

鸽巢排序算法的限制条件有两个:

一是数组中存储的必须是int类型或者转换为int类型不丢失真实数据的数据类型;

二是必须事先预测到数组中存储的最大元素,在程序运行过程中求得后因为不是const值,所以无法用int b[Max] = {0};来初始化数组b.

 

二、计数排序

算法步骤:

1)找出待排序数组a中的最大元素值max和最小元素值min然后用k=max-min+1作为计数数组C的长度;

2)统计待排序数组a中元素值等于i的元素出现的次数,存入数组C的第i项;

3)对所有的计数累加(从C中的下标值为1的元素开始,每一项和前一项相加);

4)反向填充目标数组b,将每个元素i放在新数组b下标值为C(i)的那一项,每放一个元素,就将C(i)减1.

public class SortAlgorithm {
		//计数排序
	 private static int[] CountingSort(int[] a) {
		 
	     int[] b = new int[a.length];//目标数组
	      
	     //计算a中最大最小值,以确定计数数组C的长度
	     int max = a[0];
	     int min = a[0];
	     for(int i=1;i<a.length;i++) {   // n=a.length
	       if(a[i]>max) {
	          max = a[i];
	       } else if(a[i]<min){
	          min = a[i];
		  }
	   }
		 int k = max-min+1;//计数数组C的长度
		 int[] C = new int[k];


	   //统计数组a中每个值为i的元素出现的次数,存入数组C的下标为i-min的项
	   for(int i=0;i<a.length;i++) {
	        C[a[i]-min]++; //存储相对位置
	   }

	   //对所有的计数累加
	   for(int i=1;i<k;i++) {
	         C[i]=C[i-1]+C[i];
	    }

	   //反向填充目标数组b
	  for(int i = a.length-1;i>=0;i--) {
	    int q = a[i]-min;
	     b[C[q]-1] = a[i];
	     C[q] = C[q]-1;
	  }
	  return b;
  }



	public static void main(String[] args){
	  int[]a={49,38,65,97,76,13,27,49};   
	  int[] b = CountingSort(a);   
      for(int i=0;i<b.length;i++){   
          System.out.print(b[i]+" ");   
      }   
	}

}

 计数排序算法的时间复杂度为O(n+k),适用于待排序数组的每个元素值都大于等于0。

3、快速排序算法

基本思想:

1)首先选择一个基准数X

2)通过一趟将要排序的数据分割成独立的两部分,左边部分的所有数据要小于或者等于基准数,右边部分的所有数据要大于基准数。

3)然后按照此方法对两部分分别进行快速排序,整个过程可以递归进行,以此达到所有数据编程有序。

public class SortAlgorithm {
	
		 //快速排序
	public static void QuickSort(int s[], int L, int R){
	     if (L < R){
	         int i = L,j = R,x =s[L];
	         while (i < j){
	        	 while(i < j && s[j] >= x)//从右向左找第一个小于x的数
	                j--;
	        	 
	             if(i < j)
	            	s[i++] =s[j];
	             
	             while(i < j && s[i] <x)//从左向右找第一个大于等于x的数
	                i++;

	             if(i <j)
	                s[j--] = s[i];
	             }
	           s[i] =x;

	         // 递归调用
	         QuickSort(s, L,i - 1); //左半部分
	         QuickSort(s,i + 1, R);//右半部分
	     }
	 }

	public static void main(String[] args){
	  int[] a={49,38,65,97,76,13,27,49};   
	  QuickSort(a,0,a.length-1);
      for(int i=0;i<a.length;i++){   
          System.out.print(a[i]+" ");   
      }   
	}

}

 快速排序算法在最坏的情况下退化为冒泡排序,时间复杂度为O(n^2),实际应用中的平均时间复杂度为O(n*logn)。

 

4、冒泡排序

       冒泡排序的过程很简单:首先将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则将两个记录交换位置;然后比较第二个记录的关键字和第三个记录的关键字;以此类推,直至第N-1个记录和第N个记录的关键字进行过比较为止。上述过程为第一趟排序,其结果使得关键字最大的记录被安置在最后一个记录的位置上;然后进行第二趟排序,对前N-1个记录进行同的操作,以此类推。

void BubbleSort(int[] a,int n){//n=a.length

     int temp;
     for(int i=0;i<n-1;i++){                                
           for(int j=n-1;j>i;j--){
                if(a[i]>a[j]){ 
                    temp=a[i];
                    a[i] = a[j];
                    a[j] = temp;
                 } 
            }       
      }
 }

时间复杂度:若初始序列为“正序”序列,则只需要进行一趟排序,需要进行N-1次关键字间的比较,且不移动记录;若为“逆序”序列,则需要进行N-1趟排序,需进行N(N-1)/2次比较,并做等数量级的记录移动。因此总的时间复杂度是:O(N^2)。

 

以上方法已经验证,如有不足之处,欢迎大家指正!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值