排序算法——其他排序(归并排序,计数排序,基数排序)

归并排序

思想:

将序列不断切分为子序列,将子序列排序,然后归并为新的有序序列,直至最后

public static void merge(int[] arr, int low, int high){
	if(low < high){
		int mid = ((high - low) >> 1) + low; //这么求中间数可以防止(high+low)/2可能出现的加法超出int范围的错误
		merge(arr,low,mid);
		merge(arr,mid+1,high);
		mergeSort(arr,low,mid,high);
	}
}

public static void mergeSort(int[] arr, int low, int mid, int high){
	int[] temp = new int[high - low + 1];
	int i,j,k; //i表示序列里左子序列的起始索引,j表示序列里右子序列的起始索引,k表示结果数组的起始索引
	for(i = 0, j = mid + 1, k = 0, i <= mid && j <= high; k++)
		temp[k] = arr[i] < arr[j] ? arr[i++] : arr[j++]; //比较两子序列数据,将叫嚣着复制进temp中,并把索引右移
	
	//当有一个子序列遍历完而另一个子序列没遍历完时,将另一个子序列剩下的元素直接复制进temp中
	while(i <= mid) temp[k++] = arr[i++];
	while(j <= high) temp[k++] = arr[j++];
	
	//将结果数组复制回原数组
	for(int m = 0; m < temp.length; m++)
		arr[m + low] = temp[m];  
}

复杂度分析:

最好,最坏,平均复杂度都是O(nlogn),空间复杂度为O(n)

稳定性:

该排序算法不改变相同元素的相对位置,所以稳定的。


计数排序

思想:

适合数量大,但是数字范围小的序列

public static void countSort(int[] arr, int minV, int maxV){ // minV和maxV是该序列里的最小值和最大值
	int[] result = new int[arr.length];
	int[] bucket = new int[maxV - minV + 1];

	for(int i = 0; i < arr.length; i++)
		bucket[arr[i] - minV]++;
	
	//统计bucket数组的前j位共有多少个数
	for(int i = 1; i < bucket.length; i++)
		bucket[i] += bucket[i-1];
		
	//按子关键字对指定的数据进行排序 ,因为开始是从前往后放,现在从后往前读取,保证计数排序的稳定性
	for(int i = arr.length - 1; i >= 0; i--)
		result[--bucket[arr[i]- minV]] = arr[i];
}

稳定性:

该排序算法不改变相同元素的相对位置,所以是稳定的。


基数排序

思想:

分最高位优先法和最低位优先法,这里使用的是最低位优先法。从低位到高位将以位的角度将每个数排序,整个基数排序里对每一位的排序都是一次计数排序

public static void radixSort(int[] arr, int d){ // d是该序列里最大数的位数
	int[] result = new int[arr.length];
	int[] bucket = new int[10];

	for(int i = 0; i < d; i++){
		int division = (int)Math.pow(10,i);
		Arrays.fill(bucket,0); 	        //重置bucket数组 
		System.arraycopy(arr,0,result,0,arr.length); //将arr中的元素复制到result数组中  
	
	    //计算每个待排序数据的子关键字  
		for(int j = 0; j < arr.length; j++){
			int num = (result[j] / division) % 10;
			bucket[num]++;
		}
		
		//统计bucket数组的前j位共有多少个数
		for(int j = 1; j < bucket.length; j++)
			bucket[j] += bucket[j-1];

		//按子关键字对指定的数据进行排序 ,因为开始是从前往后放,现在从后往前读取,保证基数排序的稳定性
		for(int j = arr.length - 1 ; j >= 0; j--){
			int num = (result[j] / division) % 10;
			arr[--bucket[num]] = result[j];
		}
	}
}

//下面这种写法也可以
public static void radix(int[] arr, int d){
        int[] result = new int[arr.length];
        int[] bucket = new int[10];
        for(int i = 0; i < d; i++){
            int division = (int)Math.pow(10, i);
            for(int j = 0; j < arr.length; j++){
                int num = arr[j] / division % 10;
                bucket[num]++;
            }

            for(int j = 1; j < bucket.length; j++)
                bucket[j] += bucket[j-1];

            for(int j = arr.length - 1; j >= 0; j--){
                int num = arr[j] / division % 10;
                result[--bucket[num]] = arr[j];
            }
            System.arraycopy(result, 0, arr, 0, arr.length);
            Arrays.fill(bucket, 0);
        }
}

稳定性:

该排序算法不改变相同元素的相对位置,所以是稳定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值