常见排序算法合集2

上篇文章实现了冒泡,选择,插入,希尔,归并,上一篇:常见排序算法合集1

这一篇则实现了剩下的快速,堆排,计数,桶排,基数

话不多说,直接上代码,代码中都有注释,相信不难理解:

package day01;

import java.util.Random;

public class AlgTest {
	static Random r=new Random();
	static int[] array=new int[10];
	public static void main(String[] args) {
		for(int i=0;i<10;i++) {
			array[i]=r.nextInt(100);
		}
		//调用各大算法来排序
		printArr(array);
		//快速排序
		//int left=0,right=array.length-1;
		//QuickSort(array,left,right);
		//堆排序
		//HeapSort(array);
		//计数排序
		//array=CountSort(array);
		//桶排序
		//array=BucketSort(array);
		//基数排序
		array=RadixSort(array);
		printArr(array);
	}
	/*
	 * 循环打印,用于检验
	 */
	private static void printArr(int[] arr) {
		int length=arr.length;
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+" ");
		}
		System.out.println();
	}
	/*
	 * 快速排序:averageTime(O(nlogn)   bestTime(O(nlogn))  wrostTime(O(n^2))  space(O(logn))  不稳定  不需要外部空间
	 *原理:设置一个基准值,将小于基准值的元素放左边,大于基准值的元素放右边,然后有对两边的数据进行上述相同的操作!
	 */
	private static void QuickSort(int[] arr, int left, int right) {
		if(left>right) return;
		int base=arr[left],i=left,j=right;
		while(i!=j) {
			//首先从右向左查找
			while(arr[j]>=base && i<j) {j--;}
			//然后从左向右查找
			while(arr[i]<=base && i<j) {i++;}
			//如果i<j,则交换两个数的位置
			if(i<j) {
				int temp=arr[i];
				arr[i]=arr[j];
				arr[j]=temp;
			}
		}
		//将基准值和中间值交换
		arr[left]=arr[i];
		arr[i]=base;
		//基准值前后的两个区继续上述步骤
		QuickSort(arr, left, i-1);
		QuickSort(arr, i+1, right);
	}
	/*
	 * 堆排序   averageTime(O(nlogn)   bestTime(O(nlogn))  wrostTime(O(nlogn))  space(O(1))  不稳定  不需要外部空间
	 *原理:以完全二叉树的形式存储数据,同时要求父结点的值总是小于/大于子节点
	 *代码理解:对堆排序时,我们从堆尾开始,已经排好序的元素不用再管,将堆头元素置换到堆尾后把另外的元素进行堆调整,重复此步骤!
	 */
	private static void HeapSort(int[] arr) {
		//构造初始堆
		int length=arr.length;
		for(int i=length/2-1;i>=0;i--) {
			HeadAdjust(arr,length,i);
		}
		//对堆进行排序,让最大值放在堆尾,每进行一次都需要进行堆调整
		for(int i=length-1;i>=1;i--) {
			//将堆头和当前位置进行更换,因为每次调整后堆头都是未排序的最大值
			int temp=arr[0];
			arr[0]=arr[i];
			arr[i]=temp;
			//对前面的元素进行堆调整
			HeadAdjust(arr, i, 0);
		}
	}
	//进行堆调整
	private static void HeadAdjust(int[] arr, int length, int i) {
		//temp代表当前父节点的值,index代表temp的左儿子
		int k=i,temp=arr[i],index=2*k+1;
		while(index<length) {
			//如果存在右儿子
			if(index+1<length) {
				//如果右儿子的值大于左儿子,则将操作对象转移到右儿子
				if(arr[index]<arr[index+1]) {
					index++;
				}
			}
			//如果儿子(左儿子和右儿子中较大值)大于父节点,就将该儿子变为父节点
			if(arr[index]>temp) {
				arr[k]=arr[index];
				k=index;
				index=2*k+1;
			}else break;
		}
		//将原本父节点的值赋给当前的结点
		arr[k]=temp;
	}
	/*
	 * 计数排序    averageTime(O(n+k)   bestTime(O(n+k))  wrostTime(O(n+k))  space(O(k))  稳定  需要外部空间
	 * 原理:使用辅助数组,里面的值表示原数组中对应元素出现的次数。
	 * 改进:辅助数组的值表示原数组中对应元素在新数组中对应的下标。
	 */
	private static int[] CountSort(int[] arr) {
		int length=arr.length;
		//获取数组的最大值
		int max=getMax(arr)+1;
		//array数组中下标i的元素对应原数组中值为i的个数
		int[] array=new int[max];
		//用来保存新数组
		int[] Arr=new int[length];
		for(int i=0;i<length;i++) {
			array[arr[i]]++;
		}
		//更改记录数组array里面的值,array的值不再对应原数组中元素的个数,而是对应在新数组中对应的位置+1
		for(int i=1;i<max;i++) {
			array[i]+=array[i-1];
		}
		//倒序储存
		for(int i=length-1;i>=0;i--) {
			Arr[--array[arr[i]]]=arr[i];
		}
		return Arr;
	}
	private static int getMax(int[] arr) {
		int max=arr[0],length=arr.length;
		for(int i=1;i<length;i++) {
			if(arr[i]<0) throw new RuntimeException("数组必须都为正整数");
			if(arr[i]>max) max=arr[i];
		}
		return max;
	}
	/*
	 * 桶排序   averageTime(O(n+k)   bestTime(O(n+k))  wrostTime(O(n^2))  space(O(n+k))  稳定  需要外部空间
	 * 原理:设置若干个桶,将数组中的元素放进某些桶中,对含有数据的桶进行内部排序,然后将所有的桶合并
	 */
	private static int[] BucketSort(int[] arr) {
		//设定桶的数量为10,这里我们根据十位数来进行区别
		int Bucket=10,length=arr.length;
		Integer[][] Arr=new Integer[Bucket][length];
		for(int i=0;i<length;i++) {
			int bucket=arr[i]/Bucket;
			for(int j=0;j<length;j++) {
				if(null==Arr[bucket][j]) {
					Arr[bucket][j]=arr[i];
					break;
				}
			}
		}
		//桶排序
		for(int i=0;i<Arr.length;i++) {
			//使用插入排序
			for(int j=1;j<Arr[i].length;j++) {
				if(null == Arr[i][j]) break;
				int k=j-1,temp=Arr[i][j];
				for(;k>=0 && Arr[i][k]>temp;k--) {
					Arr[i][k+1]=Arr[i][k];
				}
				Arr[i][k+1]=temp;
			}
		}
		//合并所有的桶
		for(int i=0,index=0;i<Arr.length;i++) {
			for(int j=0;j<Arr[i].length;j++) {
				if(null != Arr[i][j]) {
					arr[index++]=Arr[i][j];
				}
			}
		}
		return arr;
	}
	/*
	 * 基数排序    averageTime(O(n*k)   bestTime(O(n*k))  wrostTime(O(n*k))  space(O(n+k))  稳定  需要外部空间
	 * 原理:首先获得数组中元素的最大位数,然后对数组进行位数的计数排序,从个位一直到最大位,最后将所有的桶拼接即可
	 */
	private static int[] RadixSort(int[] arr) {
		int max=getMaxBit(arr);
		int length=arr.length;
		int bucket[]=new int[length];
		//对每一位进行计数排序
		for(int i=1;i<=max;i++) {
			//count用来记录每一位上的元素个数
			int count[]=new int[length];
			for(int j=0;j<length;j++) {
				int num=getFigure(arr[j],i,max);
				count[num]++;
			}
			//同计数排序一样进行优化
			for(int j=1;j<length;j++) {
				count[j]+=count[j-1];
			}
			//将每个桶中的元素进行倒叙存储,原理同计数排序
			for(int j=length-1;j>=0;j--) {
				int num=getFigure(arr[j],i,max);
				bucket[--count[num]]=arr[j];
			}
			//这里必须放在循环里面,因为排序的效果是迭代的,前者会影响后者!
			for(int j=0;j<length;j++) {
				arr[j]=bucket[j];
			}
		}
		return arr;
	}
	//获取元素在某个位数上的数字
	private static int getFigure(int number, int i,int max) {
		//index数组形式为{1,10,100,...,10^(max-1)}
		int[] index=new int[max];
		index[0]=1;
		int j=1;
		while(max>1) {
			index[j]=index[j-1]*10;
			max--;j++;
		}
		return (number/index[i-1])%10;
	}
	//获得数组中最大的位数
	private static int getMaxBit(int[] arr) {
		int max=arr[0],length=arr.length;
		for(int i=1;i<length;i++) {
			if(arr[i]<0) throw new RuntimeException("数组必须都为正整数");
			if(arr[i]>max) max=arr[i];
		}
		int index=0;
		while(max>0) {
			index++;
			max/=10;
		}
		return index;
	}
}

好了,十大常用算法都已经实现了,最重要的是要理解它的思想!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值