归并排序
思想:
将序列不断切分为子序列,将子序列排序,然后归并为新的有序序列,直至最后
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);
}
}
稳定性:
该排序算法不改变相同元素的相对位置,所以是稳定的。