《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领…...

RGB与YUV格式详解
图像处理 文章目录 图像处理前言一、RGB格式二、YUV格式三、RGB与YUV转换四、NV21转换为YUV420p五、YUV旋转 前言 在图像的世界里,一般使用RGB作为存储格式。而在视频的世界里,一般使用YUV作为压缩存储格式。有时候面试官会问:为什么视频使用…...

JS获取当前浏览器名称
在JavaScript中,获取当前浏览器名称的方法并不是一个标准的功能,因为浏览器厂商并没有提供一个直接的API来获取浏览器的名称。但是,你可以通过分析用户代理字符串(User-Agent)来推断出浏览器的名称。 以下是一个简单的…...

学习计算机网络(五)——ICMP协议
ICMP 协议(Internet Control Message Protocol,互联网控制报文协议),主要用于在 IP 网络中传递控制消息和差错报告。 ICMP在IP系统间传递差错和管理报文,是任何IP实现必需和要求的组成部分。 可把ICMP报文分成两类&a…...

request.getRequestURI()与request.getRequestURL()的区别
1.返回值的区别: request.getRequestURL() 返回值是一个StringBuffer类型 request.getRequestURI() 返回值是一个String类型 先看 request.getRequestURL() 返回的是一个具体的地址,访问网页的地址 而 request.getRequestURI() 返回的是一个映射地址&a…...

3154. 到达第 K 级台阶的方案数(24.8.20)
今天发晚了,嘿嘿,玩黑神话玩的 题目 给你有一个 非负 整数 k 。有一个无限长度的台阶,最低 一层编号为 0 。 Alice 有一个整数 jump ,一开始值为 0 。Alice 从台阶 1 开始,可以使用 任意 次操作,目标是到达…...

如何使用docker打包后端项目并部署到阿里云k8s集群上
如何使用docker打包后端项目并部署到阿里云k8s集群上 1. 引言 在现代软件开发中,容器化技术已经成为主流,而Kubernetes (K8s) 是管理容器的首选平台之一。本文将详细介绍如何将一个后端项目使用Docker打包,并将其部署到阿里云的Kubernetes集群上。 2. 前置条件 阿里云账号…...

ES6中解构的使用
一、提取几个属性,构造一个新的对象 在JavaScript中,你可以使用对象解构(Object Destructuring)来提取一个对象中的几个属性,并构造一个新的对象。下面是一个示例: 在这个例子中,name和email属性…...

拖拽式报表设计器优点好 实现流程化办公就靠它!
当前,实现流程化办公是很多企业都想要实现的目标。利用低代码技术平台、拖拽式报表设计器的优势特点,可以为企业降低开发成本、提升办公效率、创造更多市场价值。那么,您知道拖拽式报表设计器的优点是什么吗?通过本文一起了解拖拽…...

Spring项目:文字花园(四)
一.实现登录 传统思路: • 登陆⻚⾯把⽤⼾名密码提交给服务器. • 服务器端验证⽤⼾名密码是否正确, 并返回校验结果给后端 • 如果密码正确, 则在服务器端创建 Session . 通过 Cookie 把 sessionId 返回给浏览器. 问题: 集群环境下⽆法直接使⽤Session. 原因分析: 我们开…...

Web开发:ORM框架之Freesql的入门和技巧使用小结
目录 零、官网链接 一、字段映射表 二、查询 1.freesql独特封装:between关键字 2.分页(每页 20 条数据,查询第 1 页) 3.Withsql(子查询,不建议) 3.简单查询、映射查询 4.参数查询、自定义…...