- 归并排序
思想:归并排序与上述基于交换,选择排序的思想不一样。“归并”的含义是将两个或两个以上的有序列表组合成一个新的有序表。假定待排序表含有n个记录,则可以看成是n个有序的字表,每个字表长度为1,然后两两归并,得到n/2个长度为2或1的有序表;再两两归并,…,如此重复,直到合并成一个长度为n的有序表位置,这种排序方法成为2-路归并排序,如下为归并排序示例。
Merge()的功能是将前后相邻的两个有序表归并成为一个有序表的算法。设两段有序表A[low…mid],A[mid…high]存放在同一顺序表中小林的位置上,先将它们复制到辅助数组B中。每次从对B中的两个端取出一个记录进行关键字的比较,江较小者放入A中,将数组B中有一段的下表超出其对应的表长时(即该段的所有元素已经完全复制到A中),将另一段中的剩余部分直接复制到A中。
- java代码实现:
/**
* @author:cch
* @description: 归并排序
* @date 2020/12/17
*/
public class MergeSort {
public static void main(String[] args) {
int arr[] = { 8, 4, 5, 7, 1, 3, 6, 2 };
mergeSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void mergeSort(int[] arr, int l, int r) {
if (l == r) {
return;
}
int mid = l + ((r - l) >> 1);
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
private static void merge(int[] arr, int l, int mid, int r) {
int[] help = new int[r + 1 - l];
int i = 0;
int p1 = l;
int p2 = mid + 1;
// 两边做比较
while (p1 <= mid && p2 <= r) {
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
// 左边全部完了
while (p2 <= r) {
help[i++] = arr[p2++];
}
// 右边全部完了
while (p1 <= mid) {
help[i++] = arr[p1++];
}
for (i = 0; i < help.length; i++) {
arr[l + i] = help[i];
}
}
}
- 性能分析:
空间效率:Merge()操作中,辅助空间刚好要占用n个单元,所以归并排序的空间复杂度为O(n)。
时间效率:每一趟归并的时间复杂度为O(n),共需进行log2n趟归并,所以算法的时间复杂度为O(nlog2n)。 - 稳定性:由于Merge()操作不会改变相同关键字记录的相对次序,所以2-路归并排序算法是一个稳定得的排序算法。
- 基数排序
思想:基数排序
是一种很特备的排序方法,他不是基于比较进行排序的,而是采用多关键字排序思想(即基于关键字各位的带下进行排序的),借助“分配”和“收集”两种操作对单逻辑关键字进行排序。技术排序又可以分为最高位优先(MSD)排序和最低位优先(LSD)排序,如下为归并排序示例。
- java代码实现:
/**
* @author:cch
* @description: 基数排序
* @date 2020/12/17
*/
public class RadixSort {
public static void main(String[] args) {
int[] arr = {63, 157, 189, 51, 101, 47, 141, 121, 157, 156,
194, 117, 98, 139, 67, 133, 181, 12, 28, 0, 109};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* 高位优先法
*
* @param arr 待排序列,必须为自然数
*/
private static void radixSort(int[] arr) {
//待排序列最大值
int max = arr[0];
int exp;//指数
//计算最大值
for (int anArr : arr) {
if (anArr > max) {
max = anArr;
}
}
//从个位开始,对数组进行排序
for (exp = 1; max / exp > 0; exp *= 10) {
//存储待排元素的临时数组
int[] temp = new int[arr.length];
//分桶个数
int[] buckets = new int[10];
//将数据出现的次数存储在buckets中
for (int value : arr) {
//(value / exp) % 10 :value的最底位(个位)
buckets[(value / exp) % 10]++;
}
//更改buckets[i],
for (int i = 1; i < 10; i++) {
buckets[i] += buckets[i - 1];
}
//将数据存储到临时数组temp中
for (int i = arr.length - 1; i >= 0; i--) {
temp[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
buckets[(arr[i] / exp) % 10]--;
}
//将有序元素temp赋给arr
System.arraycopy(temp, 0, arr, 0, arr.length);
}
}
}