基本的五大排序算法

目录

一,直接插入算法

二,希尔排序算法

三,选择排序

四,堆排序

五,冒泡排序算法


简介:

        排序算法目前是我们最常用的算法之一,据研究表明,目前排序占用计算机CPU的时间已高达百分之30到百分之50。可见,高效率的排序算法是我们必须掌握的基本算法之一,本篇博客就先跟大家介绍五种常用的排序算法:直接插入算法,希尔算法,选择算法,堆排序算法,冒泡算法。

一,直接插入算法

        直接插入算法的原理与我们打扑克牌时,进行不摸牌排序的效应一样。平常我们在打扑克牌时会不断的摸牌,每当我们摸到一个牌时就会往里面插入,使得我们手中的排有序。直接插入算法与之同理,其基本思想是把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列种,直到所有的记录插入完为止,得到一个新的有序序列,即摸牌效应,如下图,是插入排序的示意图:cbbddbcf00724df98c8b5eba624928ea.gif


        明白以上原理后,接下来要思考的是此算法的效率如何,不难发现,当为最好情况时(即有序排列),将一次性直接遍历整个数组,时间复杂度为O(N);当为最坏情况是(即要跟排列的顺序相反),需要一直往首元素插入,此时的时间复杂度为O(N^2)。具体代码如下:

#include <stdio.h>
//直接插入算法
void InsertSort(int* a, int n) {for (int i = 0; i < n - 1; i++) {// [0,end]有序,把end+1位置的插入到前序序列,控制[0,end+1]有序int end = i;int next = a[i + 1];// 升序排列while (end >= 0) {if (a[end] > next) {a[end + 1] = a[end];}else {break;}end--;}a[end + 1] = next;}
}
int main() {int a[] = { 5,9,7,3,0,1,4,2,6,8 };InsertSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++) {fprintf(stdout, "%d ", a[i]);}puts("");return 0;
}

运行图:

8c03d4451dab45979beda78308fd8322.png


二,希尔排序算法

        希尔排序是以插入排序为基础的排序。首先,该算法要设置一个分组,然后再用直接插入算法的思想进行预排序,预排序是将数据分组排序,每组数据之间有着一定的间距。如下图:

c00f8c71fda44afab1b44f5fdaa8d8f3.png

        上图中,第一组数据:9,5,8,5。第二组数据:1,7,6。第三组数据:2,4,3。三组数据先分别用直接插入算法进行预排序,排序后第一组数据为5,5,8,9。第二组数据为1,6,7。第三组数据为2,3,4。经过这些预排序后,整体的数据为5  1  2  5  6  3  8  7  4  9(不同颜色代表不同组中的数据,可直观的看出)。

        其中,将数据进行预排序的目的是大的数据更快的到后面去,小的数据更快的到前面去,其中,间距越大跳得越快,越不接近有序;间距越小跳得越慢,越接近有序,当间距为1时,直接为有序,因为,当间距为1时就是直接插入排序。

        希尔算法运用得原理就是给定一个间距值进行预排序,当间距值大于1时进行的排序为预排序,当间距值等于1时的排序就是直接插入排序,即排序已完成。本算法的效率很高,但时间复杂度很难计算出,暂时先不研究这个,代码实现具体如下:

#include <stdio.h>
//希尔排序算法
void ShellSort(int* a, int n) {int grab = n;//开始时,设置间距grab = n;//当grab == 1时为直接插入算法,当grab > 1时为预排序while (grab != 1) {//grab /= 2;//不断的缩减grab的大小,直到grab == 1排序完成//由于grab一次性的缩减比较小,导致算法效率较低,以下的grab为改进算法,提高算法效率grab = grab / 3 + 1;//不断缩减间距grab的大小,直到grab == 1排序完成//以下是根据间距grab的大小来进行的插入排序for (int j = 0; j < grab; j++) {for (int i = j; i < n - grab; i += grab) {int end = i;int x = a[i + grab];while (end >= 0) {if (a[end] > x) {a[end + grab] = a[end];}else {break;}end -= grab;}a[end + grab] = x;}}}
}
int main() {int a[] = { 5,9,7,3,0,1,4,2,6,8 };ShellSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++) {fprintf(stdout, "%d ", a[i]);}puts("");return 0;
}

运行图:

becf500f9ba94dafb29bbf8610299968.png


三,选择排序

1,选择排序的基本思想:

        每一次从待排序的数据元素中选出最小或最大的一个元素,存放在系列的起始位置,即进行一趟选择,直到全部待排序的数据元素排完,其中时间复杂度:O(N^2)。空间复杂度:O(1)。如下图:

1b799e0b19b44a5bad38455dd945756e.gif


        以上就是选择排序的基本套路,但我们仔细思考下来,其实这种方法还有优化空间,当数据进行一趟选择时,我们可直接选出最大数和最小数,将其放在开头或末尾。然后再次进行遍历,直到头尾遍历相遇为止。代码如下:

#include <stdio.h>
//选择算法
void Swap(int* x1, int* x2) {int t = *x1;*x1 = *x2;*x2 = t;
}
void SelectSort(int* a, int n) {int begin = 0, end = n - 1;while (begin < end) {int max = begin, min = begin;//进行一趟遍历,确定最小值和最大值的下标,当前面遍历等于end时排序就已排好for (size_t i = begin + 1; i < end; i++) {if (a[max] < a[i]) {max = i;}if (a[min] > a[i]) {min = i;}}Swap(a + max, a + end);//当min在最后时,max与原先的end交换了位置,所以这时的end的下标已经变了if (min == end) {min = max;}Swap(a + min, a + begin);//前面排好,往后前进begin++;//后面排好,往前前进end--;}
}
int main() {int a[] = { 5,9,7,3,0,1,4,2,6,8 };SelectSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++) {fprintf(stdout, "%d ", a[i]);}puts("");return 0;
}

运行图:

bb38e77485f7424887864e60aafa71a5.png


四,堆排序

        堆排序跟二叉堆排序一模一样,即先建立堆结构,然后进行堆的调整,使整体有序。要注意的是,升序排列首选大堆,降序排列首选小堆建立。(这一原理运用的是二叉树的知识,如若感觉有困难,就必须先把二叉树的堆结构再学习下。不建议直接上来搞这一块知识)。其中结构上是选择堆结构上的选择排序,结构图如下:

7ce2be480a244150a4d25854eb4de07c.png

        由于原理与之前的二插堆一样,在这里就不做过多结构上的说明,下面是代码的实现和讲解:

#include <stdio.h>
void Swap(int* x1, int* x2) {int t = *x1;*x1 = *x2;*x2 = t;
}
//归并算法
void Adjustdown(int* a, int n, int parent) {int child = 2 * parent + 1;while (child < n) {if (child + 1 < n && a[child] < a[child + 1]) {child++;}if (a[child] > a[parent]) {Swap(a + child, a + parent);parent = child;child = parent * 2 + 1;}else {break;}}
}
//以升序为例,升序用建大堆思想
void HeapSort(int* a, int n) {//从最后一层走起,因为要保证导入的parent往下都是有序的,即大堆建立for (int i = (n - 1 - 1) / 2; i >= 0; i--) {Adjustdown(a, n, i);}//大堆建立后根为最大数,然后进行排序int end = n - 1;while (end > 0) {Swap(a, a + end);//因为根为最大数,要升序就要把最大数放入最后Adjustdown(a, end, 0);end--;}
}
int main() {//归并算法int a[] = { 5,9,7,3,0,1,4,2,6,8 };HeapSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++) {fprintf(stdout, "%d ", a[i]);}puts("");return 0;
}

运行图:

733610906033452682b0570acb3e9784.png


五,冒泡排序算法

        冒泡排序是一种交换排序,所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,此种交换的特点是将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动,其中时间复杂度:O(N^2);空间复杂度:O(1)。

冒泡排序的原理图:

c28419fdc0f441048b337a84ca87b598.gif

此种排序非常简单,具体代码如下:

#include <stdio.h>
void Swap(int* x1, int* x2) {int t = *x1;*x1 = *x2;*x2 = t;
}
//冒泡排序算法
void BubbleSort(int* a, int n)
{for (size_t j = 0; j < n; j++){//用x进行控制,可提升算法的效率int x = 0;for (size_t i = 1; i < n - j; i++){//进行排序,当没有进入此步时,说明是有序的if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);x = 1;}}//当x == 0时,说明序列是有序的,可直接跳出,提升算法的效率if (x == 0){break;}}
}
int main() {//冒泡算法int a[] = { 5,9,7,3,0,1,4,2,6,8 };BubbleSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++) {fprintf(stdout, "%d ", a[i]);}puts("");return 0;
}

运行图:

6060a2e144b746dc96dd61380f7eb6e4.png


总:在五种排序算法中,效率最高的是希尔排序,效率最低的是冒泡排序,堆排序与希尔不相上下,但堆排序实现起来比较麻烦,因此个人建议首选希尔,直接插入算法比选择排序算法和冒泡略高一筹,但在进行大量数据排序时,效率都不高,因此,在五大基本排序中,希尔排序为最佳选择。

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

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

相关文章

数据挖掘实验(一)数据规范化【最小-最大规范化、零-均值规范化、小数定标规范化】

一、数据规范化的原理 数据规范化处理是数据挖掘的一项基础工作。不同的属性变量往往具有不同的取值范围&#xff0c;数值间的差别可能很大&#xff0c;不进行处理可能会影响到数据分析的结果。为了消除指标之间由于取值范围带来的差异&#xff0c;需要进行标准化处理。将数据…

Linux性能优化--性能工具:系统内存

3.0.概述 本章概述了系统级的Linux内存性能工具。本章将讨论这些工具可以测量的内存统计信息&#xff0c;以及如何使用各种工具收集这些统计结果。阅读本章后&#xff0c;你将能够&#xff1a; 理解系统级性能的基本指标&#xff0c;包括内存的使用情况。明白哪些工具可以检索…

由于计算机中丢失msvcp110.dll的解决方法与msvcp110.dll丢失修复方法

相信大家在打开电脑软件或许游戏都有遇到过电脑提示找不到msvcp110.dll文件&#xff0c;导致软件游戏打不开&#xff0c;我们应该怎么办&#xff1f;不用着急&#xff0c;今天小编我分享我找了很久成功解决问题的方法给大家&#xff0c;希望可以帮到各位。 1. 使用DLL修复工具&…

电子计算机核心发展(继电器-真空管-晶体管)

目录 继电器 最大的机电计算机之一——哈弗Mark1号&#xff0c;IBM1944年 背景 组成 性能 核心——继电器 简介 缺点 速度 齿轮磨损 Bug的由来 真空管诞生 组成 控制开关电流 继电器对比 磨损 速度 缺点 影响 代表 第一个可编程计算机 第一个真正通用&am…

【C语言】函数的定义、传参与调用(一)

目录 导读&#xff1a; 1. 为什么要用函数 2. C语言中函数的分类 2.1 库函数 2.1.1 什么是库函数 2.1.2 C语言常用的库函数 2.2 自定义函数 2.2.1 什么是自定义函数 2.2.2 定义函数的方法 2.2.3 举例 3. 函数的参数 3.1 传参不同的对比 3.2 形式参数&#xff08;形…

ASUS (k013) ME176CX不进入系统恢复出厂设置的方法

k013 me176cx ASUS k013 ME176CX不进入系统恢复出厂设置的方法 当忘记系统密码或系统异常导致无法进入系统时&#xff0c;可以按以下步骤尝试不进入系统恢复出厂设置来解决。 注意&#xff1a;执行恢复出厂设置前&#xff0c;请先将资料备份至外接设备&#xff0c;否则资料都…

Linux基本指令(上)——“Linux”

各位CSDN的uu们好呀&#xff0c;今天&#xff0c;小雅兰的内容是Linux啦&#xff01;&#xff01;&#xff01;主要是Linux的一些基本指令和Linux相关的基本概念&#xff08;系统层面&#xff09;&#xff0c;下面&#xff0c;让我们进入Linux的世界吧&#xff01;&#xff01;…

微服务技术栈-Ribbon负载均衡和Nacos注册中心

文章目录 前言一、Ribbon负载均衡1.LoadBalancerInterceptor&#xff08;负载均衡拦截器&#xff09;2.负载均衡策略IRule 二、Nacos注册中心1.Nacos简介2.搭建Nacos注册中心3.服务分级存储模型4.环境隔离5.Nacos与Eureka的区别 总结 前言 在上面那个文章中介绍了微服务架构的…

金融机构操作风险与内控合规的介绍

目录 一.前言 术语 二.功能设计 三.部分功能简介 流程管理 流程清单 流程详情 流程重检 流程重检反馈 风险与控制自我评估&#xff08;RCSA&#xff09; 评估计划管理 评估结果管理 关键风险指标&#xff08;KRI&#xff09; 指标库管理 基础数据项录入 指标监测…

使用晶体管做布尔逻辑和逻辑门

目录 二进制&#xff0c;三进制&#xff0c;五进制 true&#xff0c;false表示0&#xff0c;1 早期计算机采用进制 布尔逻辑 三个基本操作&#xff1a;NOT,AND,OR 基础“真值表” NOT 如何实现&#xff1f; AND如何实现&#xff1f; OR如何实现&#xff1f; 图标表示…

Collagen

\ collagen XV/XVIII, Endostatin- angiogenesis inhibitor; c-type lectin 结构&#xff1b; TSP ( 含有 Laminin-G)

BIT.8_Linux 多线程

lesson35: 一、 1.OS调度的基本单位&#xff08;0&#xff1a;13&#xff1a;5&#xff09; 2.进程XXXX&#xff08;0&#xff1a;14&#xff1a;15&#xff09; a.进程的内核数据结构包含哪几个部分&#xff1f;&#xff08;n个&#xff09;&#xff08;0&#xff1a;15&a…

openGauss学习笔记-88 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用将磁盘表转换为MOT

文章目录 openGauss学习笔记-88 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用将磁盘表转换为MOT88.1 前置条件检查88.2 转换88.3 转换示例 openGauss学习笔记-88 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用将磁盘表转换为MOT …

MQTT 服务器搭建(基于mosquitto)

1、前言 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布/订阅&#xff08;publish/subscribe&#xff09;模式的"轻量级"通讯协议&#xff0c;该协议构建于TCP/IP协议上&#xff0c;…

Vue项目搭建图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 预备工作 请在本地创建文件夹用于存放Vue项目&#xff0c;例如&#xff1a;创建HelloWorld文件夹存放即将创建的Vue新项目。 创建Vue项目 首先&#xff0c;请在DOS中将目录…

八大排序源码(含优化)

文章目录 1、直接插入排序2、希尔排序3、选择排序4、冒泡排序5、堆排序6、快速排序快速排序递归实现霍尔法挖坑法前后指针法快速排序小区间优化 快速排序非递归实现 7、归并排序归并排序递归实现归并排序非递归 8、计数排序 大家好&#xff0c;我是纪宁&#xff0c;这篇文章是关…

[Realtek sdk-3.4.14b]RTL8197FH-VG 2.4G to WAN吞吐量低于60%的问题分析及解决方案

问题描述 RTL8197FH-VG 2.4G wifi to WAN吞吐量低于65%的标准,正常2T2R的wifi 300Mbps x 65% = 195Mbps,但是实际只能跑到160Mbps,这个时候CPU的idl已经为0,sirq占用率达到98%左右 网络拓扑 一台PC通过2.4G WiFi连接到RTL8197FH-VG,另外一台PC直接通过WAN口连接到RTL8197…

【pwn入门】用gdb实现第1个pwn

声明 本文是B站你想有多PWN学习的笔记&#xff0c;包含一些视频外的扩展知识。 有问题的源码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> char sh[]"/bin/sh"; int func(char *cmd){system(cmd);return 0; }int main(){char …

MongoDB快速上手

文章目录 1、mongodb相关概念1.1、业务应用场景1.2、MongoDB简介1.3、体系结构1.3.1 数据库 (databases) 管理语法1.3.2 集合 (collection) 管理语法 1.4、数据模型1.5、MongoDB的特点 2、单机部署3、基本常用命令3.1、案例需求3.2、数据库操作3.2.1 选择和创建数据库3.2.2 数据…

新一代网络框架UringNet,基于最新的异步I/O

介绍 在去年的一篇文章中&#xff0c;笔者曾经提到了最新一代的网络I/O框架UringNet。具体内容可以参考Rings’ Power,性能“世界第一”的Web I/O框架。这是基于最新Linux内核的异步I/O组件io_uring开发的网络框架。由于采用了最新的异步框架&#xff0c;因此在同等硬件配置条件…