用 C 语言描述几种排序算法
排序算法是最基本且重要的一类算法,本文基于 VS2017,使用 C 语言来实现一些基本的排序算法。
一、选择排序
选择排序,先找到数组中最小的元素,然后将这个元素与数组的第一个元素位置互换(如果第一个元素就是最小元素,则与自己互换位置)。然后在剩下的元素中寻找最小的元素,与第二个元素位置互换。以此循环,直到整个数组完成排序。
算法描述:
1)第一趟,从无序的数组中选出最小的元素,与第一个元素交换位置;
2)第二趟,除去第一个元素,剩下的元素组成一个无序数组,从中找出最小的元素然后与第二个元素交换位置;
3)重复 n - 1 次即可得到有序的数组。
算法分析:
选择排序的时间复杂度为 O(N2),空间复杂度为 O(1),是非稳定排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int *selectSort(int *numArray,int arrayLen); int main()
{
int numArray[] = {,,,,,,,,,,};
int arrayLen = sizeof(numArray) / sizeof(int);
int *newArray = selectSort(numArray,arrayLen); for (int k = ; k < arrayLen; k++) {
printf("%d ",newArray[k]);
} return ;
} int *selectSort(int *numArray,int arrayLen)
{ int len = arrayLen;
int temp = ;
for (int i = ; i < len - ; i++) {
for (int j = i + ; j < len; j++) {
if (numArray[j] <= numArray[i]) {
temp = numArray[i];
numArray[i] = numArray[j];
numArray[j] = temp;
}
}
} return numArray;
}
二、直接插入排序
直接插入排序将一个数组分为一个有序数组和一个无序数组。一开始,第一个元素单独作为一个有序数组,其他元素为无序数组;然后,每次从无序数组中取出第一个元素,与有序数组中的元素进行比较并插入到有序数组中去,与之组成一个新的有序数组,以此重复直到排序完成。
算法描述:
1)第一个元素自己作为一个有序数组;
2)从第二个元素开始,将它与其左侧第一个元素比较,若左侧第一个元素比它大,则继续与左侧第二个元素比较,直到遇到不大于(小于或等于)该元素的元素,将该元素插入到所找到的元素的右边,此时该元素及其左边的元素是已排序的;
3)选取第 3、4、...、n 个元素,重复步骤 2;
4)得到有序的数组。
算法分析:
直接插入排序的时间复杂度为 O(N2),空间复杂度为 O(1),是稳定排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int *insertSort(int *numArray,int arrayLen); int main()
{
int len;
int numArray[] = {,,,,,,,,,,,,};
len = sizeof(numArray) / sizeof(int);
int *newArray = insertSort(numArray,len);
for (int k = ; k < len; k++) {
printf("%d ",newArray[k]);
} return ;
} int *insertSort(int *numArray,int arrayLen)
{
int temp;
for (int i = ; i < arrayLen; i++) {
for (int j = i; j > ; j--) {
if (numArray[j] < numArray[j - ]) {
temp = numArray[j];
numArray[j] = numArray[j - ];
numArray[j - ] = temp;
}
}
} return numArray; }
三、冒泡排序
冒泡排序一次比较两个元素,如果前一个元素比后一个元素大,则交换两个元素的位置。从第一个元素开始,对每对相邻的元素都执行这个操作, 直到最后一个元素,则一次比较完成后,最大的元素会被放到数组最右边;去掉最右边的元素再对剩余的数组进行冒泡排序,直到所有元素都完成排序。
算法描述:
1)从第一个元素开始,比较两个相邻的元素(第1、2个元素),若后者比前者小,则交换两者的位置;
2)依次交换所有的元素,一趟交换完成后,最右边的元素为最大的元素;
3)然后再从第一个元素开始交换,除了最后一个元素;
4)重复,知道所有元素都被排序。
算法分析:
冒泡排序的时间复杂度为 O(N2),空间复杂度为 O(1),是稳定排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int *bubbleSort(int *numArray,int arrayLen); int main()
{
int len;
int numArray[] = {,,,,,,,,,,,};
len = sizeof(numArray) / sizeof(int);
int *newArray = bubbleSort(numArray,len);
for (int k = ; k < len; k++) {
printf("%d ", newArray[k]);
} return ;
} int *bubbleSort(int *numArray, int arrayLen)
{
int temp; if (arrayLen < ) {
return numArray;
} for (int i = ; i < arrayLen; i++) {
for (int j = ; j < arrayLen - i - ; j++) {
if (numArray[j + ] < numArray[j]) {
temp = numArray[j + ];
numArray[j + ] = numArray[j];
numArray[j] = temp;
}
}
} return numArray; }
四、希尔排序
希尔排序是第一批突破 O(n2) 时间复杂度的算法之一,它是插入排序的一种变种,与插入排序不同的是,它通过比较相距一定间隔的元素来工作;各趟比较所用的距离随着算法的进行而减小,直到最后一趟比较(只比较相邻元素)为止,这是距离为 1 。因此希尔排序又叫缩小增量排序。
算法描述:
1)选择一个增量 k(一般为数组长度的一半),以这个增量为步长将数组分为 k 个小数组,对每个小数组进行直接插入排序;
2)缩小增量为 k / 2,以这个增量为步长将数组分为 k / 2 个小数组,对每个小数组进行直接插入排序,由于这个小数组有一部分是已经排序了的,因此排序起来会比较容易;
3)继续缩小增量,并排序,直到增量为 1;
4)最终得到一个已排序的数组。
算法分析:
希尔排序的时间复杂度为 O(N log N),空间复杂度为 O(1),为非稳定排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int *shellSort(int *numArray, int arrayLen); int main()
{
int len;
int numArray[] = {,,,,,,,,,,,,};
len = sizeof(numArray) / sizeof(int);
int *newArray = shellSort(numArray,len);
for (int k = ; k < len; k++) {
printf("%d ", newArray[k]);
} return 0;
} int *shellSort(int *numArray,int arrayLen)
{
int step;
int temp;
int j;
if (arrayLen < )
return numArray; for (step = arrayLen / ; step > ; step /= ) { for (int i = step; i < arrayLen; i++) {
temp = numArray[i];
for (j = i - step; j >= && temp < numArray[j]; j -= step) {
numArray[j + step] = numArray[j];
}
numArray[j + step] = temp;
}
} return numArray;
}
五、归并排序
归并排序的基本思想是先把一个大的无序数组拆分成两个小的无序数组,然后对这两个数组分别进行排序,之后再将两个有序的小数组合并成一个有序的大数组。
通过递归的方式,将数组一直分割,直到数组大小为 1 ,此时数组只有一个元素,为有序状态;然后将两个大小为 1 的数组合并成一个大小为 2 的数组;再把大小为 2 的两个数组合并成大小为 4 的数组...直到将所有的数组合并成一个大数组。
算法描述:
1)将一个无序的数组分成两个无序的小数组;
2)将两个无序的小数组分别分成两个更小的无序数组;
3)重复第二步,知道小数组的长度为1,此时每个小数组都是有序的;
4)将长度为 1 的两个小数组合并成一个长度为 2 的有序数组;
5)将长度为 2 的两个小数组合并成长度为 4 的有序数组;
6)最终合成一个有序的大数组。
很显然,用递归的思想实现归并排序会比较方便。
算法分析:
归并排序的时间复杂度为 O(N log N),空间复杂度为 O(N),为稳定排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> void mergeSort(int *sourceArray,int arrayLen);
void mSort(int *sourceArray, int *tmpArray, int left, int right);
void merge(int *sourceArray, int *tmpArray, int lpos, int rpos, int rightEnd); int main()
{
int sourceArray[] = {,,,,,,,,,,,,,,};
int len = sizeof(sourceArray) / sizeof(int);
mergeSort(sourceArray,len);
for (int k = ; k < len; k++) {
printf("%d ", sourceArray[k]);
} return 0;
} // 归并排序
void mergeSort(int *sourceArray, int arrayLen)
{
int *tmpArray = (int *)malloc(sizeof(int) * arrayLen); // 新建一个临时数组
if (tmpArray != NULL) {
mSort(sourceArray, tmpArray, , arrayLen - );
free(tmpArray);
}
else {
perror("malloc failed!");
exit(EXIT_FAILURE);
}
} // 排序
void mSort(int *sourceArray, int *tmpArray, int left, int right)
{
int mid = (left + right) / ;
if (left < right) {
mSort(sourceArray, tmpArray, left, mid);
mSort(sourceArray, tmpArray, mid + , right);
merge(sourceArray, tmpArray, left, mid + , right);
} } // 归并
void merge(int *sourceArray,int *tmpArray, int lpos, int rpos, int rightEnd)
{
int i, leftEnd, elementNum, tmpPos;
tmpPos = lpos; // 临时指针
leftEnd = rpos - ;
elementNum = rightEnd - lpos + ; // 归并比较
while (lpos <= leftEnd && rpos <= rightEnd) {
if (sourceArray[lpos] <= sourceArray[rpos]) {
tmpArray[tmpPos++] = sourceArray[lpos++];
}
else {
tmpArray[tmpPos++] = sourceArray[rpos++];
}
} // 将左边剩余元素填入数组
while (lpos <= leftEnd) {
tmpArray[tmpPos++] = sourceArray[lpos++];
}
// 将右边剩余元素填入数组
while (rpos <= rightEnd) {
tmpArray[tmpPos++] = sourceArray[rpos++];
} // 将临时数组中的元素拷贝到原数组中去
for (i = ; i < elementNum; i++, rightEnd--) {
sourceArray[rightEnd] = tmpArray[rightEnd];
}
}
六、快速排序
快速排序是在实践中已知最快的一种排序算法。其基本思想是先从数组中选择一个元素作为基准元素,然后分别从数组的头部和尾部开始往数组中间遍历,并与基准元素比较,一次遍历的结果是将这个基准元素移到数组的中间(基准数的左边所有元素都小于或等于它,右边所有元素都大于或等于它);然后再从这个基准元素的左边和右边各选一个元素作为两边小数组各自的基准元素,重复之前的做法,将基准元素移到数组中间,直到所有元素都被排好序。
算法描述:
1)选择一个基准元素(比如说数组最左边的元素);
2)设置两个哨兵(指针) left 和 right,分别指向数组最左边的元素和数组最右边的元素;
3)先移动 right 哨兵,从数组右边往左边移动,当 right 哨兵所指位置的元素小于基准数时,停止移动 right 哨兵;
4)再移动 left 哨兵,从数组左边往右边移动,当 left 哨兵所指位置的元素大于基准数时,停止移动 left 哨兵;
5)交换 left 和 right 所指位置的元素;
6)重复步骤 3~5,直到 left >= right,停止移动,并将基准元素与 left 所指向位置的元素互换;
7)此时基准元素左边数组的元素全部小于它,右边数组的元素全部大于它;
8)对基准元素左边和右边的数组分别重复步骤 2~6;
9)得到被排序的数组。
算法分析:
快速排序的时间复杂度为 O(N log N),空间复杂度为 O(log N),为非稳定排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> void quickSort(int *sourceArray, int leftPos, int rightPos); int main()
{
int sourceArray[] = { ,,,,,,,,,,,,, };
int len = sizeof(sourceArray) / sizeof(int);
quickSort(sourceArray, , len - );
for (int k = ; k < len; k++) {
printf("%d ", sourceArray[k]);
} return 0;
} void quickSort(int *sourceArray, int leftPos, int rightPos)
{
int baseNum = sourceArray[leftPos]; // 基准数
int tmpPosLeft = leftPos; // tmpPos 用于存放基准数在数组中的位置
int tmpPosRight = rightPos;
int temp; if (leftPos >= rightPos) {
return;
} while (leftPos < rightPos) {
// 先从右边找起,找到比基准数小的数为止
while (leftPos < rightPos && sourceArray[rightPos] >= baseNum) {
rightPos--;
} // 再从左边找,找到比基准数大的为止
while (leftPos < rightPos && sourceArray[leftPos] <= baseNum) {
leftPos++;
} // 交换两个哨兵所在处的值
if (leftPos < rightPos) {
temp = sourceArray[leftPos];
sourceArray[leftPos] = sourceArray[rightPos];
sourceArray[rightPos] = temp;
} } // 最后将基准数放到数组中央,此时基准数左边的数全部小于它,基准数右边的数全部大于它
sourceArray[tmpPosLeft] = sourceArray[leftPos];
sourceArray[leftPos] = baseNum; quickSort(sourceArray, tmpPosLeft, leftPos - );
quickSort(sourceArray, leftPos + , tmpPosRight);
}
参考资料:
《数据结构与算法分析 -- C语言描述》
用 C 语言描述几种排序算法的更多相关文章
- [answerer的算法课堂]简单描述4种排序算法(C语言实现)
[answerer的算法课堂]简单描述4种排序算法(C语言实现) 这是我第一次写文章,想要记录自己的学习生活,写得不好请包涵or指导,本来想一口气写好多种,后来发现,写太多的话反而可读性不强,而且,我 ...
- 史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)
目录 1.准备工作 2.创建链表 3.打印链表 4.在元素后面插入元素 5.在元素前面增加元素 6.删除链表元素,要注意删除链表尾还是链表头 7.根据传入的数值查询链表 8.修改链表元素 9.求链表长 ...
- 几种排序算法的学习,利用Python和C实现
之前学过的都忘了,也没好好做过总结,现在总结一下. 时间复杂度和空间复杂度的概念: 1.空间复杂度:是程序运行所以需要的额外消耗存储空间,一般的递归算法就要有o(n)的空间复杂度了,简单说就是递归集算 ...
- 排序—时间复杂度为O(n2)的三种排序算法
1 如何评价.分析一个排序算法? 很多语言.数据库都已经封装了关于排序算法的实现代码.所以我们学习排序算法目的更多的不是为了去实现这些代码,而是灵活的应用这些算法和解决更为复杂的问题,所以更重要的是学 ...
- C语言8大经典排序算法(1)
算法一直是编程的基础,而排序算法是学习算法的开始,排序也是数据处理的重要内容.所谓排序是指将一个无序列整理成按非递减顺序排列的有序序列.排列的方法有很多,根据待排序序列的规模以及对数据的处理的要求,可 ...
- C语言实现九大排序算法
C语言实现九大排序算法 直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 基数排序 C语言实现九大排序算法 直接插入排序 将数组分为两个部分,一个是有序部分,一 ...
- JavaScript实现的7种排序算法
所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序.这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后的数据便于筛选和计算,大大提高了计算效率.对于排序,我们首先要求 ...
- 秒杀9种排序算法(JavaScript版)
一:你必须知道的 1> JS原型 2> 排序中的有序区和无序区 3> 二叉树的基本知识 如果你不知道上面三个东西,还是去复习一下吧,否则,看下面的东西有点吃力. 二:封装丑陋的原型方 ...
- PHP的几种排序算法的比较
这里列出了几种PHP的排序算法的时间比较的结果,,希望对大家有所帮助 /* * php 四种排序算法的时间与内置的sort排序比较 * 3000个元素,四种算法的排序所用的时间比较 * 冒泡排序 85 ...
随机推荐
- .net core 入坑经验 - 2、MVC Core之获取网站运行路径
这次是建立了asp.net mvc core项目,在controller中想获取网站在硬盘中的路径,找了一圈Server.MapPath() 已不存在,HttpContent也一样,经过查阅资料发现是 ...
- iptables设置规则
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 8080 -j ACCEPT 添加到最后一条iptables -I INPUT -p tcp --dpor ...
- [2011山东ACM省赛] Mathman Bank(模拟题)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/sr19930829/article/details/24187925 Mathman Bank ni ...
- Spring之 Aspect Oriented Programming with Spring
1. Concepts Aspect-Oriented Programming (AOP) complements OOP by providing another way of thinking a ...
- 【转】 python中 * 的用法
转自:https://www.cnblogs.com/jony7/p/8035376.html 1.表示乘号 2.表示倍数,例如: def T(msg,time=1): print((msg+' ...
- Python2.7-weakref
weakref 模块,允许创建对象的弱引用,被弱引用的对象其引用计数不变,对象的引用计数为0时就会被垃圾清理机制释放内存空间,此时对其的弱引用也会失效.在对象会被交叉引用,需要释放内存空间时常用. 模 ...
- jq中each的中断
最近在做项目中,遇到jq的each方法中的回调函数里面的break不生效,即通过 jquery 的循环方法进行数组遍历,但是当不符合条件时,怎么跳出当前循环,我们经常会习惯JS中的break和cont ...
- Android 使用正则表达式验证身份证号是否符合规则
我国当前的身份证号分为三种: 一.15位身份证号 二.18位身份证号(前17位位数字,最后一位为字母x) 三.18为身份证号(18位都是数字) 具体验证请参考下面代码: /** * 验证身份证号是否符 ...
- ceph状态信息靠谱查询
1)检查集群的状态汇总信息: [root@haha1 clouder]# ceph -s cluster 8e136e25-77ab-4e0b-b24b-232a7b466cfe health HEA ...
- Web.config中 mode="RemoteOnly" 跟mode="On" 区别
转载网址:mode="RemoteOnly" 跟mode="On" 区别 <!-- 自定义错误信息 设置 customErrors mode=" ...