【C语言】数据结构——排序三(归并与计数排序)

💗个人主页💗
⭐个人专栏——数据结构学习⭐
💫点击关注🤩一起学习C语言💯💫

目录

  • 导读:
  • 1. 归并排序
    • 1.1 基本思想
    • 1.2 递归实现
    • 1.3 非递归实现
  • 2. 计数排序
    • 2.1 基本思想
    • 2.2 代码实现

导读:

我们在前面学习了排序,包括直接插入排序,希尔排序,选择排序,堆排序,冒泡排序和快排。
今天我们来讲一讲归并排序和计数排序。
关注博主或是订阅专栏,掌握第一消息。

1. 归并排序

1.1 基本思想

归并排序的基本思想是将待排序的数组分成两个较小的子数组,然后递归地对这两个子数组进行排序,最后将两个有序的子数组合并成一个有序的数组。
在这里插入图片描述

  1. 将待排序数组分成两个较小的子数组,直到子数组中只剩下一个元素。
  2. 对两个子数组分别进行归并排序,即递归调用归并排序函数。
  3. 将两个有序的子数组进行合并,得到一个有序的数组。合并过程中,从两个子数组的第一个元素开始,依次比较大小,将较小的元素放入新的数组中。
  4. 将合并得到的有序数组返回。

归并排序的关键在于合并两个有序的子数组,这一步可以使用辅助数组来存储合并的结果。合并时,可以使用两个指针分别指向两个子数组的起始位置,比较指针指向的元素的大小,将较小的元素放入新的数组中,并将对应指针后移一位。当一个子数组遍历完后,将另一个子数组剩余的元素直接放入新的数组中即可。

1.2 递归实现

非递归实现归并排序的思想是通过迭代和循环来分割和合并数组,而不使用递归。

  1. 初始化一个辅助数组,用于存储合并的结果。
  2. 从数组的起始位置开始,将数组中的每个元素看作一个独立的有序序列,将它们分别放入辅助数组。
  3. 设置一个变量gap,初始值为1,代表每次合并的有序子序列的长度。
  4. 进入循环,循环条件是gap小于数组的长度。
  5. 在每一次循环中,将两个有序子序列合并并放入辅助数组中。
  6. 将合并得到的有序子序列放回原数组的对应位置。
  7. 将gap的值加倍,继续下一轮循环,直到gap大于或等于数组的长度

通过不断合并较小的有序子序列,直到整个数组排序完成,即可得到最终的有序数组。非递归实现归并排序的好处是减少了函数调用的开销,提高了排序的效率。

void _MergeSort(int* a, int begin, int end, int* tmp)
{if (begin >= end){return;}int mid = (begin + end) / 2;_MergeSort(a, begin, mid, tmp);_MergeSort(a, mid + 1, end, tmp);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}_MergeSort(a, 0, n - 1, tmp);free(tmp);
}

1.3 非递归实现

//非递归
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap < n){//printf("gap:%2d->", gap);for (size_t i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;// [begin1, end1][begin2, end2] 归并// 边界的处理if (end1 >= n || begin2 >= n){break;}if (end2 >= n){end2 = n - 1;}int j = begin1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));}//printf("\n");gap *= 2;}free(tmp);
}

2. 计数排序

2.1 基本思想

计数排序是一种线性时间复杂度的排序算法,适用于一定范围内的整数排序。其基本思想是通过统计每个元素的出现次数,然后根据统计结果将元素放置到正确的位置上。

  1. 统计每个元素出现的次数,创建一个计数数组,并初始化为0。
  2. 遍历待排序的数组,将每个元素对应的计数数组的对应位置加1,即统计元素出现次数。
  3. 对计数数组进行顺序累加,得到每个元素在排序后的数组中的最后一个下标位置。
  4. 创建一个临时数组,长度与待排序数组相同。
  5. 遍历待排序数组,根据元素值在计数数组中的累加结果,将元素放置到临时数组中的对应位置上。
  6. 将临时数组复制回原始数组,完成排序。

需要注意的是,计数排序只适用于非负整数排序,并且在k不是很大的情况下才能保证排序的效率。

2.2 代码实现

//计数排序
void CountSort(int* a, int n)
{int min = a[0], max = a[0];for (int i = 1; i < n; i++){if (a[i] < min)min = a[i];if (a[i] > max)max = a[i];}int range = max - min + 1;int* count = (int*)calloc(range, sizeof(int));if (count == NULL){printf("calloc fail\n");return;}// 统计次数for (int i = 0; i < n; i++){count[a[i] - min]++;}// 排序int i = 0;for (int j = 0; j < range; j++){while (count[j]--){a[i++] = j + min;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/630178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VSCODE上使用IDEA上的快捷键:IntelliJ IDEA Keybindings

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…

git项目管理

Git工作流程图 git 基础指令 git init #创建本地仓库,创建成功后&#xff0c;当前目录会多一个.git文件夹 git status #查看修改状态 git add . #添加工作区到暂存区 git commit -m 注释内容 #提交暂存区到本地仓库&#xff08;commit&#xff09; git log …

k8s集群环境搭建以及插件安装

前置条件 终端工具MobaXterm很好用。 1、虚拟机三台&#xff08;ip按自己的网络环境相应配置&#xff09;(master/node) 节点ipk8s-master192.168.200.150k8s-node1192.168.200.151k8s-node2192.168.200.152 2、关闭防火墙(master/node) systemctl stop firewalld systemc…

导游翻译的职责是什么?如何做好导游翻译?

作为旅游行业的关键人物&#xff0c;导游翻译是连接游客与目的地文化的桥梁。他们不仅要具备出色的语言能力&#xff0c;还要深入了解目的地的历史、文化和风俗习惯&#xff0c;为游客提供专业、贴心的导游翻译服务。那么&#xff0c;导游翻译的主要职责是什么&#xff1f;如何…

idea中设置控制台显示service窗口项

一 操作配置 1.1 具体操作 1.操作 2.操作 3.选择应用类型&#xff1a; appplication&#xff0c;springbootapplication等

AI绘画认识

什么是AI绘画 AI绘画是指利用人工智能技术进行绘画创作的过程&#xff0c;它使用机器学习算法和深度神经网络等技术&#xff0c;通过对现有艺术品、图像等大量数据进行分析和学习&#xff0c;生成新的艺术品或图像。 AI绘画的应用场景非常广泛&#xff0c;包括数字艺术、游戏…

使用 GitHub 远程仓库

使用 GitHub 远程仓库 GitHub 是最大的 Git 版本库托管商&#xff0c;是成千上万的开发者和项目能够合作进行的中心。 大部分 Git 版本库都托管在 GitHub&#xff0c;很多开源项目使用 GitHub 实现 Git 托管、问题追踪、代码审查以及其它事情。本篇文章主要带大家上手 GitHub …

模型Model:文件系统模型QFileSystemModel

一、 1、常用函数 QFileSystemModel自带目录变化监听 1)、 QModelIndex setRootPath(const QString &path); 设置检索根目录 2)、 bool isDir(const QModelIndex &index) const; 选中索引是否为目录节点 3)、 QString filePath(const QModelIndex &index) const;…

Python:list列表与tuple元组的区别

在Python中&#xff0c;List&#xff08;列表&#xff09; 和Tuple&#xff08;元组&#xff09; 都是用于存储一组有序元素的数据结构&#xff0c;但它们有一些关键的区别&#xff0c;包括可变性、性能、语法等方面。 1. List&#xff08;列表&#xff09; 用法&#xff1a;…

Git 提交前缀规范

Git 提交前缀规范 feat : 新功能。添加一个新的用户界面元素、一个新的功能或一个新的 API fix : 修复 bug。修复一个导致应用程序崩溃的错误、一个导致数据丢失的错误或一个导致用户体验不佳的错误 docs : 文档更新。更新你的应用程序的用户指南、更新你的 API 文档或更新你…

【分布式技术】分布式存储ceph之RBD块存储部署

目录 创建 Ceph 块存储系统 RBD 接口 服务端操作 1、创建一个名为 rbd-demo 的专门用于 RBD 的存储池 2、将存储池转换为 RBD 模式 3、初始化存储池 4、创建镜像 5、在管理节点创建并授权一个用户可访问指定的 RBD 存储池 6、修改RBD镜像特性&#xff0c;CentOS7默认情…

算法 - 二分法 / 双指针 / 三指针 / 滑动窗口

文章目录 &#x1f37a; 二分法&#x1f37b; 旋转数组&#x1f942; 33. 搜索旋转排序数组 [旋转数组] [目标值] (二分法) &#x1f37b; 元素边界&#x1f942; 34. 在排序数组中查找元素的第一个和最后一个位置 [有序数组] > [元素边界] > (二分法)&#x1f942; 81. …

IOS元素定位对应关系

resource-id也称为id&#xff0c;resource-id是唯一的 # 元素定位 agree_continue_id "com.baidu.searchbox:id/positive_button" WebDriverWait(driver, 10, 1).until(EC.visibility_of_element_located((MobileBy.ID, agree_continue_id))) driver.find_element…

Databend 开源周报第 128 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 使用 Databend …

[Linux 进程(四)] 再谈环境变量,程序地址空间初识

文章目录 1、前言2、环境变量2.1 main函数第三个参数 -- 环境参数表2.2 本地环境变量和env中的环境变量2.3 配置文件与环境变量的全局性2.4 内建命令与常规命令2.5 环境变量相关的命令 3、程序地址空间 1、前言 上一篇我们讲了环境变量&#xff0c;如果有不明白的先读一下上一…

C++ 编程需要什么样的开发环境?

C 编程需要什么样的开发环境&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#…

C++ 拾遗 2

1.变量的作用域 1&#xff09;全局变量 在整个程序生命周期内都是有效的&#xff0c;在定义位置之后的任意函数中都能访问。 全局变量在主程序退出时由系统收回内存空间。 2&#xff09;局部变量 在函数或语句块内部的语句使用&#xff0c;在函数或语句块外部是不可用的。 …

网页设计-用户体验

Use Cases (用例) 用例是用户如何在网站上执行任务的书面描述&#xff0c;从用户的角度描述了系统响应请求时的行为。每个用例都是用户实现目标的一系列简单的步骤。简言之&#xff0c;用例是一种用于描述系统如何满足用户需求的方法。 用例的好处 1. 明确需求&#xff1a; Use…

Python办公自动化 – 可以解析的文件格式和可以调用的API实现办公自动化

Python办公自动化 – 可以解析的文件格式和可以调用的API实现办公自动化 以下是往期的文章目录&#xff0c;需要可以查看哦。 Python办公自动化 – Excel和Word的操作运用 Python办公自动化 – Python发送电子邮件和Outlook的集成 Python办公自动化 – 对PDF文档和PPT文档的处…

Unity与Android交互通信系列(4)

上篇文章我们实现了模块化调用&#xff0c;运用了模块化设计思想和简化了调用流程&#xff0c;本篇文章讲述UnityPlayerActivity类的继承和使用。 在一些深度交互场合&#xff0c;比如Activity切换、程序启动预处理等&#xff0c;这时可能会需要继承Application和UnityPlayerAc…