C语言归并排序算法

2023-11-03

今天我要和大家分享的是一个排序算法——归并算法。

如果说快速排序是让一个数组分成很多小集体进行排序,那么归并排序就是让很多有序的小集体合成一个有序数组。

思路:

如果是升序,对于每一个数字来说其本身是有序的,最初让两个只有一个元素的数组arr1,arr2的元素进行比较,较小者放入第三个数组arr3的第一个元素的位置,然后另一个数组的元素放在arr3。然后让两个有一个以上的合并后数组的首元素进行比较较小者让在第三个数组首元素的位置,再向下进行比较,直到两个数组的元素全部进入第三个数组,然后一直重复,直到合并成最终的大数组。

要想利用小集合合成大数组前提是有小集合,所以先让数组分成许多小数组。

void merge_sort_divide(int* arr, int* temp, int start, int end)
{
	if (start < end)
	{
		int mid = (start + end) / 2;
		merge_sort_divide(arr, temp, start, mid);
		merge_sort_divide(arr, temp, mid + 1, end);
		merge(arr, temp, start, mid + 1, end);
	}
}

最后合并

void merge(int* arr, int* temp, int arr1start, int arr2start, int arr2end)
{
	int p1 = arr1start, p2 = arr2start, p3 = p1, arr1end = p2 - 1;

	//主循环
	while (p1 <= arr1end && p2 <= arr2end)
	{
		if (arr[p1] < arr[p2]) temp[p3++] = arr[p1++];
		else temp[p3++] = arr[p2++];
	}

	//一个数组排序完成后,剩下的移动过去即可
	while (p1 <= arr1end) temp[p3++] = arr[p1++];
	while (p2 <= arr2end) temp[p3++] = arr[p2++];

	//将所有数据移回原来数组
	for (int i = arr1start; i <= arr2end; i++) arr[i] = temp[i];
}

全部代码

test.c:

#include"sort.h"

int main(void)
{
	int arr[LEN] = { 0 };
	int i = 0;
	srand((unsigned int)time(NULL));
    
    //生成随机数进行检验  也可以自己输入数据
	for (i = 0; i < LEN; i++)
	{
		arr[i] = rand() % 100;
	}
	printf("数组排序前:\n");
	print_arrray(arr, LEN);

	merge_sort(arr, LEN);

	printf("数组排序后:\n");
	print_arrray(arr, LEN);

	return 0;
}

sort.h:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>

#define LEN 10//随机数的个数

void print_arrray(int* arr, int len);


void merge_sort(int* arr, int len);

void merge_sort_divide(int* arr, int* temp, int start, int end);

void merge(int* arr, int* temp, int arr1star, int arr2start, int arr2end);

sort_function.c:

#include"sort.h"

void print_arrray(int* arr, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}


//将两个有序数组合并为一个
void merge(int* arr, int* temp, int arr1start, int arr2start, int arr2end)
{
	int p1 = arr1start, p2 = arr2start, p3 = p1, arr1end = p2 - 1;

	//主循环
	while (p1 <= arr1end && p2 <= arr2end)
	{
		if (arr[p1] < arr[p2]) temp[p3++] = arr[p1++];
		else temp[p3++] = arr[p2++];
	}

	//一个数组排序完成后,剩下的移动过去即可
	while (p1 <= arr1end) temp[p3++] = arr[p1++];
	while (p2 <= arr2end) temp[p3++] = arr[p2++];

	//将所有数据移回原来数组
	for (int i = arr1start; i <= arr2end; i++) arr[i] = temp[i];
}

void merge_sort_divide(int* arr, int* temp, int start, int end)
{
	if (start < end)
	{
		int mid = (start + end) / 2;
		merge_sort_divide(arr, temp, start, mid);
		merge_sort_divide(arr, temp, mid + 1, end);
		merge(arr, temp, start, mid + 1, end);
	}//分成许多小的数组最后执行合并
}


void merge_sort(int* arr, int len)
{
	int* temp = malloc(sizeof(int) * len);
	merge_sort_divide(arr, temp, 0, len - 1);
	free(temp);
}

运行结果:

 

牛客网 初学者编程118题小乐乐与序列_牛客题霸_牛客网

 我的初代思路:极其听话地先去重再排序。

初代代码:

#include<stdio.h>
 
int main(void)
{
    int arr[60] = { 0 };
    int n = 0;
    int i = 0;
    int j = 0;
    int k = 0;
    int count = 0;
    int flag = 0;
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
    }
    for (i = 0; i < n - count; i++)
    {
        for (k = i + 1; k < n - count; k++)
        {
            flag = 0;
            for (j = k; j < n - count; j++)
            {
                if(arr[j] == arr[i])
                {
                    flag = 1;
                    count++;
                    k = j - 1;
                    break;
                }
            }
            for (j; j < n - count; j++)
            {
                arr[j] = arr[j + 1];
            }
        }
    }
     
    //for (i = 0; i < n - count; i++)
    //{
        //printf("%d ", arr[i]);
    //}
    int p = 0;
    int min = 0;
    for (i = 0; i < n - count; i++)
    {
        p = i;
        min = arr[i];
        for (j = i + 1; j < n - count; j++)
        {
            if(arr[j] < min)
            {
                p = j;
                min = arr[j];
            }
        }
        if(p != i)
        {
            int t = arr[i];
            arr[i] = arr[p];
            arr[p] = t;
        }
    }
     
    for (i = 0; i < n - count; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

 数据太少了

然后改进:

改成了5000个数据

然后出现了这个

 

这是n的值

我就只能在堆上要这么多数据,并且学习了一个算法——快速排序,结果超时了,超过一秒程序直接暂停。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 
void W(int* p, int left, int right)//先去重
{
    int flag = 0;
    flag = *(p + left);
    int t = right;
    //int ret = right - left;
    while (left < right)
    {
        if (*(p + right) < flag)
        {
            *(p + left) = *(p + right);
            left++;
            while (left < right)
            {
                if (*(p + left) > flag)
                {
                    *(p + right) = *(p + left);
                    right--;
                    break;
                }
                else
                {
                    left++;
                }
            }
        }
        else
        {
            right--;
        }
    }
     
    *(p + left) = flag;
 
    if (left > 1)
    {
        W(p, 0, left - 1);
    }
    if (right < t - 1)
    {
        W(p, right + 1, t);
    }
}
 
int main(void)
{
    //int arr[10000] = { 0 };
    //int* p = (int*)calloc(80000, sizeof(int));
    int* p = (int*)malloc(80000*sizeof(int));
    if (p != NULL)
    {
        int n = 0;
        int i = 0;
        int j = 0;
        int k = 0;
        int count = 0;
        int flag = 0;
        scanf("%d", &n);
        for (i = 0; i < n; i++)
        {
            scanf("%d", p + i);
        }
        for (i = 0; i < n - count - 1; i++)
        {
            for (k = i + 1; k < n - count; k++)
            {
                flag = 0;
                for (j = k; j < n - count; j++)
                {
                    if (*(p + j) == *(p + i))
                    {
                        flag = 1;
                        count++;
                        k = j - 1;
                        break;
                    }
                }
                for (j; j < n - count; j++)
                {
                    *(p + j) = *(p + j + 1);
                }
            }
        }
 
        //for (i = 0; i < n - count; i++)
        //{
            //printf("%d ", arr[i]);
        //}
         
        W(p, 0, n - 1);
         
        for (i = 0; i < n - count; i++)
        {
            printf("%d ", *(p + i));
        }
        printf("\n");
    }
    free(p);
    p = NULL;
    return 0;
}

改进顺序,先排序后去重,在去重的同时打印:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 
void W(int* p, int left, int right)
{
    int flag = 0;
    flag = *(p + left);
    int t = right;
    while (left < right)
    {
        if (*(p + right) < flag)
        {
            *(p + left) = *(p + right);
            left++;
            while (left < right)
            {
                if (*(p + left) > flag)
                {
                    *(p + right) = *(p + left);
                    right--;
                    break;
                }
                else
                {
                    left++;
                }
            }
        }
        else
        {
            right--;
        }
    }
     
    *(p + left) = flag;
 
    if (left > 1)
    {
        W(p, 0, left - 1);
    }
    if (right < t - 1)
    {
        W(p, right + 1, t);
    }
}
 
int main(void)
{
    int* p = (int*)malloc(72641*sizeof(int));
    //int* q = (int*)malloc(70000*sizeof(int));
    if (p != NULL)
    {
        int n = 0;
        int i = 0;
        int k = 0;
        scanf("%d", &n);
        for (i = 0; i < n; i++)
        {
            scanf("%d", p + i);
        }
        W(p, 0, n - 1);
         
        for (i = 0; i < n - 1; i++)
        {
            if(*(p + i) != *(p + i + 1))
            {
                printf("%d ", *(p + i));
            }
        }
        printf("%d ", *(p + n - 1));
    }
    free(p);
    p = NULL;
    return 0;
}

 还是超时

然后用归并排序解决问题:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 
//将两个有序数组合并为一个
void merge(int* arr, int* temp, int arr1start, int arr2start, int arr2end)
{
    int p1 = arr1start, p2 = arr2start, p3 = p1, arr1end = p2 - 1;
 
    //主循环
    while (p1 <= arr1end && p2 <= arr2end)
    {
        if (arr[p1] < arr[p2]) temp[p3++] = arr[p1++];
        else temp[p3++] = arr[p2++];
    }
 
    //一个数组排序完成后,剩下的移动过去即可
    while (p1 <= arr1end) temp[p3++] = arr[p1++];
    while (p2 <= arr2end) temp[p3++] = arr[p2++];
 
    //将所有数据移回原来数组
    for (int i = arr1start; i <= arr2end; i++) arr[i] = temp[i];
}
 
void merge_sort_divide(int* arr, int* temp, int start, int end)
{
    if (start < end)
    {
        int mid = (start + end) / 2;
        merge_sort_divide(arr, temp, start, mid);
        merge_sort_divide(arr, temp, mid + 1, end);
        merge(arr, temp, start, mid + 1, end);
    }
}
 
 
void merge_sort(int* arr, int len)
{
    int* temp = malloc(sizeof(int) * len);
    merge_sort_divide(arr, temp, 0, len - 1);
    free(temp);
}
int main(void)
{
    int* p = (int*)malloc(100000*sizeof(int));
    if (p != NULL)
    {
        int n = 0;
        int i = 0;
        int a = 0;
        scanf("%d", &n);
        for (i = 0; i < n; i++)
        {
            scanf("%d", p + i);
        }
        merge_sort(p, n);
         
        for (i = 0; i < n - 1; i++)
        {
            if(*(p + i) != *(p + i + 1))
            {
                printf("%d ", *(p + i));
            }
        }
        printf("%d ", *(p + n - 1));
    }
    free(p);
    p = NULL;
    return 0;
}

最后说明一下为什么我从堆上要了10万个数,因为它真的用了

 经历了22次试错,因为自测都能通过,真正测试的10组中最后4组都是大数

 难题就要慢慢解决,写出来真的很有成就感,虽然那些大佬一眼就看出来了,但是我一个小鸟做出来感觉已经不错了,我会一直努力的。

 

 

 好吧,这几天没有太努力,让这张图片激励一下我吧!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言归并排序算法 的相关文章

随机推荐

  • TCGA数据库详解

    TCGA The cancer genome atlas 癌症基因组图谱 由 National Cancer Institute NCI 美国国家癌症研究所 和 National Human Genome Research Institut
  • C#位运算示例

    在C 中可以对整型运算对象按位进行逻辑运算 按位进行逻辑运算的意义是 依次取被运算对象的每个位 进行逻辑运算 每个位的逻辑运算结果是结果值的每个位 C 支持的位逻辑运算符如表2 9所示 运算符号 意义 运算对象类型 运算结果类型 对象数 实
  • 即将成为史上最具用户体验的Hexo+GitHub Pages搭建博客的教程(持续更新中)

    前言 网上关于Hexo Github Pages搭建博客的教程很多 但是参阅很多博文 都是表达不够清晰 绕来绕去 基于此 我想以一个初来者的角度写一篇尽可能靠谱的教程 方便大家快速搭建好 大致流程 搭建Node js环境 搭建Git环境 搭
  • c++ 习题(1)

    1 输入一个正整数n 计算下式的和求e的值 保留4位小数 e 1 输入输出示例 Input n 10 e 2 7183 if 1 include stdio h double facabular int n int sum 1 i for
  • 如何在C语言循环里实现多线程,如何用C语言实现多线程

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 Windows操作系统 C语言实现多线程 include include DWORD APIENTRY ThreadOne LPVOID threadArg printf 线程开始啦 参数是 s
  • 买车注意事项

    YETI 2016创行 车 保险 税 上牌 17 2w 其中裸车15 76w GS4 手动豪华 我的手动豪华117500包上牌 交强险 购置税 全车膜 脚垫 侧蹋 行车记录仪 发动机护板 挡泥板 座套 方向盘套 前两次首保免费 10万公里机
  • Git背后的设计理念

    首先要清楚Git版本管理中提交的概念 通过按行对比 line diff 将有差异的部分作为增量补丁 使用git add添加到暂存区里的每一个文件都会由按行对比得到他们的增量补丁 而使用git commit将暂存区里的所有文件的增量补丁合并起
  • 泛型知识点总结

    目录 泛型的概念 泛型的底层实现 什么是类型擦除 Java编译器具体是如何擦除泛型的 对于泛型的理解 泛型的使用注意点 零散知识点1 泛型的使用注意点 零散知识点2 泛型方法 类型变量的限定 泛型的概念 泛型的底层实现 我们知道 Java有
  • Java项目结构的总体理解

    本文简单记录了一下自己对java项目各个层的理解 清理笔记 hhh 新版编辑器既好用又不好用 哎 第一次发布的序号都被打乱了 参考 作者 码农BookSea 原文链接 DAO层和Service层的究极理解 这波我在大气层 码农BookSea
  • doGet与doPost的区别

    在使用表单提交数据到服务器的时候有两张方式可共选择 一个是post一个是get 可在
  • 公有云和私有云的区别

    在现在云计算大行其道的时候 许多的企业都将自己的数据信息进行云迁移 但是面对种类繁多的云服务 企业应该如何选择适合自己的业务呢 首先我们要了解什么是云计算 云计算有几种模式 各种模式的架构原理 什么是云计算云计算将计算作为一种服务交付给用户
  • 浪潮服务器硬盘阵列怎么做,server - 浪潮服务器RAID阵列配置及OS安装

    1 RAID磁盘阵列配置 1 1RAID含义 磁盘阵列 Redundant Arrays of Independent Disks RAID 有 独立磁盘构成的具有冗余能力的阵列 之意 1 2RAID配置作用 将独立磁盘 组合成容量巨大的磁
  • C++:什么是RAII?

    一 什么是RAII RAll Resource Acquisition ls Initialization 是由c 之父Bjarne Stroustrup提出的 中文翻译为资源获取即初始化 使用局部对象来管理资源的技术称为资源获取即初始化
  • vscode优美的主题

    如何给VS Code更换主题 Mac用户 K 然后 T 会显示出所有的主题列表 按上下键可修改主题 P 在输入框中color theme 然后回车 同样也会进入主题列表 Windows用户 Ctrl Shift P 即可进入主题列表 6款精
  • JavaScript WebGL 帧缓冲区对象

    引子 在看 How I built a wind map with WebGL 的时候 里面用到了 framebuffer 就去查了下资料单独尝试了一下 Origin My GitHub 帧缓冲区对象 WebGL 有一个能力是将渲染结果作为
  • 公司的苹果开发者账号续费问题

    最近公司的开发者账号马上要过期了 因此从来没有接触过这个方面的我主动接受了续费这项任务 不接手不知道 一接手才知道问题很多 现在总结一下 以供大家学习 续费通知 临近到期日一个月以内 苹果会向开发者账号绑定的邮箱发送一条邮件 提醒续费 如下
  • BeagleBone Black 学习网址

    https www digikey com eewiki display linuxonarm BeagleBone Black
  • C++ 泛型编程(三) 模版实参推断

    前文回顾 C 泛型编程 一 基本概念 C 泛型编程 二 函数模版 模版实参推断 类型转换 编译器通常不是对实参进行类型转换 而是生成一个新的模版实例 只有有限的几种类型会进行类型转换 可以将一个非 const 对象的引用或者指针传递给一个
  • 用python实现简易计算器

    最近学习了字符串 运算符 条件语句 循环语句 我在想可以用我最近学的东西做什么 看到运算我就想到了可以做一个简易的计算器 实现流程 1 定义函数 2 请用户选择运算方法 3 请用户输入要运算的两个数 4 运算出结果 代码实现 定义加减乘除四
  • C语言归并排序算法

    今天我要和大家分享的是一个排序算法 归并算法 如果说快速排序是让一个数组分成很多小集体进行排序 那么归并排序就是让很多有序的小集体合成一个有序数组 思路 如果是升序 对于每一个数字来说其本身是有序的 最初让两个只有一个元素的数组arr1 a