每个人的实现都有不同,重要是掌握其思想。
归并排序
归并排序(MERGE-SORT)是利用归并思想实现的排序方法,该算法采用经典的分治(divide-and-conquer) 策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修 补"在一起,即分而治之)。
基本思想示意图
归并排序思想示意图 2
合并相邻有序子序列:
再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将 [4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤
应用实例
[8, 4, 5, 7, 1, 3, 6, 2]归并排序完成排序
package my.sort;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int arr[] = { 8, 4, 5, 7, 1, 3, 6, 2 };
int temp[] = new int[arr.length];
mergeSort(arr, 0, arr.length - 1, temp);
System.out.println("归并排序后=" + Arrays.toString(arr));
}
private static void mergeSort(int[] arr,int left,int right,int[] temp) {
// TODO Auto-generated method stub
if(left<right) {
int mid=(left+right)/2;
mergeSort(arr,left,mid,temp);
mergeSort(arr,mid+1,right,temp);
merge(arr,left,mid,right,temp);
}
}
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
// TODO Auto-generated method stub
int i=left;
int j=mid+1;
int t=0;
while(i<=mid && j<=right) {
if(arr[i]<=arr[j]) {
temp[t]=arr[i];
t++;
i++;
}else {
temp[t]=arr[j];
t++;
j++;
}
}
while(i<=mid) {
temp[t]=arr[i];
t++;
i++;
}
while(j<=right) {
temp[t]=arr[j];
t++;
j++;
}
t=0;
int tempLeft=left;
while(tempLeft<=right) {
arr[tempLeft]=temp[t];
t++;
tempLeft++;
}
}
}
基数排序
- 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或 bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用
- 基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法
- 基数排序(Radix Sort)是桶排序的扩展
- 将整数按位数切割成不同的数字,然后按每个位数分别比较
基数排序基本思想
- 将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
- 然后,从最低位开始,依次进行一次排序。 这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序图文说明
数组 {53, 3, 542, 748, 14, 214} 使用基数排序, 进行升序排序
代码实现
package src.my.sort;
import java.util.Arrays;
public class BasicNumSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {
10,20,39,200,45,69,320,9,58,
};
sort(arr);
}
private static void sort(int[] arr) {
// TODO Auto-generated method stub
//这是10个桶,每个桶存放数据,每个桶都是一维数组,用来存放数据
int[][] buckets=new int[10][arr.length];
//记录每个桶存放了多少个数。
int[] bucketCounts=new int[10];
//找出数组的最大值
int max=0;
for(int i=0;i<arr.length;i++) {
if(max<arr[i])max=arr[i];
}
//得出最大数的长度
int length=(max+"").length();
//1.第一轮排序:按照个位数将每个元素放入不同的桶
//遍历所有数据
for(int i=0,n=1; i<length;i++,n*=10) {
int index=0;
for(int j=0;j<arr.length;j++) {
//得每个数据的个位数
int temp=arr[j] / n %10;
//bucketCounts[temp] :记录temp号桶存放了多少个数据。初始化为0,桶元素数量对应每个桶的元素编号。
buckets[temp][bucketCounts[temp]]=arr[j];
//bucketCounts[temp] :记录temp号桶存放了多少个数据,+1 表示该桶有一个数据
bucketCounts[temp]++;
}
//从桶中取出数据
//遍历每个桶
for(int j=0; j<bucketCounts.length;j++) {
//判断桶元素的数量是否为空
if(bucketCounts[j]!=0) {
//遍历桶的每一个元素,按顺序存到原来的数组arr中。
for(int k=0; k<bucketCounts[j];k++) {
//index:原数组下标
//k:表示桶的某一个元素
arr[index]=buckets[j][k];
index++;
}
bucketCounts[j]=0;
}
}
}
System.out.println("第一轮排序后:" + Arrays.toString(arr));
}
}
基数排序的说明
- 基数排序是对传统桶排序的扩展,速度很快.
- 基数排序是经典的空间换时间的方式,占用内存很大, 当对海量数据排序时,容易造成 OutOfMemoryError 。
- 基数排序时稳定的。[注:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些
记录的相对次序保持不变,即在原序列中,r[i]=r[j],且 r[i]在 r[j]之前,而在排序后的序列中,r[i]仍在 r[j]之前,
则称这种排序算法是稳定的;否则称为不稳定的]