您的位置:首页 > 编程语言 > C语言/C++

合并排序 分治(递归、自然合并排序)实现(C++)

2020-06-01 05:12 1046 查看

文章目录

  • 三、自然合并排序
  • 一、合并排序(归并排序)概念

    定义:

    引用自"百度百科"
    ·

    • 合并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
    • 合并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
    • 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。合并排序也叫归并排序。

    算法步骤:

    引用自"菜鸟教程"

    1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
    2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
    3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
    4. 重复步骤 3 直到某一指针达到序列尾;
    5. 将另一序列剩下的所有元素直接复制到合并序列尾。

    二、分治&递归算法实现

    1. 设计递归方程

    1. 我们需要将序列拆分,将当前区间一分为二,即求中间点
    2. 递归地对两个子区间 L[left…mid] 和 R[mid+1…right] 进行归并排序

    / / 3. 将已排序的两个子区间 L[left…mid] 和 R[mid+1…right] 合并为一个有序的区间[left…right]

    2. 确定边界条件

    • 当拆分后的子序列只含有一个元素时,结束递归调用,开始合并操作。

    3. 编写程序代码

    // 合并排序
    #include<iostream>
    
    using namespace std;
    
    void mergeSort(int array[], int left, int right);
    void merge(int array[], int left, int mid, int right);
    
    int main()
    {
    // 待排序数组,也可进行改写,获取键盘输入进行排序
    int array[] = { 10,5,8,6,3,9,4,1,2,7 };
    int len = sizeof(array) / sizeof(int); // 数组长度
    
    mergeSort(array, 0, len-1);
    cout << "合并排序:";
    for (int i = 0;i < len;i++)
    cout << array[i] << " ";
    cout << endl;
    
    return 0;
    }
    
    void mergeSort(int array[], int left, int right)
    {
    // 当子序列就只有一个元素的时候结束递归调用
    if (left == right)
    return;
    else {
    // 分治
    // 判断中间位置,进行拆分
    int mid = (left + right) / 2;
    mergeSort(array, left, mid);
    mergeSort(array, mid + 1, right);
    // 合并
    merge(array, left, mid, right);
    }
    }
    
    void merge(int array[], int left, int mid, int right)
    {
    // 声明一个指针,指向临时数组,临时存放排序后的元素
    int* tempArray = new int[right - left + 1];
    
    int left_1 = left;		// 指向 左待排序区域 第一个元素
    int left_2 = mid + 1;	// 指向 右待排序区域 第一个元素
    int k = 0;				// 指向 临时数组 第一个元素
    
    // 顺序选取两个待排序区的较小元素,存储到tempArr数组中
    while (left_1 <= mid && left_2 <= right) {
    // 将较小的元素存入tempArr数组中,并将指针递增
    if (array[left_1] <= array[left_2])
    tempArray[k++] = array[left_1++];
    else
    tempArray[k++] = array[left_2++];
    }
    // 若比较完之后,有序区仍有剩余元素,则直接复制到tempArray数组中
    while (left_1 <= mid)
    tempArray[k++] = array[left_1++];
    while (left_2 <= right)
    tempArray[k++] = array[left_2++];
    
    // 将临时数组中排序后的元素取出
    for (int i = left, j = 0;i <= right;i++,j++)
    array[i] = tempArray[j];
    
    // 删除指针
    delete[] tempArray;
    }

    4. 运行结果展示

    三、自然合并排序

    1. 描述&基本思想

    • 自然合并排序是合并排序算法的一种改进
    • 对于初始给定的数组,通常存在多个长度大于1的已排好序的子数组段。因此用一次线性扫描就可以找出所有这些排好序的子数组段,然后将相邻的排好序的子数组段两两合并
    • 注:通常情况下, 按此方式进行合并排序所需的合并次数较少。
    • 举个栗子: 数组a中元素为{2, 5, 8, 3, 6, 10, 4, 9};
    • 用一次对数组a的线性扫描,找出自然排好序的子数组段:{2, 5, 8},{3, 6},{10},{4, 9};
    • 然后将相邻的排好序的子数组段两两合并:{2, 3, 5, 6, 8},{4, 9, 10};
    • 继续合并直至整个数组排好序{2, 3, 4, 5, 6, 8, 9, 10}。

    2. 编写程序代码

    // 待更新。。。

    3. 运行结果展示

    运行截图(待更新。。。)

    *其它一些常见算法请参阅此链接~

    最后,非常欢迎大家来讨论指正哦!

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: