目录
1.归并排序
1.1.算法思想
归并:把两个或者多个有序的序列表合并成一个(m路归并,每选出一个元素需要关键字为m - 1个)
将相邻的两个有序表归并为一个有序表
1.将顺序表中每两个相邻元素分为一组,进行排序:分组(49、38)(65、97)(66、13)(27)
2.将重复1操作直到序列有序:分组(38、49、65、97)(13、76、27)
3.整个数组为一组,进行排序后,整组有序
1.2.代码
//全局变量,申明一个大小为n + 1的数组(可以容纳下所有的数组元素)
elemtype *temp = (elemtype*)malloc(sizeof(elemtype) * (n + 1));
void Merge(int arr[], int low, int mid, int high){
//将arr数组元素复制到temp中
for (int k = low; k <= high; k++) temp[k] = arr[k];
int i, j, k;
//遍历数组
for (i = low, j = low, k = mid + 1; j <= mid && k <= high; i++) {
//将j和k指向的元素中更小的那个插入表中,并且其对应的指针往后移动
if (temp[j] <= temp[k]) arr[i] = temp[j++]; //两个子表若元素相同,则优先选择左子表
else arr[i] = temp[k++];
}
//将剩余元素插入到表中
while (j <= mid) arr[i++] = temp[j++];
while (j <= mid) arr[i++] = temp[k++];
}
void MergeSort(int arr[], int low, int high){
if (low < high) {
int mid = low + high / 2;
//对左子表进行排序
MergeSort(arr, low , mid);
//对右子表进行排序
MergeSort(arr, mid + 1, high);
//对当前整个表进行排序
Merge(arr, low, high);
}//if
}
1.3.时间复杂度和稳定性
1.时间复杂度:O(nlog2n)
A.归并的过程类似二叉树,树高即为归并总次数→O(log2n)向上取整
B.每次归并的时间复杂度为O(n),指针需要从头到尾遍历一次数组
2.空间复杂度:O(n),辅助数组B需要复制数组元素
3.稳定性:稳定。左右两个数组中若同时出现相同元素,则优先将左边的元素加入数组中
2.基数排序
2.1.算法思想
不基于比较的算法
基于关键字的各个位数的大小进行排序
1.初始化r个队列,按照关键字的权值递增的顺序(个十百),进行关键字总位数分配和收集
2.分配:遍历各个元素,根据当前轮次的关键字和当前元素的关键字位插入相应的链表中
3.收集:将各个队列中的元素依次出队,并首尾相接形成新的序列
2.2.手算实现过程
1.初始状态,申明十个队列分别表示当前位数上的数字为0 - 9
2.以个位进行匹配,按当前数字的个位入队到相应的队列中
3.为得到递减序列,按9 - 0 的顺序将各个队列中的元素依次出队,并首尾相接形成新的序列(实现按个位递减)
4.基于3中结果,以十位进行匹配,按当前数字的十位挂到入队相应队列中。因为已经对个位排序,因此,每个队列中的元素按照个位递减的顺序排列
5.为得到递减序列,按9 - 0 的顺序将各个队列中的元素依次出队,并首尾相接形成新的序列(实现按十位递减、十位相同按个位递减)
6. 基于5中结果,以十位进行匹配,按当前数字的十位入队相应队列中。因为已经对十位排序,因此,每个队列中的元素按照十位递减的顺序排列
6.为得到递减序列,按9 - 0 的顺序将各个队列中的元素依次出队,并首尾相接形成新的序列(实现按百位递减、百位相同按十位递减、十位相同按个位递减)
2.3.时间复杂度和稳定性
1.空间复杂度:需要r个队列,每个队列需要的仅是头尾指针。O(r)
2.时间复杂度:O(d(n + r))
A.需要进行d趟(关键字个数)O(d)
B.每趟进行一次分配遍历 n 个元素O(n),一趟收集遍历r个队列O(r)。O(n + r)(可以为每个队列结构体中设置一个队尾元素指针,遍历队列的过程中将队尾指针的next域指向下一个队列的队首元素,不需要遍历队列中全部元素)
3.稳定性:稳定
2.4.基数排序的应用
例:生日(日→月→年)
1.数据元素可以被拆分为d个关键字(d不宜过大)(反例:身份证)
2.每个关键字的取值范围不大(反例:中文名字,虽然只有几个字,但是每个字有几千种可能)
3.数据元素的个数 n 很大(例子:给全中国人的身份证排序)