常见排序算法详解与C语言实现 - 详解

news/2025/10/6 20:08:24/文章来源:https://www.cnblogs.com/tlnshuju/p/19127865

常见排序算法详解与C语言实现 - 详解

2025-10-06 20:00  tlnshuju  阅读(0)  评论(0)    收藏  举报

目录

1. 冒泡排序(Bubble Sort)

2. 选择排序(Selection Sort)

3. 插入排序(Insertion Sort)

4. 希尔排序(Shell Sort)

5. 堆排序(Heap Sort)

6. 快速排序(Quick Sort)

7. 归并排序(Merge Sort)

总结


引言

排序算法是计算机科学中最基础也是最重要的算法之一。本文将详细介绍七种常见的排序算法,包括冒泡排序、选择排序、插入排序、希尔排序、堆排序、快速排序和归并排序,并给出每种算法的C语言实现代码。

1. 冒泡排序(Bubble Sort)

冒泡排序是最简单的排序算法之一,它重复地遍历要排序的列表,比较相邻的元素并交换它们的位置,直到列表排序完成。

演示
初始数组:[5, 3, 8, 6, 2]

第一轮:

  • 比较5和3 → 交换 → [3,5,8,6,2]

  • 比较5和8 → 不交换

  • 比较8和6 → 交换 → [3,5,6,8,2]

  • 比较8和2 → 交换 → [3,5,6,2,8] (8已到位)

第二轮:

  • 比较3和5 → 不交换

  • 比较5和6 → 不交换

  • 比较6和2 → 交换 → [3,5,2,6,8] (6已到位)

第三轮:

  • 比较3和5 → 不交换

  • 比较5和2 → 交换 → [3,2,5,6,8] (5已到位)

第四轮:

  • 比较3和2 → 交换 → [2,3,5,6,8] (排序完成)

void bob(int *a, int size){    // 外层循环控制排序轮数    for (int i = 0; i  a[j])            {                int temp = a[i];                a[i] = a[j];                a[j] = temp;            }        }    }}

时间复杂度

  • 最好情况:O(n)(已经排序的情况)

  • 平均和最坏情况:O(n²)

空间复杂度:O(1)

2. 选择排序(Selection Sort)

选择排序每次从未排序的部分选择最小(或最大)的元素,放到已排序部分的末尾。

演示
初始数组:[5, 3, 8, 6, 2]

第一轮:

第二轮:

第三轮:

第四轮:

void sel(int *a, int size){    // 外层循环控制已排序部分的末尾    for (int i = 0; i  a[j])            {                min_index = j;            }        }                // 如果最小元素不是当前元素,则交换        if (min_index != i)        {            swap(&a[i], &a[min_index]);        }    }}

时间复杂度:始终为O(n²)

空间复杂度:O(1)

3. 插入排序(Insertion Sort)

插入排序通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

演示
初始数组:[5, 3, 8, 6, 2]

第一步:

第二步:

第三步:

第四步:

void insert(int *a, int size){    // 从第二个元素开始(第一个元素视为已排序)    for (int i = 1; i = 0 && a[j] > k)        {            a[j + 1] = a[j];            j--;        }                // 将当前元素插入到正确位置        a[j + 1] = k;    }}

时间复杂度

  • 最好情况:O(n)(已经排序的情况)

  • 平均和最坏情况:O(n²)

空间复杂度:O(1)

4. 希尔排序(Shell Sort)

希尔排序是插入排序的改进版本,通过将原始列表分成多个子列表来提高插入排序的性能。

演示
初始数组:[5, 3, 8, 6, 2, 9, 1, 7, 4]

第一轮(间隔=4):

  • 子序列1:[5,2,4] → 排序后[2,4,5]

  • 子序列2:[3,9] → 排序后[3,9]

  • 子序列3:[8,1] → 排序后[1,8]

  • 子序列4:[6,7] → 排序后[6,7]

  • 数组变为:[2,3,1,6,4,9,8,7,5]

第二轮(间隔=2):

  • 子序列1:[2,1,4,8,5] → 排序后[1,2,4,5,8]

  • 子序列2:[3,6,9,7] → 排序后[3,6,7,9]

  • 数组变为:[1,3,2,6,4,7,5,9,8]

第三轮(间隔=1):

  • 标准插入排序 → [1,2,3,4,5,6,7,8,9]

void shell(int *a, int size){    // 初始间隔为数组长度的一半,逐步缩小间隔    for (int gap = size / 2; gap > 0; gap /= 2)    {        // 对每个间隔分组进行插入排序        for (int i = gap; i = gap && a[j - gap] > temp; j -= gap)            {                a[j] = a[j - gap];            }                        a[j] = temp;  // 插入元素到正确位置        }    }}

时间复杂度:取决于间隔序列,最好可达O(n log²n)

空间复杂度:O(1)

5. 堆排序(Heap Sort)

堆排序利用堆这种数据结构所设计的一种排序算法,是一种选择排序。

演示
初始数组:[5, 3, 8, 6, 2]

构建最大堆:

  1. 从最后一个非叶子节点(6)开始调整:

    • 6>2 → 不交换

  2. 调整节点3:

    • 3<8 → 交换 → [5,8,3,6,2]

    • 3无子节点 → 停止

  3. 调整节点5:

    • 5<8 → 交换 → [8,5,3,6,2]

    • 5>2 → 不交换

堆排序过程:

  1. 交换堆顶8和末尾2 → [2,5,3,6,8] (8已排序)

  2. 调整堆:

    • 2<5 → 交换 → [5,2,3,6,8]

    • 2<3 → 交换 → [5,3,2,6,8]

  3. 交换堆顶5和末尾2 → [2,3,5,6,8] (5,6,8已排序)

  4. 调整堆:

    • 2<3 → 交换 → [3,2,5,6,8]

  5. 交换堆顶3和末尾2 → [2,3,5,6,8] (排序完成)

void heapify(int *a, int size, int i){    int largest = i;         // 初始化最大元素为当前节点    int left = i * 2 + 1;    // 左子节点索引    int right = i * 2 + 2;   // 右子节点索引     // 如果左子节点存在且大于当前最大节点    if (left  a[largest])    {        largest = left;    }     // 如果右子节点存在且大于当前最大节点    if (right  a[largest])    {        largest = right;    }     // 如果最大节点不是当前节点,交换并继续调整    if (largest != i)    {        swap(&a[i], &a[largest]);        heapify(a, size, largest);    }} void heapsort(int *a, int size){    // 构建最大堆(从最后一个非叶子节点开始)    for (int i = size / 2 - 1; i >= 0; i--)    {        heapify(a, size, i);    }     // 逐个提取堆顶元素(最大值)并调整堆    for (int i = size - 1; i >= 0; i--)    {        // 将堆顶元素(最大值)与当前末尾元素交换        swap(&a[0], &a[i]);                // 调整剩余元素使其保持堆性质        heapify(a, i, 0);    }}

时间复杂度:O(n logn)

空间复杂度:O(1)

6. 快速排序(Quick Sort)

快速排序是一种分治算法,它选择一个"基准"元素,将数组分为两部分,一部分小于基准,一部分大于基准,然后递归地对这两部分进行排序。

演示
初始数组:[5, 3, 8, 6, 2]

第一轮(基准=2):

  • 2是最小值 → 分区后:[2,5,3,8,6]

  • 左子数组空,右子数组[5,3,8,6]

第二轮(基准=6):

  • 分区过程:

    • 5<6 → i=0 → [5,3,8,6]

    • 3<6 → i=1 → [5,3,8,6]

    • 8>6 → 不移动

  • 交换a[i+1]和基准 → [5,3,6,8]

  • 左子数组[5,3], 右子数组[8]

第三轮(左子数组基准=3):

  • 分区后:[3,5]

  • 排序完成

最终结果:[2,3,5,6,8]

void quicksort(int *a, int left, int right){    if (left < right)    {        // 选择最后一个元素作为基准值        int pivot = a[right];        int i = left - 1;  // 小于基准值的元素分界点         // 分区过程:将所有小于等于基准的元素移到左边        for (int j = left; j < right; j++)        {            if (a[j] <= pivot)            {                i++;                swap(&a[i], &a[j]);            }        }                // 将基准值放到正确位置        swap(&a[i + 1], &a[right]);        int pivot_index = i + 1;         // 递归排序左右两部分        quicksort(a, left, pivot_index - 1);        quicksort(a, pivot_index + 1, right);    }}

时间复杂度

  • 最好和平均情况:O(n logn)

  • 最坏情况:O(n²)(当数组已经排序或逆序时)

空间复杂度:O(logn)(递归调用栈)

7. 归并排序(Merge Sort)

归并排序是一种分治算法,它将数组分成两半,递归地对每一半进行排序,然后将两个有序的半部分合并成一个有序的整体。

演示
初始数组:[5, 3, 8, 6, 2]

拆分过程:
[5,3,8,6,2] → [5,3,8]和[6,2]
[5,3,8] → [5,3]和[8]
[5,3] → [5]和[3]
[6,2] → [6]和[2]

合并过程:

  1. 合并[5]和[3] → [3,5]

  2. 合并[3,5]和[8] → [3,5,8]

  3. 合并[6]和[2] → [2,6]

  4. 合并[3,5,8]和[2,6]:

    • 比较3和2 → 取2 → [2]

    • 比较3和6 → 取3 → [2,3]

    • 比较5和6 → 取5 → [2,3,5]

    • 比较8和6 → 取6 → [2,3,5,6]

    • 剩余8 → [2,3,5,6,8]

void merge(int *a, int l, int m, int r){    int n1 = m - l + 1;  // 左子数组长度    int n2 = r - m;       // 右子数组长度    int i, j, k;     // 分配临时数组存储左右子数组    int *L = (int *)malloc(n1 * sizeof(int));    int *R = (int *)malloc(n2 * sizeof(int));     // 拷贝数据到临时数组    for (i = 0; i < n1; i++)    {        L[i] = a[l + i];    }    for (j = 0; j < n2; j++)    {        R[j] = a[m + 1 + j];    }     // 合并两个有序子数组    i = 0;     // 左子数组索引    j = 0;     // 右子数组索引    k = l;     // 合并后数组索引     while (i < n1 && j < n2)    {        if (L[i] <= R[j])        {            a[k] = L[i];            i++;        }        else        {            a[k] = R[j];            j++;        }        k++;    }     // 拷贝左子数组剩余元素    while (i < n1)    {        a[k] = L[i];        i++;        k++;    }     // 拷贝右子数组剩余元素    while (j < n2)    {        a[k] = R[j];        j++;        k++;    }     // 释放临时数组内存    free(L);    free(R);}  void mergeSort(int arr[], int left, int right){    if (left < right)    {        // 计算中间索引(防止整数溢出)        int mid = left + (right - left) / 2;         // 递归排序左半部分        mergeSort(arr, left, mid);         // 递归排序右半部分        mergeSort(arr, mid + 1, right);         // 合并两个已排序的子数组        merge(arr, left, mid, right);    }}

时间复杂度:始终为O(n logn)

空间复杂度:O(n)(需要额外的存储空间)

总结

排序算法平均时间复杂度最好情况最坏情况空间复杂度稳定性
冒泡排序O(n²)O(n)O(n²)O(1)稳定
选择排序O(n²)O(n²)O(n²)O(1)不稳定
插入排序O(n²)O(n)O(n²)O(1)稳定
希尔排序O(n logn)~O(n²)O(n logn)O(n²)O(1)不稳定
堆排序O(n logn)O(n logn)O(n logn)O(1)不稳定
快速排序O(n logn)O(n logn)O(n²)O(logn)不稳定
归并排序O(n logn)O(n logn)O(n logn)O(n)稳定

在实际应用中,快速排序通常是最快的通用排序算法,而归并排序由于其稳定性和始终如一的O(n logn)性能,也是常用的选择。对于小规模数据,插入排序可能更高效,因为它有较低的常数因子。

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

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

相关文章

网站开发专业介绍pc开奖网站开发

已在内核代码中添加EmbedSky_hello驱动为例&#xff0c;进行内核编译时候出现了一下几个问题&#xff1a;1、在 /opt/EmbedSky/linux 2.6.30.4/drivers/char目录下修改“Kconfig”文件&#xff0c;添加如下内容&#xff1a;config EmbedSky_HELLOtristate "TQ2440/SKY2440…

南宁网站建设长春网站配图尺寸

在当今数字化金融时代&#xff0c;股票接口成为连接量化交易策略与金融市场的桥梁&#xff0c;为投资者提供了高效、准确的数据获取和交易执行功能。 一、股票接口的基本原理&#xff1a; 股票接口是量化交易系统的核心组成部分&#xff0c;它负责连接投资者的交易程序与金融市…

深入解析:43. 远程分布式测试实现

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实用指南:【相机基础知识与物体检测】更新中

实用指南:【相机基础知识与物体检测】更新中pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &qu…

外贸网站推广方法南昌百度关键词搜索

Windows 网络质量测试 References 保证网络稳定性&#xff0c;建议最大数据包延迟 200ms 以内&#xff0c;数据包最大和最小延迟差 100ms 以内&#xff0c;丢包率最好不丢包或 5% 以内。 ping www.baidu.com -t 调出 运行 (快捷键 Win R)&#xff0c;输入 cmd&#xff0c;pi…

网站用cms如何制作网址内容

SharePoint 2013 单一服务器场环境恢复数据库内容 笑男的公司服务很多客户&#xff0c;当然&#xff0c;这些客户都很挑剔&#xff0c;所以一般情况下生产&#xff08;Prod&#xff09;环境的服务是不能停的。 当然&#xff0c;如果你将包含相同网站集的数据库连接到同一个服务…

文化类网站建设福州seo推广外包

网上很多代码都略显繁琐&#xff0c;看了一下yy dalao的代码感觉很好&#xff0c;但他懒得打题解&#xff08;好吧我也是 以0为根节点的话&#xff0c;我把yy的一段代码删了改用fail[c]x0?0:ch[fail[x]][i];来实现特判&#xff0c;效果还不错&#xff01;也算是AC自动机的模版…

广州网站建设推广网站建设及推广开发

根据html&#xff1a;可知div是块级标签&#xff0c;span是行级标签 这里view类似于div&#xff0c;text类似于span&#xff0c;即 块级标签&#xff1a;view 行级标签&#xff1a;text、icon 类似效果 两个icon图标&#xff0c;置于第一排 两个view&#xff0c;分别位于第…

在上海哪个网站比较好自己在家可以做网站吗

在使用web-view时发现了一个问题总是会过段时间自己跳转到web-view是src地址 由于我是写的轮播图中嵌套一个web-view 所以当时我以为是轮播图和这个web-view冲突了 其实设计就是如此 自己跳 <view class"page-body"><web-view src"{{url}}">&…

AtCoder Beginner Contest 422 游记(VP)

很快过 $3t$,D 题稍微卡顿,E 题一堆垃圾错误。省流 很快过 \(3t\),D 题稍微卡顿,E 题一堆垃圾错误。10.6 内含剧透,请vp后再来。 不是题解!!!!!!! 赛前 本来在补 \(2023CCPCHarbin\) 的题目,做到最小生成…

详细介绍:无人机光纤FC接口模块技术分析

详细介绍:无人机光纤FC接口模块技术分析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "M…

2025 --【J+S 二十连测】-- 第十三套 总结

总结 T1 T3 考试时很快就写出了代码,没什么问题 T2 考试时很快就写出了代码,但思路不严谨,故失分 T4 T5 考试时很快就写出了部分分代码,无失分 题解 T1 利用最近学的数学方法即可 代码 #include<bits/stdc++.h&…

企业网站制作需要多少钱网页翻译功能在哪

配置文件目录 linux 系统中有很多配置文件目录/etc/systemd/system、/lib/systemd/system 以及/usr/lib/systemd/system 等&#xff0c;这三者有什么样的关系呢&#xff1f; 以下是网络上找的资料汇总&#xff0c;并加了一些操作验证。方便后期使用 介绍 目录/lib/systemd/s…

文件提供的基本操作

创建文件(create) 1.所需外存空间大小 2.文件存放路径 3.文件名 操作系统在接受大create之后 1.在外存中找到文件所需空间(上小结内容) 2.根据文件存放路径信息找到目录对应的目录文件,在目录文件创建文件对应的目…

上海建设小学网站电脑从做系统怎么找回以前登录的网站

数据结构之图 图的定义和概念图的定义图的术语 图的类型定义图的存储结构数组&#xff08;邻接矩阵&#xff09;表示法无向图的邻接矩阵表示法有向图的邻接矩阵表示法网&#xff08;即有权图&#xff09;的邻接矩阵表示法 邻接矩阵的ADT定义邻接表&#xff08;链式&#xff09;…

网站制作步骤深圳营销推广公司

什么是IOC&#xff1f; 控制反转&#xff0c;依赖注入 1、控制什么&#xff1f; 控制对象的创建及销毁(生命周期) 2、反转什么&#xff1f; 讲对象的控制权交给IOC容器

无锡知名网站制作广州个人网站制作公司

引言&#xff1a;从本文开始&#xff0c;我们详细介绍Xilinx CIC IP核滤波器相关知识&#xff0c;包括CIC IP核提供的特性、IP核接口描述以及IP核设计指导等相关内容。1.概述级联积分器梳状(CIC)滤波器&#xff0c;也称为Hogenauer滤波器&#xff0c;是用于实现数字系统中大采样…

深入解析:MySQL(50)如何使用UNSIGNED属性?

深入解析:MySQL(50)如何使用UNSIGNED属性?pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &quo…

网站建设公司新员工培训ppt重庆是哪个省

条款15: 让operator返回*this的引用 c的设计者bjarne stroustrup想使用户自定义类型尽可能地和固定类型的工作方式相似。所以有重载运算符&#xff0c;类型转换函数、拷贝赋值、拷贝构造函数等。 类c中&#xff0c;缺省版本的operator函数具有如下形式&#xff1a; c& c::…

衡水企业网站河北建设集团股份有限公司

背景 众所周知&#xff0c;目前群晖DSM7中使用Synology Photos做照片管理时&#xff0c;个人照片只能默认索引 /home/Photos 文件夹&#xff0c;但是如果个人照片很多或者用户很多时&#xff0c;共享文件夹/homes 所在的存储空间就会不够用 当然&#xff0c;如果你的存…