数据结构--基数排序(桶排序)

基数排序(桶排序)

1.定义:

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,借以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog®m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法(截取自百度百科)。

2.原理

/**
	 * 基数排序的思想 
	 *  首先定义10个桶  ,然后对数组中的数据进行按个位、十位、百位、千位 来分配到相应的桶中
	 *  1.比如: arr这样一个数组数据  那么第一轮按照每位数据的个位数进行分桶
	 *  桶的位数    0    1   2   3    4    5    6  7  8  9
	 *   数据:          32   3   54        256
	 *   					    724      16
	 *    经过第一轮排序后位:  32,3,54,724,256,16
	 *  2.  第二轮按照十位来分
  	 *	 桶的位数       0    1   2   3    4    5    6  7  8  9
  	 *    数据:  3   16  724  32       54
  	 *    							 256
  	 *    进过第二轮排序后:  3,16,724,32,54,256
  	 *   3.第三轮按照百位来分
  	 *   桶的位数       0    1   2   3    4    5    6   7    8    9
  	 *     数据:  3       256                    724
  	 *			16
  	 *			32
  	 *			54
  	 *		进过第三轮排序后:  3,16,32,54,256,724
  	 *  说明: 
  	 *  1.排序的次数按照数组中最大位数来的
  	 *  2.当位数不足时,在位数前补0
  	 *  
  	 *  需注意:
  	 *    1.定义10个桶 刚好对应0-9这个10个数字  然后每个桶需要记录桶里面数据的个数

3.代码实现

下面是每一步推导的过程,结合上面的算法思想去理解就会很容易了。

	public static void radixSort(int[] arr) {
   	
   	
   	//首先需要定义桶的数量
   	int [][] msg=new int[10][arr.length];
   	//用来记录每个桶装了几个数据
   	int [] backElment=new int[10];
   	for(int j=0;j<arr.length;j++) {
   		//取出个位数据
   		int temp=arr[j]/1 % 10;
   		//放到对应的桶中
   		msg[temp][backElment[temp]]=arr[j];
   		backElment[temp]++;
   	}
   	//按照这个桶的顺序(一维数组的下标一次取出数据,放入到原来的数组中)
   	int index=0;
   	//遍历每一个桶,并将桶中的数据,放到原数组中
   	for(int i=0;i<backElment.length;i++) {
   		//如果桶中有数据,则将桶中数据循环放入原数组中
   		  if(backElment[i]!=0) {
   			  //循环该桶 即第I桶(即第i个一维数组) 放入
   			  for(int k=0;k<backElment[i];k++) {
   				   arr[index++]= msg[i][k];  
   			  }
   		  }
   		  //取出数组后将该桶置为0
   		  backElment[i]=0;
   	}
   	
   	System.out.println("第一轮排序后的结果:===>"+Arrays.toString(arr));
   	
   	
   	for(int j=0;j<arr.length;j++) {
   		//取出个位数据
   		int temp=arr[j]/10 % 10;
   		//放到对应的桶中
   		msg[temp][backElment[temp]]=arr[j];
   		backElment[temp]++;
   	}
   	//按照这个桶的顺序(一维数组的下标一次取出数据,放入到原来的数组中)
   	 index=0;
   	//遍历每一个桶,并将桶中的数据,放到原数组中
   	for(int i=0;i<backElment.length;i++) {
   		//如果桶中有数据,则将桶中数据循环放入原数组中
   		  if(backElment[i]!=0) {
   			  //循环该桶 即第I桶(即第i个一维数组) 放入
   			  for(int k=0;k<backElment[i];k++) {
   				   arr[index++]= msg[i][k];  
   			  }
   		  }
   		  backElment[i]=0;
   	}
   	System.out.println("第二轮排序后的结果:===>"+Arrays.toString(arr));
   	
   	for(int j=0;j<arr.length;j++) {
   		//取出个位数据
   		int temp=arr[j]/100 % 10;
   		//放到对应的桶中
   		msg[temp][backElment[temp]]=arr[j];
   		backElment[temp]++;
   	}
   	//按照这个桶的顺序(一维数组的下标一次取出数据,放入到原来的数组中)
   	 index=0;
   	//遍历每一个桶,并将桶中的数据,放到原数组中
   	for(int i=0;i<backElment.length;i++) {
   		//如果桶中有数据,则将桶中数据循环放入原数组中
   		  if(backElment[i]!=0) {
   			  //循环该桶 即第I桶(即第i个一维数组) 放入
   			  for(int k=0;k<backElment[i];k++) {
   				   arr[index++]= msg[i][k];  
   			  }
   		  }
   	}
   	System.out.println("第三轮排序后的结果:===>"+Arrays.toString(arr));
   	
   } 	 
最终代码
/**
	 * 优化后的桶排序算法
	 * @param arr
	 */
	public static void radixSort2(int[] arr) {
		// 桶排序的循环次数是根据数组中最大位数的来定义
		// 1 查找到数组中最大的数据 获取位数 我们可以吧第一位定义为最大的数字信息
		int maxValue = arr[0];
		for (int j = 1; j < arr.length; j++) {
			if (maxValue < arr[j]) {
				maxValue = arr[j];
			}
		}
		// 得到循环的次数
		int arrCount = (maxValue + "").length();
		// 首先需要定义桶的数量
		int[][] msg = new int[10][arr.length];
		// 用来记录每个桶装了几个数据
		int[] backElment = new int[10];

		for (int i = 0, j = 1; i < arrCount; i++, j *= 10) {
			for (int k = 0; k < arr.length; k++) {
				// 取出个位数据
				int temp = arr[k] / j % 10;
				// 放到对应的桶中
				msg[temp][backElment[temp]] = arr[k];
				backElment[temp]++;
			}
			// 按照这个桶的顺序(一维数组的下标一次取出数据,放入到原来的数组中)
			int index = 0;
			// 遍历每一个桶,并将桶中的数据,放到原数组中
			for (int l = 0; l < backElment.length; l++) {
				// 如果桶中有数据,则将桶中数据循环放入原数组中
				if (backElment[l] != 0) {
					// 循环该桶 即第I桶(即第i个一维数组) 放入
					for (int k = 0; k < backElment[l]; k++) {
						arr[index++] = msg[l][k];
					}
				}
				// 取出数组后将该桶置为0
				backElment[l] = 0;
			}
			//System.out.println("第"+(i+1)+"轮排序后的结果:===>"+Arrays.toString(arr));
		}

	}

4 测试性能

public static void main(String[] args) {
		int [] arr= {54,16,32,3,256,724,1024};
		
		radixSort(arr);
		System.out.println("--------------");
	
		
		//我们用数据来测试一下基数排序(桶排序)的性能
		int []data=new int[8000000];
		for(int i=0;i<8000000;i++) {
			data[i]=(int) (Math.random()*80000);
		}
		SimpleDateFormat format=new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
		Date str01=new Date();
		System.out.println("排序前--------------"+format.format(str01));
		radixSort2(data);
		Date str02=new Date();
		System.out.println("排序后--------------"+format.format(str02));
	}

由于笔记本性能较差 ,测试8000000条数据只需要1秒钟即可完成。当然机器性能越好,测试数据条数也可更多。
以上如有不妥,欢迎指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章