《C语言实现各种排序算法》
文章目录
- 一、排序
- 1、排序的各种方式分类
- 二、插入排序
- 1、直接插入排序
- 2、希尔排序
- 3、希尔排序时间复杂度分析
- 三、选择排序
- 1、直接选择排序
- 2、堆排序
- 四、交换排序
- 1、冒泡排序
- 2、快速排序
- 3、快速排序hoare找基准值
- 4、快排挖坑法找基准值
- 5、前后指针法
- 6、快速排序非递归实现
- 五、归并排序
- 1、递归实现
- 2、非递归实现
- 六、排序算法复杂度及稳定性分析
- 七、计数排序
一、排序
在生活中各种场景中都会有排序的身影存在,在网购时会有价格排序,在学校中会有程序排序,在游戏中会有段位的排序等。
1、排序的各种方式分类
这些排序的效率各有不同
二、插入排序
直接插⼊排序是⼀种简单的插⼊排序法,其基本思想是:把待排序的记录按其关键码值的⼤⼩逐个插⼊到⼀个已经排好序的有序序列中,直到所有的记录插⼊完为⽌,得到⼀个新的有序序列 。
1、直接插入排序
当插⼊第 i(i>=1) 个元素时,前⾯的 array[0],array[1],…,array[i-1] 已经排好序,此时⽤ array[i] 的排序码与 array[i-1],array[i-2],… 的排序码顺序进⾏⽐较,找到插⼊位置即将 array[i] 插⼊,原来位置上的元素顺序后移
代码实现:
void InsertionSort(int* arr, int n)
{int i = 0;int j = 0;for ( i = 1; i < n; i++){j = i-1;int tmp = arr[i];while (j >= 0){if (arr[j] < tmp){arr[j + 1] = arr[j];j--;}else{break;}}arr[j + 1] = tmp;}
}
2、希尔排序
直接插入排序效率不高,在直接插入排序的基础上进行优化,改进,把一个大的集合分为若干个小的集合再进行直接插入排序,从而提升效率。
希尔排序法⼜称缩⼩增量法。希尔排序法的基本思想是:先选定⼀个整数(通常是gap = n/3+1),把待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,当gap=1时,就相当于直接插⼊排序。
代码实现:
void ShellSort(int* arr, int n)
{int gec = n;int i, j = 0;while (gec > 1){gec = gec / 3 + 1;for (i = gec; i < n; i++){j = i - gec;int tmp = arr[i];while (j >= 0){if (arr[j] < tmp){arr[j + gec] = arr[j];j -= gec;}else{break;}}arr[j + gec] = tmp;}}
}
3、希尔排序时间复杂度分析
外层循环的时间复杂度可以直接给出为: O(log2 n) 或者 O(log3 n) ,即 O(log n)
内层循环:
希尔排序的时间复杂度大约为 log 2 n 1.3 \log_2 {n^{1.3}} log2n1.3
三、选择排序
每⼀次从待排序的数据元素中选出最⼩(或最⼤)的⼀个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
1、直接选择排序
void SelectSort(int* a, int n)
{int begin = 0, end = n - 1;while (begin < end){int max = begin, min = begin;for (int i = begin + 1; i <= end; i++){if (a[i] < a[min]){min = i;}if (a[i] > a[max]){max = i;}}if (max == begin){max = min;}{int tmp = a[min];a[min] = a[begin];a[begin] = tmp;}{int tmp = a[max];a[max] = a[end];a[end] = tmp;}begin++;end--;}
}
2、堆排序
void HeapSort(int* arr, int n)
{int i = 0;for (i = (n-1)/2; i>=0; i--){int parent = i;int child = parent * 2 + 1;while (child <= i){if (child + 1 <= i && arr[child + 1] < arr[child]){child++;}if (arr[child] < arr[parent]){int tmp = arr[parent];arr[parent] = arr[child];arr[child] = tmp;parent = child;child = parent * 2 + 1;}else{break;}}}for (i = n - 1; i > 0; i--){int child = i;int parent = 0;int tmp = arr[parent];arr[parent] = arr[child];arr[child] = tmp;child = parent * 2 + 1;while (child < i){if (child + 1 < i && arr[child + 1] < arr[child]){child++;}if (arr[child] < arr[parent]){tmp = arr[parent];arr[parent] = arr[child];arr[child] = tmp;parent = child;child = parent * 2 + 1;}else{break;}}}
}
堆排序的时间复杂度为n log n \log n logn
四、交换排序
1、冒泡排序
void BubbleSort(int* a, int n)
{for (int i = 0; i < n - 1; i++){int falg = 1;for (int j = 0; j < n - 1 - i; j++){if (a[j] > a[j + 1]){int tmp = a[j];a[j] = a[j + 1];a[j + 1] = tmp;falg = 0;}}if (falg){break;}}
}
2、快速排序
通过找基准值,基准值的位置就是这个值该待的位置,然后递归找基准值左边区间和右区间,直到区间不成立位置,确定每个值该待的位置完成排序。
int _QuickSort(int* a, int left, int right)
{int keyi = left;left++;while (left <= right){while (left <= right && a[left] < a[keyi]){left++;}while (left <= right && a[right] > a[keyi]){right--;}if (left <= right){int tmp = a[left];a[left] = a[right];a[right] = tmp;left++;right--;}}int tmp = a[keyi];a[keyi] = a[right];a[right] = tmp;return right;
}void QuickSort(int* a, int left,int right)
{if (left >= right){return;}int keyi = _QuickSort(a, left, right);QuickSort(a, keyi + 1, right);QuickSort(a, left, keyi - 1);}
快排的空间复杂度:O( l o n g n long n longn)
快排的时间复杂度:O(n l o n g n long n longn)
3、快速排序hoare找基准值
//快速排序hoare版本
int PartSort1(int* a, int left, int right)
{int keyi = left;++left;while (left < right){while (left <=right && a[right] > a[keyi]){right--;}while (left <= right && a[left] < a[keyi]){left++;}if (left < right){swap(&a[left], &a[right]);}}swap(&a[keyi], &a[right]);return right;
}
4、快排挖坑法找基准值
// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{int hole = left;int tmp = a[hole];while (left < right){while (left < right && a[right] > tmp){right--;}a[hole] = a[right];hole = right;while (left < right && a[left] < tmp){left++;}a[hole] = a[left];hole = left;}a[hole] = tmp;return hole;
}
5、前后指针法
// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{int pfast = left + 1;int pslow = left;int keyi = left;while (pfast <= right){while (pfast <= right && a[pfast] < a[keyi] && ++pslow != pfast){swap(&a[pslow], &a[pfast]);}pfast++;}swap(&a[pslow], &a[keyi]);return pslow;
}
6、快速排序非递归实现
// 快速排序 非递归实现//运用栈数据结构
typedef int StackDataType;typedef struct Stack
{int* a;int capacity;int top;
}ST;//栈初始化
void STInit(ST* ps)
{ps->a = NULL;ps->capacity = ps->top = 0;
}//入栈
void STPush(ST* ps,StackDataType x){if (ps->capacity == ps->top){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;int* tmp = (int*)realloc(ps->a, newcapacity * sizeof(StackDataType));if (tmp == NULL){perror("realloc fail");return;}ps->capacity = newcapacity;ps->a = tmp;tmp = NULL;}ps->a[ps->top++] = x;
}//判断栈是否为空
bool STEmpty(ST* ps)
{return ps->top == 0;
}//出栈
void STPop(ST* ps)
{if (ps->top == 0){return;}ps->top--;
}//取栈顶元素
StackDataType STTop(ST* ps)
{if (ps->top == 0){exit(1);}return ps->a[ps->top - 1];
}void QuickSortNonR(int* a, int left, int right)
{ST s;STInit(&s);STPush(&s, right);STPush(&s, left);while (!STEmpty(&s)){int begin = STTop(&s);STPop(&s);int end = STTop(&s);STPop(&s);int pfast = begin + 1;int pslow = begin;int keyi = begin;while (pfast <= end){while (pfast <= end && a[pfast] < a[keyi] && ++pslow != pfast){swap(&a[pslow], &a[pfast]);}pfast++;}swap(&a[pslow], &a[keyi]);if (pslow + 1 < end){STPush(&s, end);STPush(&s, pslow + 1);}if (pslow - 1 > begin){STPush(&s, pslow - 1);STPush(&s, begin);}}
五、归并排序
归并排序算法思想:
归并排序(MERGE-SORT)是建⽴在归并操作上的⼀种有效的排序算法,该算法是采⽤分治法(DivideandConquer)的⼀个⾮常典型的应⽤。将已有序的⼦序列合并,得到完全有序的序列;即先使每个⼦序列有序,再使⼦序列段间有序。若将两个有序表合并成⼀个有序表,称为⼆路归并。
1、递归实现
代码实现:
//归并排序
void _MergeSort(int* arr, int left, int right, int* tmp)
{if (left >= right){return;}int mid = (right - left) / 2 + left;_MergeSort(arr, left, mid, tmp);_MergeSort(arr, mid + 1, right,tmp);//合并int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int begin = left;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[begin++] = arr[begin1++];}else{tmp[begin++] = arr[begin2++];}}while (begin1 <= end1){tmp[begin++] = arr[begin1++];}while (begin2 <= end2){tmp[begin++] = arr[begin2++];}//传值while (left <= right){arr[left] = tmp[left];left++;}
}void MergeSort(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n - 1, tmp);free(tmp);tmp = NULL;
}
2、非递归实现
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");exit(1);}int k = 1;while (k < n){int i = 0;for (i = 0; i < n - 2 * k + 1;i += 2*k){int mid = i + k - 1;int left = i;int right = i + 2 * k - 1;int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int begin = left;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[begin++] = a[begin1++];}else{tmp[begin++] = a[begin2++];}}while (begin1 <= end1){tmp[begin++] = a[begin1++];}while (begin2 <= end2){tmp[begin++] = a[begin2++];}while (left <= right){a[left] = tmp[left];left++;}}if (i < n-k){int mid = i+k-1;int left = i;int right = n-1;int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int begin = left;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[begin++] = a[begin1++];}else{tmp[begin++] = a[begin2++];}}while (begin1 <= end1){tmp[begin++] = a[begin1++];}while (begin2 <= end2){tmp[begin++] = a[begin2++];}while (left <= right){a[left] = tmp[left];left++;}}k *= 2;}free(tmp);
}
六、排序算法复杂度及稳定性分析
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,⽽在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
七、计数排序
只能排序整数,不适合排不集中的数据如1,10000000,100000002;会产生空间浪费
// 计数排序
void CountSort(int* a, int n)
{int min = a[0], max = a[0];for (int i = 1; i < n; i++){if (min > a[i]){min = a[i];}if (max < a[i]){max = a[i];}}int range = max - min + 1;int* count = (int*)calloc(range ,sizeof(int));for (int i = 0; i < n; i++){count[a[i]-min]++;}int indext = 0;for (int i = 0; i < range; i++){while (count[i]--){a[indext++] = i + min;}}free(count);count = NULL;
}
相关文章:

《C语言实现各种排序算法》
文章目录 一、排序1、排序的各种方式分类 二、插入排序1、直接插入排序2、希尔排序3、希尔排序时间复杂度分析 三、选择排序1、直接选择排序2、堆排序 四、交换排序1、冒泡排序2、快速排序3、快速排序hoare找基准值4、快排挖坑法找基准值5、前后指针法6、快速排序非递归实现 五…...
【888题竞赛篇】第五题,2023ICPC澳门-传送(Teleportation)
这里写自定义目录标题 更多精彩内容256题算法特训课,帮你斩获大厂60W年薪offer 原题2023ICPC澳门真题传送B站动画详解 问题分析思路分析图的构建最短路径算法具体步骤 算法实现Dijkstra 算法图的构建 代码详解标准代码程序C代码Java代码Python代码Javascript代码 复…...

javascript写一个页码器-SAAS本地化及未来之窗行业应用跨平台架构
一代码 接引入 <script type"text/javascript" src"CyberWin_APP_Page.js" alt"未来之窗页码"></script>function 未来之窗页面触发器(页码){console.log("当前用户新"页码);}CyberWin_Page.set_callback(未来之窗页面触发…...
微信小程序如何自定义一个组件
微信小程序支持组件化开发,这有助于我们复用代码,提高开发效率。下面我将给出一个简单的微信小程序组件化示例,包括一个自定义组件的创建和使用。 1. 创建自定义组件 首先,在项目的 components 目录下创建一个新的组件文件夹&am…...

【数学建模备赛】Ep05:斯皮尔曼spearman相关系数
文章目录 一、前言🚀🚀🚀二、斯皮尔曼spearman相关系数:☀️☀️☀️1. 回顾皮尔逊相关系数2. 斯皮尔曼spearman相关系数3. 斯皮尔曼相关系数公式4. 另外一种斯皮尔曼相关系数定义5. matlab的用法5. matlab的用法 三、对斯皮尔曼相…...
MATLAB进行神经网络建模的案例
下面是一个使用MATLAB进行神经网络建模的案例,该案例涉及使用神经网络来逼近一个未知系统的输入输出关系。这个案例与您提到的学习资料中的实例类似,但我会简化并解释每个步骤。 案例背景 假设我们有一组输入和输出数据,我们希望通过建立一…...
每天一个数据分析题(四百八十九)- 主成分分析与因子分析
关于主成分分析和因子分析的区别,下列描述正确的是( ) A. 主成分分析是一种无监督学习算法,而因子分析是一种有监督学习算法 B. 主成分分析是一种线性变换方法,而因子分析是一种非线性变换方法 C. 主成分分析的结果…...
Java RPC、Go RPC、Node RPC、Python RPC 之间的互相调用
Java RPC、Go RPC、Node RPC、Python RPC 之间的互相调用是完全可以实现的,但需要满足一些条件和依赖于特定的工具和协议。以下是如何实现不同语言之间的RPC互相调用的详细解释: 1. 使用通用协议和标准:gRPC gRPC 是一个高性能、开源的RPC框…...

国外代理IP选择:IP池的大小有何影响
代理IP是跨境人不可或缺的工具,广泛应用于广告验证、数据获取和账号矩阵管理等方面。而在选择代理IP时,IP池的大小往往是一个至关重要的考量因素。本文将深入解析IP池大小对代理IP选择的影响,帮助大家更好地理解这一关键决策点。 一、IP池的…...

手机谷歌浏览器怎么用
谷歌浏览器不仅在PC端受欢迎,在移动端也是广泛应用的。为了帮助大家更好的理解和使用手机谷歌浏览器,本文将详细介绍如何使用手机谷歌浏览器,对这款浏览器感到陌生的话就快快学起来吧。(本文由https://chrome.cmrrs.com/站点的作者…...
Button窗口部件
# 2. Button窗口部件 # 简单说明: # Button(按钮)部件是一个标准的Tkinter窗口部件,用来实现各种按钮。按钮能够包含文本或图象, # 并且你能够将按钮与一个Python函数或方法相关联。当这个按钮被按下时,Tki…...

PCIe学习笔记(25)
数据完整性 PCI Express的基本数据可靠性机制包含在数据链路层(data Link Layer)中,它使用32位的LCRC (CRC)码逐链路检测TLP中的错误,并采用逐链路重传机制进行错误恢复。TLP是一个数据和事务控制单元,由位于PCI Express域“边缘”的数据源(…...
8.20
上午 1、使用ansible安装并启动ftp服务 [root1 ~]# vim /etc/ansible/hosts s0 ansible_ssh_host10.0.0.12 ansible_ssh_port22 ansible_ssh_userroot ansible_ssh_pass1 s1 ansible_ssh_host10.0.0.13 ansible_ssh_port22 ansible_ssh_userroot ansible_ssh_pass1 s2 ansi…...
centos7.9系统安装talebook个人书库
1.简介: talebook —— 一个基于Calibre的简单的个人图书管理系统,支持在线阅读。 2.环境准备: #使用阿里源 wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo #安装docker yu…...

ES高级查询Query DSL查询详解、term术语级别查询、全文检索、highlight高亮
文章目录 ES高级查询Query DSLmatch_all返回源数据_source返回指定条数size分页查询from&size指定字段排序sort 术语级别查询term query术语查询terms query多术语查询range query范围查询exists queryids queryprefix query前缀查询wildcard query通配符查询fuzzy query模…...

关于Blender云渲染农场,你应该知道的一切!
Blender是一个功能强大的免费开源3D创作套件,提供了广泛的工具和特性,因此受到了许多3D艺术家的喜爱。在创建3D场景的过程中,渲染作为最后一步,常常是许多艺术家头疼的问题,因为它不仅耗时,还占用了他们的计…...

Obsidian如何安装插件
文章目录 前言开始安装写在最后 前言 没有插件的 Obsidian 是不完整的 Obsidian,如果你正在使用 Obsidian,一定要会安装插件。 本文将告诉你如何安装 Obsidian 第三方插件。 开始安装 首先进入 Obsidian 界面。 点击左下角的设置图标,就…...

Nginx服务器申请及配置免费SSL证书
免费SSL证书申请 背景: 我的情况是这样,域名解析是华为云的,然后免费证书在腾讯云申请。但是大致的配置流程都是一样的 在腾讯云平台申请免费的SSL证明(目前有效期是9天),申请步骤如下 主要步骤说明 申请免费SSL证书配置证书到域…...

STM32CubeMX 配置串口通信 HAL库
一、STM32CubeMX 配置串口 每个外设生成独立的 ’.c/.h’ 文件 不勾:所有初始化代码都生成在 main.c 勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。 二、重写fputc函数 #include <stdio.h>#ifdef __GNUC__#def…...

GitHub的未来:在微软领导下保持独立与AI发展的平衡
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...