数据结构与C++

数据结构与C++ 知识量:9 - 32 - 91

9.4 其他排序方法><

归并排序- 9.4.1 -

归并排序(Merge Sort)是一种分治策略的排序算法,它将一个无序数组分成两个子数组,对子数组递归地进行排序,然后将有序的子数组合并成一个有序的数组。

以下是使用C++实现归并排序的代码:

#include <iostream>  
#include <vector>  
using namespace std;  
  
void merge(vector<int>& arr, int left, int mid, int right) {  
    vector<int> temp(right - left + 1); // 创建临时数组  
    int i = left, j = mid + 1, k = 0; // i指向左子数组的起始位置,j指向右子数组的起始位置,k指向临时数组的起始位置  
  
    // 合并左右子数组到临时数组  
    while (i <= mid && j <= right) {  
        if (arr[i] <= arr[j]) {  
            temp[k++] = arr[i++];  
        } else {  
            temp[k++] = arr[j++];  
        }  
    }  
  
    // 将剩余元素复制到临时数组中  
    while (i <= mid) {  
        temp[k++] = arr[i++];  
    }  
  
    while (j <= right) {  
        temp[k++] = arr[j++];  
    }  
  
    // 将临时数组中的元素复制回原数组中  
    for (int p = 0; p < temp.size(); p++) {  
        arr[left + p] = temp[p];  
    }  
}  
  
void mergeSort(vector<int>& arr, int left, int right) {  
    if (left < right) {  
        int mid = left + (right - left) / 2; // 计算中间位置  
        mergeSort(arr, left, mid); // 递归地对左右子数组进行排序  
        mergeSort(arr, mid + 1, right); // 递归地对左右子数组进行排序  
        merge(arr, left, mid, right); // 合并左右子数组  
    }  
}  
  
int main() {  
    vector<int> arr = {5, 2, 9, 1, 5, 6};  
    mergeSort(arr, 0, arr.size() - 1);  
    for (int i = 0; i < arr.size(); i++) {  
        cout << arr[i] << " ";  
    }  
    cout << endl;  
    return 0;  
}

多关键码排序- 9.4.2 -

多关键码排序是指使用多个关键码进行排序的方法。在处理实际问题时,一个对象可能包含多个属性,这些属性都可能影响对象的排序。为了得到更准确、更符合实际需求的排序结果,可以使用多关键码排序。

多关键码排序的基本思想是将多个关键码组合成一个优先级序列,然后按照优先级序列的顺序对对象进行比较和排序。在比较过程中,先按照优先级最高的关键码进行比较,如果两个对象在该关键码上的值相等,则继续按照下一个关键码进行比较,以此类推,直到比较完所有的关键码。

多关键码排序的实现方式有多种,其中一种常用的方法是使用“快速排序”算法的变种。具体来说,可以将每个对象看作是一个“键值对”,其中键是关键码的集合,值是对象的值。然后使用类似于快速排序的分治策略,将对象按照关键码的顺序分成不同的子集,再递归地对子集进行排序。最后将所有有序的子集合并成一个有序的整体。

多关键码排序的应用非常广泛,例如在数据库查询、搜索引擎、推荐系统等领域都有广泛的应用。通过使用多关键码排序,可以更好地处理具有多个属性、多个特征的数据,得到更准确、更符合实际需求的排序结果。

链式基数排序- 9.4.3 -

链式基数排序是一种排序算法,它基于“分配式排序”的思想,特别是一种叫做“多关键字排序”的方法。该算法将一个单关键字视为多个关键字,例如对于数字0~999,可以把每一位上的十进制数字都视为一个关键字。

链式基数排序使用LSD(最低位优先法)进行排序,从最低位的关键字开始,按照关键字的值将原始序列中的记录分配到多个“桶”中,然后依次收集,组成新的序列。再按照次低位的关键字重新将记录分配并收集,如此重复操作,直到按照最高位关键字对序列分配收集完毕,方可获得一个按关键字有序的序列。

这种排序方法结合了多关键字排序和桶排序,解决了桶排序中时间效益与空间效益不可兼得的矛盾。对于10个一千以内的整数,使用桶排序时,若每个桶中存储的键值依次加1,那么这10个数据会被分配到这1000个桶中,显然很多桶都为空;使用链式基数排序时,一千以内的整数被视为由三个0~9之间的数字组成的数据,关键字的范围从原来的0~999缩小到了0~9,只需要根据每一位的数字,对这10个一千以内的数进行三次分配与收集,就能得到需要的序列。

各种内部排序方法的比较- 9.4.4 -

各种内部排序方法的比较可以从时间复杂度、空间复杂度、稳定性以及适用场景等多个维度进行。以下是一些常见的内部排序方法的比较:

  • 时间复杂度:不同的内部排序方法具有不同的时间复杂度。其中,直接插入排序、选择排序和冒泡排序的时间复杂度较高,为O(n^2),而快速排序、归并排序和堆排序的时间复杂度较低,为O(nlogn)。在最坏情况下,快速排序的时间复杂度会退化到O(n^2),但其平均时间复杂度仍然是O(nlogn)。

  • 空间复杂度:归并排序和快速排序需要额外的空间来存储临时数据,其空间复杂度为O(n),而其他的排序方法如选择排序、冒泡排序和插入排序的空间复杂度为O(1)。链式基数排序的空间复杂度为O(rd),其中rd是基数。

  • 稳定性:当两个元素的比较结果相同时,稳定的排序方法会保持它们的相对位置不变。在稳定排序方法中,插入排序、归并排序和基数排序最为常见。

  • 适用场景:选择排序和插入排序在n较小时更为有效,特别是当数据量小且大部分元素已经近似有序时。对于大型数据集,快速排序、堆排序和归并排序通常更为高效。链式基数排序适用于处理非常大的数据集,特别是当数据的关键字位数较少时。

综上所述,各种内部排序方法各有其特点,应根据实际需求和应用场景来选择合适的排序方法。