【C】初阶数据结构15 -- 计数排序与稳定性分析

news2025/5/10 12:57:27

本文主要讲解七大排序算法之外的另一种排序算法 -- 计数排序 


目录

1  计数排序

1) 算法思想

2) 代码 

3) 时间复杂度与空间复杂度分析 

(1) 时间复杂度

(2) 空间复杂度

4) 计数排序的优点与缺点

(1) 优点

(2) 缺点

2  排序的稳定性

1) 稳定性的定义

2) 七大排序算法的稳定性分析

3) 七大排序算法时空复杂度与稳定性总结

3  总结


1  计数排序

        计数排序是排序算法中最简单的一种算法,不需要借助递归等算法,不过需要一点哈希表的思想(哈希表是一种数据结构,后面 C++ 部分会有相应的讲解,本质就是通过一个函数将元素值转化为其对应的映射,从而快速找到其值的一个数据结构)。


1) 算法思想

        计数排序的算法思想如同其名字一样,就是计算出其每个元素出现的次数,然后进行排序,其算法过程如下:

a. 先找出其数组中的最大值 maxnum 与 最小值 minnum,然后动态开辟一个 maxnum - minnum + 1 空间大小的数组 count

b. 然后用一个变量 i 遍历原数组,假设原数组为 arr,然后每次让 count[arr[i] - minnum]++

c. 再用一个变量 i 遍历 count 数组,再创建一个 index 下标,初始为 0,如果 count[i] != 0,那就让arr[index] = i + minnum,然后 index++,count[i]--,直到 count[i] 变为 0 为止。

其算法思想本质就是通过 arr 数组中每个元素减去最小值计算出 arr 数组中每个元素在 count 数组中的下标映射,然后越小的元素就在 count 数组中处于越前面的位置,count[i] 就记录了每个元素出现的次数。其执行过程如下:
(1) count 数组变化的过程:

(2) arr 数组变化过程:


2) 代码 

void CountSort(int* arr, int n)
{
    //先找最大值和最小值
    int maxnum = 0, minnum = INT_MAX;
    for (int i = 0; i < n; i++)
    {
        if (maxnum < arr[i]) maxnum = arr[i];
        if (minnum > arr[i]) minnum = arr[i];
    }

    //开辟数组空间
    int* count = (int*)calloc(maxnum - minnum + 1, sizeof(int));
    if (count == NULL)
    {
        perror("malloc fail!\n");
        exit(1);
    }

    //遍历原数组,count记录出现次数
    for (int i = 0; i < n; i++)
    {
        count[arr[i] - minnum]++;
    }

    //再遍历count数组,将元素放到 arr 数组中
    int index = 0;
    for (int i = 0; i < maxnum - minnum + 1; i++)
    {
        while (count[i])
        {
            arr[index++] = i + minnum;
            count[i]--;
        }
    }
}

这里有个需要注意的一点,就是动态开辟 count 数组空间的时候,要使用 calloc 函数,因为 count 数组里面的值必须全都初始化为 0,如果用 malloc 函数的话里面是随机值,是会发生错误的。

测试用例:

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int arr[] = { 6, 3, 10, 7, 2, 5, 12, 4, 1, 8, 11 };
    int n = sizeof(arr) / sizeof(arr[0]);
    CountSort(arr, n);
    
    for (int i = 0; i < n; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

3) 时间复杂度与空间复杂度分析 

(1) 时间复杂度

        从代码来分析,尽管有里面有两层循环,但是里面的 count[i] 循环仅有常数次,假设这里的 maxnum - minnum + 1 = k,计数排序的时间复杂度为 T(n) = O(n + k)

(2) 空间复杂度

        假设 maxnum - minnum + 1 为 k,由于动态开辟了 k 个空间,所以空间复杂度为 S(n) = O(k)


4) 计数排序的优点与缺点

(1) 优点

        计数排序的优点特别明显,就是其时间复杂度比较低,执行效率很高;前面的七大排序算法最快的时间复杂度就是 O(nlogn),所以计数排序的执行效率是比前面任何一个排序的执行效率都快。

(2) 缺点

        但是计数排序也有明显的缺点,由于在排序过程中需要动态开辟 maxnum - minnum + 1 的空间,所以如果 maxnum 与 minnum 相差很大时,需要动态开辟的空间就很大,会浪费很多空间;所以如果 arr 数组中的数据相差很大,比较离散时,计数排序的消耗就会很大。

        综合来说,计数排序的应用场景比较有限,如果 arr 数组中的数据很集中时,应用计数排序就很合适,效率很高;但如果数据比较离散的话,计数排序就不太适合了,消耗会比较大


2  排序的稳定性

1) 稳定性的定义

        一个排序算法是否稳定是指:如果对于一组数据,其中有相等的值,如果进行排序之后,之前相等的值的相对位置保持不变,那就称该排序算法是稳定的,否则就是不稳定的。比如:有一组数据 1 8 5 8 7,假设第一个 8 为 num1,第二个数据为 num2,排序之前 num1 排在 num2 之前,排完序之后,该组数据变为 1 5 7 num1 num2,num1 还是排在 num2 之前,就称该排序算法是稳定的;假如排完序之后,num1 排在了 num2 之后,那么该排序算法就是不稳定的。


2) 七大排序算法的稳定性分析

冒泡排序:假设一组数据为 8 8 2 1,第一个 8 为 num1,第二个 8 为 num2(num1 num2  2 1),那么根据冒泡排序的算法思想,第一轮排序的结果应该为 num1 2 1 num2,第二轮为 2 1 num1 num2,第三轮排序结果为 1 2 num1 num2。经过排序之后,发现 num1 还是排在 num2 之前,所以冒泡排序算法是稳定的。

 直接插入排序:还是假设数据为 num1 num2  2 1(同冒泡排序),经过第一轮排序,结果仍为 num1 num2 2 1,第二轮排序结果为 2 num1 num2 1,第三轮排序结果为 1 2 num1 num2。排完序之后,num1 依然排在 num2 之前,所以直接插入排序也是稳定的。

归并排序:依然假设数据为 num1 num2  2 1,num1 与 num2 合并之后依然是 num1 num2,2 与 1 合并之后结果为 1 2,然后两个子数组再进行合并,结果为 1 2 num1 num2。排完序之后,num1 依然排在 num2 之前,所以归并排序也是稳定的。

直接选择排序:假设一组数据为 num1 8 num2  2 9 (5 8 5 2 9),第一轮排序之后结果为 2 8 num2 num1 9,发现 num1 跑到 num2 之后了,所以直接选择排序是不稳定的。究其原因,就是因为直接选择排序会将最大的与每轮排序中的最后一个位置交换,将最小的和每轮排序中的第一个位置交换,就有能会使相同元素的相对位置发生变化。​

希尔排序:假设一组数据为 num1 8 2 num2  9 (5 8 2 5 9),第一轮排序 num1 2 9 一组,8 num2 一组,排完序之后结果就变为了 2  num2  num1  8  9,此时 num2 与 num1 相对位置发生了变化,所以希尔排序也是一种不稳定的排序算法。

堆排序:假设一组数据为 num1  num2  num3  num4 (2  2  2  2),第一次排序会将 num1 与 num4交换(堆顶元素与最后一个元素交换),此时结果变为了 num4  num2  num3  num1,相对位置发生了变化,所以堆排序也是一种不稳定的排序算法。

快速排序:假设一组数据为 5  num1  num2  4  num3  8  9  10  11(5  3  3  4  3  8  9  10  11),第一次排序,key值为 5,cur 在后面找比 5 小的元素然后和 ++prev 位置交换(双指针算法找 key 值),所以第一次排序之后结果为 num3  num1  num2  4  5  8  9  10  11,此时相对位置发生了变化,所以快速排序算法也是一种不稳定的排序算法。


3) 七大排序算法时空复杂度与稳定性总结

 以下表格是对七大排序的时空复杂度以及稳定性的总结:
 

七大排序算法总结
排序算法时间复杂度空间复杂度稳定性
直接插入排序O(n^2)O(1)稳定
直接选择排序O(n^2)O(1)不稳定
希尔排序O(n^1.3)O(1)不稳定
冒泡排序O(n^2)O(1)稳定
堆排序O(nlogn)O(1)不稳定
快速排序O(nlogn)O(logn) ~ O(n)不稳定
归并排序O(nlogn)O(n)稳定

3  总结

        到这里,初阶数据结构的知识就已经结束了,我们来回顾一下:在初阶数据结构里面,我们学习了顺序表、链表、栈、队列以及二叉树这五种数据结构,学习了 8 种排序算法;不仅通过具体代码实现了每个数据结构,而且还通过具体题目来加深了对于数据结构的理解,相信在学习完初阶数据结构之后,代码能力肯定会提升很多。

        在之后,我们会开启新的模块的学习,包括 C++语言、Linux操作系统以及高阶数据结构和各种经典算法,比如递归、回溯、动态规划、双指针算法等,在后面的文章中会交叉更新不同内容,后面的难度也肯定会呈不断递增的趋势,但是只要继续学下去,肯定就会收获满满,所以不要放弃哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2372316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高性能Python Web 框架--FastAPI 学习「基础 → 进阶 → 生产级」

以下是针对 FastAPI 的保姆级教程&#xff0c;包含核心概念、完整案例和关键注意事项&#xff0c;采用「基础 → 进阶 → 生产级」的三阶段教学法&#xff1a; 一、FastAPI介绍 FastAPI 是一个现代化的、高性能的 Python Web 框架&#xff0c;专门用于构建 APIs&#xff08;应…

Qt QML自定义LIstView

QML ListView组合拳做列表&#xff0c;代码不可直接复制使用&#xff0c;需要小改 先上图看效果 样式1 样式2 样式3 原理&#xff1a;操作&#xff1a;技术点:代码片段&#xff1a; 先上图看效果 样式1 三个表格组合成要给&#xff0c;上下滚动时&#xff0c;三个同时滚动&am…

C++进阶--红黑树的实现

文章目录 红黑树的实现红黑树的概念红黑树的规则红黑树的效率 红黑树的实现红黑树的结构红黑树的插入变色单旋&#xff08;变色&#xff09;双旋&#xff08;变色&#xff09; 红黑树的查找红黑树的验证 总结&#xff1a;结语 很高兴和大家见面&#xff0c;给生活加点impetus&a…

WPF之值转换器

文章目录 目录什么是值转换器IValueConverter接口Convert方法ConvertBack方法 创建和使用值转换器定义转换器类在XAML中使用转换器转换器参数&#xff08;ConverterParameter&#xff09; 常用转换器实现布尔值转可见性&#xff08;BoolToVisibilityConverter&#xff09;数值转…

qml中的TextArea使用QSyntaxHighlighter显示高亮语法

效果图&#xff0c;左侧显示行号&#xff0c;右侧用TextArea显示文本内容&#xff0c;并且语法高亮。 2025年5月8号更新 1、多行文本注释 多行文本注释跟普通的高亮规则代码不太一样&#xff0c;代码需要修改&#xff0c;这里以JavaScript举例。 先制定多行文本注释规则&…

Transformer编码器+SHAP分析,模型可解释创新表达!

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基本介绍 基于SHAP分析的特征选择和贡献度计算&#xff0c;Matlab2023b代码实现&#xff1b;基于MATLAB的SHAP可解释Transformer编码器回归模型&#xff0c;敏感性分析方法。 详细介绍 引言 在正向渗透&#xff08…

[特殊字符]适合母亲节的SVG模版[特殊字符]

宝藏模版 往期推荐&#xff08;点击阅读&#xff09;&#xff1a; 趣味效果&#xff5c;高大上&#xff5c;可爱风&#xff5c;年终总结I&#xff5c;年终总结II&#xff5c;循环特效&#xff5c;情人节I&#xff5c;情人节II&#xff5c;情人节IIII&#xff5c;妇女节I&…

浅蓝色调风格人像自拍Lr调色预设,手机滤镜PS+Lightroom预设下载!

调色教程 浅蓝色调风格人像自拍 Lr 调色是利用 Adobe Lightroom 软件针对人像自拍照进行后期处理的一种调色方式。它通过对照片的色彩、对比度、亮度等参数进行精细调整&#xff0c;将画面的主色调打造为清新、柔和的浅蓝色系&#xff0c;赋予人像自拍独特的清新、文艺风格&…

isp流程介绍(yuv格式阶段)

一、前言介绍 前面两章里面&#xff0c;已经分别讲解了在Raw和Rgb域里面&#xff0c;ISP的相关算法流程&#xff0c;从前面文章里面可以看到&#xff0c;在Raw和Rgb域里面&#xff0c;很多ISP算法操作&#xff0c;更像是属于sensor矫正或者说sensor标定操作。本质上来说&#x…

数巅智能携手北京昇腾创新中心深耕行业大模型应用

当前&#xff0c;AI技术正在加速向各行业深度渗透,成为驱动产业转型和社会经济发展的重要引擎。构建开放协作的AI应用生态体系、推动技术和应用深度融合&#xff0c;已成为行业发展的重要趋势。 近日&#xff0c;数巅智能与北京昇腾人工智能计算中心&#xff08;北京昇腾创新中…

【LangChain高级系列】LangGraph第一课

前言 我们今天直接通过一个langgraph的基础案例&#xff0c;来深入探索langgraph的核心概念和工作原理。 基本认识 LangGraph是一个用于构建具有LLMs的有状态、多角色应用程序的库&#xff0c;用于创建代理和多代理工作流。与其他LLM框架相比&#xff0c;它提供了以下核心优…

常见降维算法分析

一、常见的降维算法 LDA线性判别PCA主成分分析t-sne降维 二、降维算法原理 2.1 LDA 线性判别 原理 &#xff1a;LDA&#xff08;Linear Discriminant Analysis&#xff09;线性判别分析是一种有监督的降维方法。它的目标是找到一个投影方向&#xff0c;使得不同类别的数据在…

计算机二级(C语言)已过

非线性结构&#xff1a;树、图 链表和队列的结构特性不一样&#xff0c;链表可以在任何位置插入、删除&#xff0c;而队列只能在队尾入队、队头出队 对长度为n的线性表排序、在最坏情况下时间复杂度&#xff0c;二分查找为O(log2n)&#xff0c;顺序查找为O(n)&#xff0c;哈希查…

2025年3月,​韩先超对国网宁夏进行Python线下培训

大家好&#xff0c;我是韩先超&#xff01;在2025年3月3号和4号&#xff0c;为 宁夏国网 的运维团队进行了一场两天的 Python培训 &#xff0c;培训目标不仅是让大家学会Python编程&#xff0c;更是希望大家能够通过这门技术解决实际工作中的问题&#xff0c;提升工作效率。 对…

[计算机网络]物理层

文章目录 物理层的概述与功能传输介质双绞线:分类:应用领域: 同轴电缆&#xff1a;分类: 光纤&#xff1a;分类: 无线传输介质&#xff1a;无线电波微波&#xff1a;红外线&#xff1a;激光&#xff1a; 物理层设备中继器(Repeater)&#xff1a;放大器&#xff1a;集线器(Hub)&…

幂等操作及处理措施

利用token模式去避免幂等操作 按以上图所示&#xff0c;除了token,应该也可以把传入的参数用MD5加密&#xff0c;当成key放入redis里面&#xff0c;业务执行完后再删除这个key.如还没有执行完&#xff0c;则请不要重复操作。纯属个人理解

Matlab 数控车床进给系统的建模与仿真

1、内容简介 Matlab217-数控车床进给系统的建模与仿真 可以交流、咨询、答疑 2、内容说明 略 摘 要:为提高数控车床的加工精度,对数控 车床进给系统中影响加工精度的主要因素进行了仿真分析研 动系统的数学模型,利用MATLAB软件中的动态仿真工具 究:依据机械动力学原理建立了…

低成本自动化改造的18个技术锚点深度解析

执行摘要 本文旨在深入剖析四项关键的低成本自动化技术&#xff0c;这些技术为工业转型提供了显著的运营和经济效益。文章将提供实用且深入的指导&#xff0c;涵盖老旧设备联网、AGV车队优化、空压机系统智能能耗管控以及此类项目投资回报率&#xff08;ROI&#xff09;的严谨…

我国脑机接口市场规模将破38亿元,医疗领域成关键突破口

当人类仅凭"意念"就能操控无人机编队飞行&#xff0c;当瘫痪患者通过"脑控"重新站立行走&#xff0c;这些曾只存在于科幻电影的场景&#xff0c;如今正通过脑机接口技术变为现实。作为"十四五"规划中重点发展的前沿科技&#xff0c;我国脑机接口…

Edu教育邮箱申请成功下号

这里是第2部分 如你所见&#xff0c;我根本就没有考虑流量的问题&#xff0c; 如果你有幸看到前面的内容&#xff0c;相信你能自己找到这个后续。