江
江小南
V1
2023/04/05阅读:39主题:萌绿
【数据结构】归并排序、基数排序
1. 归并排序
1. 归并排序的定义
归并:把两个或多个已经有序的序列合并成一个。
两个称为二路归并。
多个称为m路归并。
“2路”归并—每选出一个小元素需要对比关键字1次。
对比i,j所指元素,选择更小的一个放入k所指位置。
m路归并,每选出一个元素需要对比关键字m-1次。
2. 手算模拟
核心操作:把数组内的两个有序序列归并为一个。

3. 算法实现
int *B=(int *)malloc(n*sizeof(int)); // 辅助数组B
// A[low,...,mid]和A[min+1,...,high]各自有序,将两部分归并
void Merge(int A[],int low,int mid,int high){
int i,j,k;
for(k=low;k<=high;k++){
B[k]=A[k]; // 将A中所有元素复制到B中
}
for(i=low,j=mid+1,k=i;i<=mid && j<=high;k++){ // 归并
if(B[i]<=B[j]){
A[k]=B[i++]; // 将较小值复制到A中。两个元素相等时,优先使用靠前的那个(稳定性)
}else{
A[k]=B[j++];
}
}
while(i<=mid){
A[k++]=B[i++];
}
while(j<=high){
A[k++]=B[j++];
}
}
void MergeSort(int A[],int low,int high){
if(low<high){
int mid=(low+high)/2; // 从中间划分
MergeSort(A,low,mid); // 对左半部分归并排序
MergeSort(A,mid+1,high); // 对右半部分归并排序
Merge(A,low,mid,high); // 归并
}
}

4. 算法效率分析

2路归并“归并树”——形态上就是一棵倒立的二叉树。
空间复杂度:O(n),来自于辅助数组B。
时间复杂度:O(nlog n)。
2. 基数排序
1. 过程模拟
说明:首先观察,个位可以取到0-9的9个数。指针P从前往后扫描,第一趟将个位的数字分配到对应的队列中,然后收集。第二趟按照十位采用相同的方法分配和收集,第三趟按照百位采用相同的方法分配和收集,最终得到了一个降序排列的序列。

2. 基数排序
基数排序得到递减序列的过程如下,
-
初始化:设置r 个空队列,Qr-1, Qr-2,...,Q0 -
按照各个关键字位权重递增的次序(个、十、百),对d个关键字位分别做“分配”和“收集”。 -
分配:顺序扫描各个元素,若当前处理的关键字位=x,则将元素插入Qx队尾。 -
收集:把Qr-1, Qr-2,...,Q0各个队列中的结点依次出队并链接。
说明:基数排序不是基于“比较”的排序算法。
3. 算法效率分析
空间复杂度:O(r)。需要r个辅助队列。
时间复杂度:O(d(n+r))。n:元素的个数。d:把关键字拆为d个部分。r:每个部分可能取得r个值。
稳定性:稳定。
4. 基数排序的应用
基数排序擅长解决的问题:
-
数据元素的关键字可以方便地拆分为d组,且d较小。 -
每组关键字的取值范围不大,即r较小。 -
数据元素个数n较大。
示例:某校有10000 个学生,将学生信息按年龄递减排序,那么生日可拆分为三组关键字:年(1991~2005)、月(1~12)、日(1~31)。
3. 小结
作者介绍
江
江小南
V1