一、归并排序
1、基本思路
归并的含义是将两个或者两个以上的有序表组合成一个新的有序表。有2路归并和多路归并多种算法。下面以2路归并为例分析:假设一个序列有n个记录,则可以看做是有n个有序的子表,然后这n个字表两两归并,得到n/2或者(n/2)+1个有序子表,在两两归并.......直到只有一个子表,且表长为n时候结束。
2、示例代码
输出结果:2 6 34 35 43 45 65 74 75 85#include<iostream> #include<stdlib.h> using namespace std; int *B = (int *)malloc(10 * sizeof(int)); //分配内存辅助空间 void Merge(int A[], int low, int mid,int high) { int i,j,k; for (int k = low;k <= high;k++) //把A中的所有元素都赋值到B中 B[k] = A[k]; for (i = low,j = mid + 1,k = i;i <= mid&&j <= high;k++) { if (B[i] <= B[j]) //比较B中左右两段的元素大小 A[k] = B[i++];//将较小值赋值给A else A[k] = B[j++]; } while (i <= mid) A[k++] = B[i++]; //B中左端为检测完,复制到A中 while (j <= high) A[k++] = B[j++]; //若B中右端为检测完,复制到A中 } 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); } } void main() { int A[10] = {43,34,6,74,2,85,35,75,45,65}; MergeSort(A, 0, 9); for (int i = 0;i < 10;i++) cout << A[i] << " "; while (1); }
3、算法分析
(1)空间复杂度:辅助空间为malloc函数申请的内存空间,共有n个单元,则空间复杂度为O(n)。
(2)时间复杂度:每一趟Merge()归并的时间复杂度为O(n)。共有log2(n)趟归并,则算法时间复杂度为O(n*log2(n))。
(3)稳定性:Merge()函数并不会改变连个相同关键字的相对顺序,所以算法稳定。
注意:一般而言,对于N个元素进行k路归并时,排序趟数为logk(N)次。
二、基数排序
1、基本思路
基数排序不是基于比较进行排序的,而是采用多关键字排序思想,借助“分配”和“收集”两种操作对单逻辑关键字进行排序。基数排序又分为最高位优先排序(MSD)和最低位优先排序(LSD)。下面举例说明最低位优先排序:
假设原始序列为: 329 457 657 839 436 720 355
第一趟排序后: 720 355 436 457 657 329 839 //按最低位由低到高排列
第二趟排序后: 720 329 436 839 355 457 657 //按倒数第二位由低到高排列
第三趟排序后: 329 355 436 457 657 720 839 //按最高位由低到高排序
2、算法分析
(1)时间复杂度:假设 n 为记录个数, rd 为基数值,d 为构成逻辑关键字的关键字位数。一趟“ 分配” 的时间复杂度是O(n), 一趟的收集” 复杂度是O(rd)。因此一趟分配和收集的时间复杂度为O(n+rd)。对每一位关键字进行一趟分配和收集, 因此总的时间复杂度为O(d(n+rd))。一般情况下, 相比 n 而言, rd 要小得多, 因此可简写为O(dn)。换句话说, 当待排序序列中的记录数量很大, 而逻辑关键字的“位数” 较小, 此时用基数排序法进行排序将比快速排序的效率更高。
(2)空间复杂度:空间复杂度为O(rd)。
(3)稳定性:对于基数排序而言,按位排序时必须是稳定的,也保证了基数排序的稳定性。