当前位置: 首页 > news >正文

常见的排序算法原理及c代码实现

1.冒泡排序

原理:比较两个相邻的元素,将值大的元素交换到右边

依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。

    (1)第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。

    (2)比较第2和第3个数,将小数 放在前面,大数放在后面。

    ......

    (3)如此继续,知道比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成

    (4)在上面一趟比较完成后,最后一个数一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。

    (5)在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。

    (6)依次类推,每一趟比较次数减少依次


void bubbleSort(int *arr,int n)
{
	int m,i,j;
	for(i=0;i<n-1;i++)
		for(j=0;j<n-1-i;j++)
			if(arr[j]>arr[j+1])
			{
				m=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=m;
			}
}

2.插入排序

原理:每一步将一个待排序的数据插入到前面已经排好序的有序序列中,直到插完所有元素为止。

算法实现:直接插入排序是将无序序列中的数据插入到有序的序列中,在遍历无序序列时,首先拿无序序列中的首元素去与有序序列中的每一个元素比较并插入到合适的位置,一直到无序序列中的所有元素插完为止。对于一个无序序列arr{4,6,8,5,9}来说,我们首先先确定首元素4是有序的,然后在无序序列中向右遍历,6大于4则它插入到4的后面,再继续遍历到8,8大于6则插入到6的后面,这样继续直到得到有序序列{4,5,6,8,9}。


void StraightSort(int *arr,int len)
{
	int tmp;
	int i;
	int j;
	for (i = 1;i < len;i++)
	{
		tmp = arr[i];
		for (j = i - 1;j >= 0 && arr[j] > tmp;j--)
		{
			arr[j + 1] = arr[j];
		}
		arr[j + 1] = tmp;
	}
}

3.希尔排序

原理:希尔排序是插入排序的改进版,首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高。

图解算法---希尔排序

举例:按下标相隔距离为4分组,也就是说把下标相差4的分到一组,a[0]与a[4]是一组、a[1]与a[5]是一组...,这里的差值(距离)被称为增量

每个分组进行插入排序后,各个分组就变成了有序的了(整体不一定有序)

图解算法---希尔排序

然后缩小增量为上个增量的一半:2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比高

图解算法---希尔排序

同理对每个分组进行排序(插入排序),使其每个分组各自有序

图解算法---希尔排序

最后设置增量为上一个增量的一半:1,则整个数组被分为一组,此时,整个数组已经接近有序了,插入排序效率高

图解算法---希尔排序

同理,对这仅有的一组数据进行排序,排序完成


void shell_sort(int array[], int length){
	int i;
	int j;
	int k;
	int gap;	//gap是分组的步长
	int temp;	//希尔排序是在直接插入排序的基础上实现的,所以仍然需要哨兵
	for(gap=length/2; gap>0; gap=gap/2){
		for(i=0; i<gap; i++){
			for(j=i+gap; j<length; j=j+gap){	//单独一次的插入排序
				if(array[j] < array[j - gap]){
					temp = array[j];	//哨兵
					k = j - gap;
					while(k>=0 && array[k]>temp){
						array[k + gap] = array[k];
						k = k - gap;
					}
					array[k + gap] = temp;
				}
			}
		}
	}

4.归并排序

原理:分治法。

  • 分解(Divide):将n个元素分成个含n/2个元素的子序列。
  • 解决(Conquer):用合并排序法对两个子序列递归的排序。
  • 合并(Combine):合并两个已排序的子序列已得到排序结果。

  

具体的我们以一组无序数列{14,12,15,13,11,16}为例分解说明,如下图所示:

上图中首先把一个未排序的序列从中间分割成2部分,再把2部分分成4部分,依次分割下去,直到分割成一个一个的数据,再把这些数据两两归并到一起,使之有序,不停的归并,最后成为一个排好序的序列。

void merge_sort_recursive(int arr[], int reg[], int start, int end) {
    if (start >= end)
        return;
    int len = end - start, mid = (len >> 1) + start;
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    merge_sort_recursive(arr, reg, start1, end1);
    merge_sort_recursive(arr, reg, start2, end2);
    int k = start;
    while (start1 <= end1 && start2 <= end2)
        reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
    while (start1 <= end1)
        reg[k++] = arr[start1++];
    while (start2 <= end2)
        reg[k++] = arr[start2++];
    for (k = start; k <= end; k++)
        arr[k] = reg[k];
}
void merge_sort(int arr[], const int len) {
    int reg[len];
    merge_sort_recursive(arr, reg, 0, len - 1);
}

5.快速排序

原理:分治法,选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

下面以数列a={30,40,60,10,20,50}为例,演示它的快速排序过程(如下图)。

上图只是给出了第1趟快速排序的流程。在第1趟中,设置x=a[i],即x=30。
(01) 从"右 --> 左"查找小于x的数:找到满足条件的数a[j]=20,此时j=4;然后将a[j]赋值a[i],此时i=0;接着从左往右遍历。
(02) 从"左 --> 右"查找大于x的数:找到满足条件的数a[i]=40,此时i=1;然后将a[i]赋值a[j],此时j=4;接着从右往左遍历。
(03) 从"右 --> 左"查找小于x的数:找到满足条件的数a[j]=10,此时j=3;然后将a[j]赋值a[i],此时i=1;接着从左往右遍历。
(04) 从"左 --> 右"查找大于x的数:找到满足条件的数a[i]=60,此时i=2;然后将a[i]赋值a[j],此时j=3;接着从右往左遍历。
(05) 从"右 --> 左"查找小于x的数:没有找到满足条件的数。当i>=j时,停止查找;然后将x赋值给a[i]。此趟遍历结束!

按照同样的方法,对子数列进行递归遍历。最后得到有序数组!

/*
 * 快速排序
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     l -- 数组的左边界(例如,从起始位置开始排序,则l=0)
 *     r -- 数组的右边界(例如,排序截至到数组末尾,则r=a.length-1)
 */
void quick_sort(int a[], int l, int r)
{
    if (l < r)
    {
        int i,j,x;

        i = l;
        j = r;
        x = a[i];
        while (i < j)
        {
            while(i < j && a[j] > x)
                j--; // 从右向左找第一个小于x的数
            if(i < j)
                a[i++] = a[j];
            while(i < j && a[i] < x)
                i++; // 从左向右找第一个大于x的数
            if(i < j)
                a[j--] = a[i];
        }
        a[i] = x;
        quick_sort(a, l, i-1); /* 递归调用 */
        quick_sort(a, i+1, r); /* 递归调用 */
    }
}

 

相关文章:

  • stl之remove、erase算法与元素的删除
  • docker学习之旅二:docker基本命令
  • docker学习之旅一:ubuntu下安装docker+配置阿里源
  • redis-跳跃表zskiplist
  • redis集群介绍与搭建
  • Linux系统命令与网络、磁盘参数和日志监控命令
  • mysql 8.0版本修改密码
  • 解决Navicat 连接mysql报错:Can‘t connect to MYSQL server on “ip address“(10061)
  • jsoncons使用之: 构造json
  • 使用reserve来避免不必要的内存重新分配
  • redis 编译报错 zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: 没有那个文件或目录
  • linux下hiredis安装、C接口编程
  • redis源码学习之数据结构---双向链表
  • redis源码分析--事件驱动模型
  • ubuntu下zmq编译安装及请求-应答模式测试
  • [NodeJS] 关于Buffer
  • create-react-app项目添加less配置
  • create-react-app做的留言板
  • js写一个简单的选项卡
  • JS字符串转数字方法总结
  • Twitter赢在开放,三年创造奇迹
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 基于Android乐音识别(2)
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 容器服务kubernetes弹性伸缩高级用法
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 设计模式走一遍---观察者模式
  • 数据可视化之 Sankey 桑基图的实现
  • 微服务入门【系列视频课程】
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • (12)目标检测_SSD基于pytorch搭建代码
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (二)Linux——Linux常用指令
  • (分布式缓存)Redis哨兵
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)fock函数详解
  • (转)Windows2003安全设置/维护
  • (转载)Google Chrome调试JS
  • .form文件_一篇文章学会文件上传
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .Net Core和.Net Standard直观理解
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET 设计模式初探
  • .NET 指南:抽象化实现的基类
  • .ui文件相关
  • /run/containerd/containerd.sock connect: connection refused
  • [ JavaScript ] JSON方法
  • [Angular 基础] - 表单:响应式表单
  • [AutoSAR 存储] 汽车智能座舱的存储需求