归并排序——递归和迭代

一 前言

不想写前言,归并排序,我好像搞了一下午,我的妈,我在干啥,我,要命啊。不搞了,不来了,简单做下记录。

只记录两种代码。

  1. 递归
  2. 迭代

二 代码

2.0 例子

用归并排序排它。
在这里插入图片描述

2.1 迭代

数据元素下标从1开始。下标为0的数据不用。

需要改进成从0开始,等我想了再改吧

在这里插入图片描述

A 主调函数

#include <iostream>
#include <stdio.h>

using namespace std;

// 函数声明
void merge_sort(int a[], int n); // 迭代
void merge(int a[], int s1_left, int s1_right, int s2_left, int s2_right); // 合并两段有序序列
void mergePass(int a[], int s, int n); // 合并中间过程,一次调用就是一轮合并

// 归并排序——迭代方法
int main()
{
    int a[] = {-1, 50, 10, 100, 30, 70, 40, 80, 60, 20};
    int n = 10;
    int i;

    cout << "Before: " << endl;
    for (i=1; i<n; i++)
        cout << a[i] << " ";
    cout << endl;
	
	// 迭代归并排序
    merge_sort(a, n-1);

    cout << "After: " << endl;
    for (i=1; i<n; i++)
        cout << a[i] << " ";
    cout << endl;
    
    
    system("pause");
    return 0;
}


B 归并函数

void merge_sort(int a[], int n)
{
    int k = 1;

    while (k < n)
    {
        mergePass(a, k, n); // 从1->2->4 ... ->2k逐项合并
        k = 2 * k;
    }
    
}

C 两两逐项合并函数

void mergePass(int a[], int s, int n)
{
    int i = 1;
    
    while (i <= n-2*s+1) //两两合并
    {
        merge(a, i, i+s-1, i+s, i+2*s-1); // 从小到大合并两个有序序列
        i = i + 2*s;
    }

    if (i < n-s+1) //合并最后两个序列
        merge(a, i, i+s-1, i+s, n);
    
}
// 将两个有序序列s1 s2合并
// s1_left: s1序列的左边界  s1_right: s1序列的右边界
// s2_left: s1序列的左边界  s2_right: s1序列的右边界
void merge(int a[], int s1_left, int s1_right, int s2_left, int s2_right)
{
    int i, j, k; // 三指针
    int b[9] = {0}; //合并场地, 初始化下。9为待排数据总长度

    // 指针赋初值
    i = s1_left; j = s2_left; k = s1_left;

    // 当两个序列s1 s2均不满的时候
    while ( (i<=s1_right) && (j<=s2_right) )
    {
        if ( a[i] < a[j])
            b[k++] = a[i++];
        else
            b[k++] = a[j++];
    }

    // s1未结束
    while ( i <= s1_right )
        b[k++] = a[i++];

    // s2未结束
    while ( j <= s2_right )
        b[k++] = a[j++];
    
    // 将合并后的有序段移动回源数组a
    for (i=s1_left; i<=s2_right; i++)
        a[i] = b[i];

}

2.2 递归

递归过程就是这样子,管你看不看的懂,记就完了。

这个下标是从0开始的,没错的。当然你也可以改成从1开始。
在这里插入图片描述

A 主调函数

#include <iostream>
#include <stdio.h>

using namespace std;

// 函数声明
void merge(int a[], int s1_left, int s1_right, int s2_left, int s2_right); // 合并两段有序序列
void merge_sort2(int a[], int i, int j); //递归


// 归并排序——递归
int main()
{
    int a[] = {50, 10, 90, 30, 70, 40, 80, 60, 20};
    int n = 9;

    int i;

    cout << "Before: " << endl;
    for (i=0; i<n; i++)
        cout << a[i] << " ";
    cout << endl;

    merge_sort2(a, 0, n-1);

    cout << "After: " << endl;
    for (i=0; i<n; i++)
        cout << a[i] << " ";
    cout << endl;
    
    
    system("pause");
    return 0;
}

B 归并函数

// 递归
// 从0到n-1进行调用: merge_sort2(a, 0, n-1)
void merge_sort2(int a[], int i, int j)
{
    int k;

    if (i < j) // 每段元素个数大于1; 先拆分递归、再归并退出递归
    {
        k = (i + j) / 2;
        merge_sort2(a, i, k); // 对左段进行排序,s1
        merge_sort2(a, k+1, j); // 对右段进行排序,s2
        merge(a, i, k, k+1, j); // 合并 s1 s2
    } 
}

C 两两合并函数

// 将两个有序序列s1 s2合并
// s1_left: s1序列的左边界  s1_right: s1序列的右边界
// s2_left: s1序列的左边界  s2_right: s1序列的右边界
void merge(int a[], int s1_left, int s1_right, int s2_left, int s2_right)
{
    int i, j, k; // 三指针
    int b[9] = {0}; //合并场地, 初始化下。9为待排数据总长度

    // 指针赋初值
    i = s1_left; j = s2_left; k = s1_left;

    // 当两个序列s1 s2均不满的时候
    while ( (i<=s1_right) && (j<=s2_right) )
    {
        if ( a[i] < a[j])
            b[k++] = a[i++];
        else
            b[k++] = a[j++];
    }

    // s1未结束
    while ( i <= s1_right )
        b[k++] = a[i++];

    // s2未结束
    while ( j <= s2_right )
        b[k++] = a[j++];
    
    // 将合并后的有序段移动回源数组a
    for (i=s1_left; i<=s2_right; i++)
        a[i] = b[i];

}

参考资料

[1] 数据结构 – 中国人民解放军陆军工程大学 –陈卫卫、李清等 – 公开课 – 中国大学MOOC
https://www.icourse163.org/course/PAEU-1001660013#/info

[2] 程杰著.大话数据结构[M].北京:清华大学出版社.2011.

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值