当前位置: 首页 > article >正文

[数据结构]排序之 归并排序(有详细的递归图解)

一、非递归

基本思想:
归并排序( MERGE-SORT )是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法( Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:
归并:如果左区间和右区间都有序,那么一次比较,小的尾插到新空间,链表可以摘下来插入,数组不行,得借助新空间
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void _MergeSort(int* a, int begin, int end, int* temp)
{
    if (begin>=end)
        return;
    int mid = (begin + end) / 2;
    //[begin,mid] [mid+1,end]如果这两个区间有序,那么可以归并了
    _MergeSort(a, begin, mid, temp);
    _MergeSort(a, mid+1, end, temp);
    //[begin, mid] [mid + 1, end]归并
    int begin1 = begin, end1 = mid;
    int begin2 = mid+1, end2 = end;
    int i = begin;
    while (begin1 <= end1 && begin2 <= end2)
    {
        if (a[begin1] < a[begin2])
        {
            temp[i] = a[begin1];
            i++;
            begin1++;
        }
        else
        {
            temp[i] = a[begin2];
            i++;
            begin2++;
        }
    }
    //谁没结束谁++来拷贝,由于不知道是哪个区间没有结束,所有都写一遍
    while (begin1 <= end1)
    {
        temp[i] = a[begin1];
        i++;
        begin1++;
    }
    while (begin2 <= end2)
    {
        temp[i] = a[begin2];
        i++;
        begin2++;
    }
     //等把所有数都放到temp数组上时,再拷贝回去
    memcpy(a+begin, temp+begin,sizeof(int)*(end-begin+1));
}
void MergeSort(int* a, int n)
{
    int* temp = (int*)malloc(sizeof(int) * n);
    if (temp == NULL)
    {
        perror("malloc fail\n");
        return;
    }
    _MergeSort(a, 0, n - 1, temp);
    free(temp);
}
int main()
{
    int a[] = {10,6,7,1,3,9,4,2 };
    MergeSort(a,8);
    for (int i = 0; i < 8; i++)
    {
        printf("%d ", a[i]);
    }
    return 0;
}

注:以下图片看不清楚可以点进去放大看

二、递归 

不能用栈,栈是前序,而归并是后序
方法:
能不能依次依次往后算?算完第一个和第二个后算第三个和第四个,再算第五个和第六个.......
第一次归完后再拷贝回去后四个四个一归.....

必须得注意细节:如果是奇数个数那么得注意边界

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void Swap(int* a, int* b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
void _MergeSort(int* a, int begin, int end, int* temp)
{
    if (begin >= end)
        return;
    int mid = (begin + end) / 2;
    //[begin,mid] [mid+1,end]如果这两个区间有序,那么可以归并了
    _MergeSort(a, begin, mid, temp);
    _MergeSort(a, mid + 1, end, temp);
    //[begin, mid] [mid + 1, end]归并
    int begin1 = begin, end1 = mid;
    int begin2 = mid + 1, end2 = end;
    int i = begin;
    while (begin1 <= end1 && begin2 <= end2)
    {
        if (a[begin1] < a[begin2])
        {
            temp[i] = a[begin1];
            i++;
            begin1++;
        }
        else
        {
            temp[i] = a[begin2];
            i++;
            begin2++;
        }
    }
    //谁没结束谁++来拷贝,由于不知道是哪个区间没有结束,所有都写一遍
    while (begin1 <= end1)
    {
        temp[i] = a[begin1];
        i++;
        begin1++;
    }
    while (begin2 <= end2)
    {
        temp[i] = a[begin2];
        i++;
        begin2++;
    }
    //等把所有数都放到temp数组上时,再拷贝回去
    memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
    int* temp = (int*)malloc(sizeof(int) * n);
    if (temp == NULL)
    {
        perror("malloc fail\n");
        return;
    }
    int gap = 1;
    while (gap < n)
    {
        for (int i = 0; i < n; i += 2 * gap)
        {
            int begin1 = i, end1 = i + gap - 1;
            int begin2 = i + gap, end2 = i + 2 * gap - 1;
            int j = i;
            while (begin1 <= end1 && begin2 <= end2)
            {
                if (a[begin1] < a[begin2])
                {
                    temp[j] = a[begin1];
                    j++;
                    begin1++;
                }
                else
                {
                    temp[j] = a[begin2];
                    j++;
                    begin2++;
                }
            }
            //谁没结束谁++来拷贝,由于不知道是哪个区间没有结束,所有都写一遍
            while (begin1 <= end1)
            {
                temp[j] = a[begin1];
                j++;
                begin1++;
            }
            while (begin2 <= end2)
            {
                temp[j] = a[begin2];
                j++;
                begin2++;
            }
            //等把所有数都放到temp数组上时,再拷贝回去
            memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
        }
        gap *= 2;
    }
    
    free(temp);
}
int main()
{
    int a[] = {10,6,7,1,3,9,4,2 };
    MergeSort(a,8);
    for (int i = 0; i < 8; i++)
    {
        printf("%d ", a[i]);
    }
    return 0;
}

 


http://www.kler.cn/a/595136.html

相关文章:

  • 微服务分层架构详解:表示层、应用层与基础设施层的协同工作
  • Python学习第二十二天
  • WPF UI元素保存为图像文件
  • L2和内积inner dot区别
  • Vue 3 自定义指令:实现自动滚动效果
  • 去中心化金融的风起与未来:从边缘创新到主流趋势
  • 4.1、网络安全模型
  • QT并发编程进阶--线程安全与同步技巧详解
  • Nexus L2 L3基本配置
  • VS010生成可由MATLAB2016调用的DLL文件方法
  • Sympy入门之微积分基本运算
  • 建模中的特征衍生技巧总结(含各类常用衍生函数)
  • sougou AI close
  • MyBatis 的一次缓存与二次缓存
  • 如何使用AIOps明确Devps的问题归责
  • 混合精度-基于torch内部
  • 尝试在软考65天前开始成为软件设计师-计算机网络
  • 【vLLM 学习】使用 XPU 安装
  • (C语言)sizeof与strlen的区别,以及有关习题练习
  • YOLO可视化界面,目标检测前端QT页面。