排序(3)归并排序、基数排序以及各种排序算法的比较

1. 归并排序

思路:归并排序是多次将相邻两个或两个以上的有序表合并成一个新的有序表。
最简单的归并是将相邻的两个有序的子表合并成为一个有序的表,即二路归并排序。
在这里插入图片描述
算法设计
Merge():一次二路归并,用B存放合并的序列,空间复杂度为 O ( h i g h − l o w + 1 ) O(high-low+1) O(highlow+1)
MergePass():一趟二路归并;
MergeSort():二路归并排序算法,共归并 ⌈ l o g 2 n ⌉ \lceil log_2n \rceil log2n趟。

void Merge(RecType A[], int low, int mid, int high){
    
    
    RecType *B = (RecType*)malloc((high-low+1)*sizeof(RecType));
    int i = low, j = mid+1, k = 0;
    while (i<=mid && j<=high){
    
    //将合并的有序序列放在B中
        if (A[i].key<A[j].key) B[k++] = A[i++];
        else B[k++] = A[j++];
    }
    while (i<=mid) B[k++] = A[i++];
    while (j<=high) B[k++] = A[j++];
    for (int k=0; k<=high-low; k++)//将B中元素复制到A中
        A[low+k] = B[k];
    free(B);
}
void MergePass(RecType A[], int length, int n){
    
    
    int i;
    for (i=0; i+2*length-1<n; i=i+2*length)//归并长度为length的两个相邻子表
        Merge(A,i,i+length-1,i+2*length-1);
    if (i+length<n)//余下两个子表,后者长度小于length
        Merge(A,i,i+length-1,n-1);
}
void MergeSort(RecType A[], int n){
    
    
    int length;
    for (length=1;length<n;length=2*length)
        MergePass(A,length,n);
}

空间效率:最后一趟合并时,B要存储所有元素,空间复杂度为 O ( n ) O(n) O(n)
时间效率:每一趟归并的时间复杂度为 O ( n ) O(n) O(n),总共需要进行 ⌈ l o g 2 n ⌉ \lceil log_2n \rceil log2n趟,时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
稳定性:稳定。

void Merge(vector<int>& arr, int left, int right, int length){
    
    
    int i = left, j = left + length, k = 0;
    vector<int> tmp(right-left+1,0);
    while (i < left+length && j <= right){
    
    
        if (arr[i] < arr[j])
            tmp[k++] = arr[i++];
        else
            tmp[k++] = arr[j++];
    }
    while (i < left + length)
        tmp[k++] = arr[i++];
    while (j <= right)
        tmp[k++] = arr[j++];
    for (int i = left; i <= right; i++)
        arr[i] = tmp[i-left];
    vector<int>().swap(tmp);
}
void MergePass(vector<int>& arr, int length){
    
    
    int n = arr.size();
    int i;
    for (i = 0; i + 2 * length <= n; i += 2*length)
        Merge(arr,i,i+2*length-1,length);
    if (i + length < n)
        Merge(arr,i,n-1,length);
}
void MergeSort(vector<int>& arr){
    
    
    int n = arr.size();
    for (int length = 1; length < n; length *= 2)
        MergePass(arr,length);
}

2. 基数排序

基数 r r r:对于二进制数 r r r为2,对于十进制数 r r r为10.
每条记录的关键字有 d d d元组 ( k j d − 1 , k j d − 2 , . . . , k j 1 , k j 0 ) (k_j^{d-1},k_j^{d-2},...,k_j^{1},k_j^{0}) (kjd1,kjd2,...,kj1,kj0)组成,满足 0 < = K j i < = r − 1 0<=K_j^i<=r-1 0<=Kji<=r1。其中, k j d − 1 k_j^{d-1} kjd1为最主位关键字, k j 0 k_j^{0} kj0为最次位关键字。
分为两种,第一种是最高位优先(MSD)法,按关键字位权重递减依次逐层划分成若干更小的子序列,最后将所有的子序列依次连接成一个有序序列;第二种是最低位优先(LSD)法,按关键字权重递增依次进行排序,最后形成一个有序序列。
排序过程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
空间效率:一趟排序需要的辅助空间为 r r r(r个队列),空间复杂度为 O ( r ) O(r) O(r)
时间效率:基数排序需要进行 d d d趟分配和收集,一趟分配需要 O ( n ) O(n) O(n),一趟收集需要 O ( r ) O(r) O(r),所以时间复杂度为 O ( d ( n + r ) ) O(d(n+r)) O(d(n+r))。且与序列的初始状态无关。
稳定性:稳定。

3. 各种排序算法的比较

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42820853/article/details/106102134