《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领…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
