数据结构——排序(C语言版)

news2024/12/27 16:29:39

冒泡排序:

        冒泡排序是一种简单直观的排序算法,其基本思想是多次遍历待排序数组,每次遍历时比较相邻的两个元素,如果它们的顺序不符合排序规则(比如升序),则交换它们的位置,直到整个数组有序为止。

代码解释分为以下几个步骤:

  1. 外层循环:for (int i = 0; i < n; i++)

            这是冒泡排序的主循环,控制总共需要进行多少轮排序。对于长度为n的数组,最多需要n-1轮排序就可以将数组完全排序好。
  2. 内层循环:for (int j = 0; j < n - i - 1; j++)

           内层循环负责相邻元素的比较和交换。每次内层循环都会把当前未排序部分中最大的元素放置到到数组的最后位置,就像气泡一样冒到最上层。
  3. 比较和交换:if (a[ j ] > a[ j + 1])

            在内层循环中,通过比较相邻的两个元素a[ j ]和 a[ j + 1]的大小关系,如果a[ j ]大于 a[ j + 1],则交换它们的位置,确保每次循环结束后,最大的元素都被交换到了当前未排序部分的末尾。
  4. Swap函数:Swap(&a[j], &a[j + 1]);

           这里调用了一个交换函数 Swap,用于交换数组中两个元素的值并使用了取地址因为形参的改变并不会影响实参,所以需要用到&符号。

 

        随着每轮外层循环的进行,内层循环将大的数据排到数组的末端,直到所有元素都被正确排序。

选择排序:

        每⼀次从待排序的数据元素中选出最⼩(或最⼤)的⼀个元素,存放在序列的起始位置,直到全部待 排序的数据元素排完 。

代码解释分为以下几个步骤:

  1. 初始化: begin表示当前未排序部分的起始索引,end表示当前未排序部分的末尾索引。

  2. 查找最大值和最小值

         在每一轮循环中,通过遍历未排序部分(begin到end),找到其中的最大值max和最小值min的索引。
  3. 特殊情况处理

          如果begin的索引就是找到的max的索引,说明max可能被错误地更新为min,因此需要将max重新赋值为min。
  4. 交换操作

           将最小值min移动到当前起始位置 begin,将最大值max移动到当前末尾位置end。
  5. 开始缩小排序范围

            每完成一轮排序begin向右移动一位,end向左移动一位,缩小未排序部分的范围,也就是从两头开始向中间缩。

插入排序:

        直接插⼊排序是⼀种简单的插⼊排序法,其基本思想是:把待排序的记录按其关键码值的⼤⼩逐个插⼊到⼀个已经排好序的有序序列中,直到所有的记录插⼊完为⽌,得到⼀个新的有序序列。
代码解释分为以下几个步骤:
  1. 循环结构:外层循环for (int i = 0; i < n-1; i++)控制每次插入的位置。从数组的第一个元素开始,依次将后面的元素插入到已排序区间中。

  2. 初始化插入位置:在每次外层循环的开始,将end初始化为i。这表示当前待插入元素 a[i+1]将要插入到已排序区间中的合适位置。

  3. 保存待插入元素:用 temp变量保存当前待插入的元素a[i+1]的值。

  4. 内层循环:while (end >= 0)是一个内部循环,用来寻找temp 在已排序区间中的正确位置。

          如果 a[end] > temp,表示已排序区间的当前元素大于temp,则将该元素后移一位a[end + 1] = a[end],同时end--继续向前比较。                                                                                       如果 a[end] <= temp,说明已经找到了temp的插入位置,退出循环。
  5. 插入操作:在内层循环结束后,将temp插入到正确的位置及a[end + 1] = temp。

 

希尔排序:

        希尔排序法⼜称缩⼩增量法。希尔排序法的基本思想是:先选定⼀个整数(通常是gap = n/3+1),把 待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,相当于在插入排序之前对原数据进行一个预排序,当gap=1时就相当于 直接插⼊排序。
        它是在直接插⼊排序算法的基础上进⾏改进⽽来的,因为它在预排序时将整个数组变的相对有序,综合来说它的效率肯定是要⾼于直接插⼊排序算法的。

代码解释分为以下几个步骤:

  1. 初始间隔(gap)设置

             希尔排序的特点是使用不同的间隔进行分组插入排序,初始间隔通常取数组长度n。
  2. 间隔(gap)的缩小:

             在每次循环中,通过gap /= 3来减小间隔,这是希尔排序的核心。通常使用gap = gap / 3+1来缩小间隔。这里最后的+1是有必要的,当gap最后为3或小于3时再除3会直接为0。gap需要保证最后一次排序gap为1,完整最终的排序。
  3. 插入排序的应用

             对于每个间隔,类似上面插入排序的方式将当前元素插入到已排序部分的正确位置。这一步骤是希尔排序的关键,通过大步长的排序预排序,使得数组逐渐趋向部分有序,再通过小步长的排序最终达到完全有序。
  4. 终止条件

               当间隔gap缩小到1时,此时完成了最后一次以间隔为1的插入排序及直接插入排序,整个数组也就完成了排序。

堆排序:

        堆排序(Heapsort)是指利⽤堆积树(堆)这种数据结构所设计的⼀种排序算法,它是选择排序的⼀ 种。它是通过堆来进⾏选择数据。需要注意的是排升序要建⼤堆,排降序建⼩堆。

代码解释分为以下几个步骤:

AdjustDwon函数:

        用于向下调整堆,确保以parent为根节点的子树满足大根堆的性质。

        根据传入的parent节点,计算其左孩子节点child = parent * 2 + 1。

        进入循环,只要child小于n(即数组长度),继续执行向下调整操作。

        在循环中,首先判断child+1是否<n,如果不小于则表示只有一个左孩子,保证数组不会越界访问再选择左右子节点中值较大的节点作为child,

        如果child节点的值大于parent节点的值,则交换它们,并更新parent 和child 索引,继续向下调整。

        如果 parent已经大于等于child,则跳出循环,调整结束。

HeapSort 函数:

实现了堆排序算法,包括建堆和排序两个阶段。

        建堆阶段:从最后一个非叶子节点开始,依次向前调用AdjustDwon函数,使得整个数组调整为大顶堆。这里使用(n - 2) / 2计算最后一个非叶子节点的下标(及最后一个叶子节点的父亲节点),确保从第一个非叶子节点开始向下调整。(n-2)/2展开为: (n-1-1)/2。n-1表示从数组最后一个有效数据的下标开始,其父节点的下标为是(n-1-1)/2 = (n-2)/2。

 

        排序阶段:通过循环,每次将堆顶元素(当前最大值)与未排序部分的最后一个元素交换,然后调用AdjustDwon函数重新调整剩余元素,使其继续保持大顶堆的性质。size变量递减,确保每次排序后未排序部分减少一个元素。

快速排序:        

        hoare法:

        快速排序是Hoare于1962年提出的⼀种⼆叉树结构的交换排序⽅法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两⼦序列,左⼦序列中所有元素均⼩于基准值,右⼦序列中所有元素均⼤于基准值,然后最左右⼦序列重复该过程,直到所有元素都排列 在相应位置上为⽌。

代码解释分为以下几个步骤:

PartSort1函数解释:

  1. 参数和变量初始化

            a 是一个整型数组, left 和 right 分别表示当前排序部分的左右边界。                                 keyi是基准元素的下标,默认初始设为  left 。
  2. 分区过程

          left 和 right是两个指针,它们从左右两端向中间移动,寻找需要交换的元素位置                     while (left <= right && a[right] > a[keyi]) --right;:从右向左找到第一个小于或等于基准元素的值。                                                                                                                                           while (left <= right && a[left] < a[keyi]) ++left;:从左向右找到第一个大于或等于基准元素的值。                                                                                                                      
  3. 交换操作

    • 如果left <= right,即找到了需要交换的两个元素,则执行交换操作 Swap(&a[left++], &a[right--]);
    • left++和 right--确保在交换后继续向中间缩,继续寻找下一对需要交换的元素。
  4. 基准元素归位

    • 当 left > right时,意味着 left和right指针已经错过,此时right指向的位置就是基准元素最终需要放置的位置。
    • 将基准元素a[keyi]与a[right]进行交换,确保基准元素左侧的元素都小于等于它,右侧的元素都大于等于它。
  5. 返回值

    • 返回 right,即基准元素的最终位置,用于后续递归调用快速排序时排序以keyi为基准的左右区间。

QuickSort函数解释:

  1. 递归终止条件

              如果left >= right,表示当前排序的部分只有一个元素或没有元素,无需继续排序,直接返回。
  2. 分区和递归排序

          key变量存储了PartSort1返回的基准元素的最终位置。接着,递归调用QuickSort函数分别对基准元素左右两侧的子数组进行排序:                                                               QuickSort(a, left, key - 1);:排序右侧子数组。                                                               QuickSort(a, key + 1, right);:排序左侧子数组。

     

         挖坑法:

        创建左右指针。⾸先从右向左找出⽐基准⼩的数据,找到后⽴即放⼊左边坑中,当前位置变为新 的"坑",然后从左向右找出⽐基准⼤的数据,找到后⽴即放⼊右边坑中,当前位置变为新的"坑",结 束循环后将最开始存储的分界值放⼊当前的"坑"中,返回当前"坑"下标(即分界值下标)

代码解释分为以下几个步骤:

  1. 基准值选择和初始化

          keyi变量初始化为 a[left],即选择当前分区的最左边元素作为基准值。                                    hole变量用于保存坑的位置。
  2. 分区过程

          从右向左找小元素:                                                                                                                   while (left < right && a[right] >= keyi):从右向左找到第一个小于基准值keyi的元素。                                                                                                                                                                a[hole] = a[right]:将找到的小于基准值的元素移到坑位,即 hole 所指向的位置。                                                                                                                                                                    hole = right:更新hole的位置为刚刚移动的元素的位置。                                                                                                                                                                                                                                                                                                                                                           从左向右找大元素:                                                                                                                  while (left < right && a[left] <= keyi):从左向右找到第一个大于基准值keyi的元素。                                                                                                                                                                a[hole] = a[left]:将找到的大于基准值的元素移到之前坑洞的位置,即hole所指向的位置。                                                                                                                                                  hole = left;更新hole的位置为刚刚移动的元素的位置。     
  3. 基准值最终归位

               当left == right时,将基准值keyi放到hole所指示的最终位置上。
  4. 返回值

    • 返回hole,即基准值的最终位置,下次快速排序算法递归调用hole的左区间与右区间

       

        前后指针法:

代码解释分为以下几个步骤:

  1. 变量初始化

              prev和cur是两个指针,prev初始值为left,cur初始值为left + 1。这两个指针用于遍历数组并进行元素交换操作。                                                                                                                  keyi初始化为 left,表示选择最左边的元素作为基准值的下标位置。
  2. 分区过程

    • 遍历过程:                                                                                                                                 cur从left + 1开始向右遍历,查找小于基准值a[keyi]的元素。                                           如果a[cur]小于a[keyi],则先++prev,将cur所指向的元素与prev的元素交换。                   这样,prev指向的是当前已经处理好的小于基准值的部分的最后一个元素的位置。
  3. 最终位置确定

                  遍历结束后,将基准值a[keyi]与a[prev]进行交换,确保基准值被放置在正确的位置上。此时,prev所指向的位置就是基准值的最终位置。
  4. 返回值

            返回prev,即基准值的最终位置,下次快速排序算法递归调用prev的左区间与右区间。

归并排序:

        归并排序(MERGE-SORT)是建⽴在归并操作上的⼀种有效的排序算法,该算法是采⽤分治法(Divide and Conquer)的⼀个⾮常典型的应⽤。将已有序的⼦序列合并,得到完全有序的序列;即先使每个 ⼦序列有序,再使⼦序列段间有序。若将两个有序表合并成⼀个有序表,称为⼆路归并。 
代码解释分为以下几个步骤:
        主函数Mergesort:

           Mergesor函数是归并排序的入口函数,接收一个整型数组a和数组长度n。

           在函数内部,首先动态分配了一个与数组a同样大小的临时数组temp,用于在排序过程中存储中间结果。

           接着调用了递归函数 Mergesor1,负责实际的归并排序操作。

           最后,释放了临时数组temp的内存,避免内存泄漏。

        

        递归函数Mergesort1: 

       Mergesort1是归并排序的递归函数,负责实际的排序工作。

        首先检查区间[left, right]是否为空或者只有一个元素,如果是,则直接返回,不需要再进行排序。

        计算中间位置mid,将数组分割为两部分:左半部分[left, mid]和右半部分[mid+1, right]。

        递归调用Mergesort1对左右两部分继续递归分割。

    接下来是合并操作:                                                                                                                               使用begin1和begin2分别指向左右两个区间的起始位置,end1和end2分别指向左右两个区间的结束位置。                                                                                                                                              比较a[begin1]和a[begin2]的大小,将较小的元素放入临时数组temp中,并将相应的指针向后移动。                                                                                                                                                           如果某一区间还有剩余的元素,直接将剩余的元素复制到临时数组temp中。                            最后,通过memcpy将排序好的临时数组temp的内容复制回原数组 a 的对应区间 [left, right]。

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

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

相关文章

Oracle数据库入门

目录 Oracle基础概念数据库安装连接Oracle查看当前用户 数据表的基本概念查看当前系统表Orcale函数单行函数多行函数/组函数/聚合函数 SQL语句DMLinsert批量插入数据创建新表在旧表中插入 delete全表删除 update DDLcreatealterdrop 连接 Oracle基础概念 数据库: 数据的仓库 以…

探索大模型的“心理理论”能力:TMBENCH基准测试

人工智能咨询培训老师叶梓 转载标明出处 心理理论是理解他人信念、意图、情感等心理状态的能力&#xff0c;对人类社会交往至关重要。近期研究引发了关于LLMs是否展现出ToM的辩论。然而&#xff0c;现有的评估方法受限于范围狭窄、主观判断和潜在的数据污染等问题&#xff0c;无…

万能DIY预约小程序源码系统 自由DIY 适合任何行业的在线预约小程序 带源代码包以及搭建部署教程

系统概述 随着移动互联网的发展&#xff0c;小程序作为一种轻量级应用&#xff0c;因其便捷性和易用性而受到广大用户的喜爱。各行各业都在积极探索如何利用小程序提升服务体验。小编给大家分享一款万能DIY预约小程序的源码系统&#xff0c;该系统支持自由定制&#xff0c;适用…

S3GCL Spectral, Swift, Spatial Graph Contrastive Learning

发表于:PMLR24 推荐指数: #paper/⭐⭐⭐ 总结做了什么: 利用gcn对比学习训练mlp来提取特征嵌入,使得训练完毕使用的时候,可以更快的得到嵌入(类似于师生蒸馏的加速).其中,结合了异配图的chebnet2,以及高通低通过滤,和非对称对比学习等 看图解释:作者将全通的MLP训练得到的嵌入…

PostgreSQL入门与进阶学习,体系化的SQL知识,完成终极目标高可用与容灾,性能优化与架构设计,以及安全策略

​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录 概述基础篇初级篇进阶篇…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 7月31日,星期三

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年7月31日 星期三 农历六月廿六 1、 海关总署&#xff1a;我国关税总水平目前已经降至7.3%&#xff0c;接近发达国家平均水平。 2、 网络身份证要来了&#xff1a;两部门征求意见&#xff0c;拟为社会公众统一签发网号、网证…

HighConcurrencyCommFramework c++通讯服务器框架 :网路通迅实战

数据总在两端进行&#xff0c;一个客户端&#xff0c;一个服务器端 连接建立起来&#xff0c;数据双向流动&#xff0c;这叫双工&#xff0c;你可以发给我我也可以发给你 既然服务器端是被动的接受的&#xff0c;那么客户端必须得知道服务器的地址 我浏览器要访问的淘宝网&a…

基于Spring boot + Vue的加油站系统

项目名称&#xff1a;加油站系统 作者的B站地址&#xff1a;程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址&#xff1a;程序员云翼-CSDN博客 1.项目技术栈&#xff1a; 前后端分离的项目 后端&#xff1a;Springboot MybatisPlus 前端&#xff1a;Vue…

Jetbrains Idea插件开发教程

背景介绍 痛点&#xff1a;在idea开发过程中&#xff0c;希望按需驼峰选中文本。现在默认是一整个单词选中&#xff0c;只有在设置–>智能按键 中开启了使用"CamelHumps单词"时能够驼峰选中。但是这种情况比较粗暴&#xff0c;直接全局开启了。但是在日常开发中&…

论文《Few-Shot Object Detection with Model Calibration》的解读

《Few-Shot Object Detection with Model Calibration》论文的解读 作者&#xff1a;Qi Fan1, Chi-Keung Tang1 , and Yu-Wing Tai1,2 单位&#xff1a;1 The Hong Kong University of Science and Technology, 2 Kuaishou Technology 邮箱&#xff1a;fanqicsgmail.com, ckta…

Unity | Shader基础知识(第二十一集:应用-怪兽膨胀、顶点着色器和表面着色器合并)

目录 一、前言 二、资源介绍 三、顶点着色器和表面着色器一起使用基础 1.使用表面着色器代码 2.光照选择 3.加入顶点着色器 4.补充表面着色器 四、在顶点着色器中完成怪兽膨胀功能 1.膨胀原理解释 2.完成膨胀代码 1&#xff09;.写出需要的结构体 2&#xff09…

修改所属用户/用户组——chown

目录 &#xff08;1&#xff09;修改所属用户 &#xff08;2&#xff09;修改所属用户组 &#xff08;3&#xff09;修改所属用户和用户组 &#xff08;4&#xff09; 选项 -R 使用 chown 可以修改文件/文件夹的所属用户&#xff0c;所属用户组&#xff1b; 当然与 chmod …

7thonline第七在线出席中服协时尚科技峰会 探讨AI商品管理落地

7月25-26日&#xff0c;中国服装协会2024中国时尚科技创新峰会在杭州隆重举行&#xff0c;本次大会以“新质焕能&#xff0c;革故鼎新”为主题&#xff0c;为持续推动服装产业鼎力创新&#xff0c;以新质生产力的新特征为引领&#xff0c;布局高质量发展新赛道&#xff0c;充分…

MySQL基础练习题15-进店却未进行交易过的顾客

题目&#xff1a;有一些顾客可能光顾了购物中心但没有进行交易。来查找这些顾客的 ID &#xff0c;以及他们只光顾不交易的次数。 准备数据 分析数据 题目&#xff1a;有一些顾客可能光顾了购物中心但没有进行交易。来查找这些顾客的 ID &#xff0c;以及他们只光顾不交易的次…

c++迭代器的介绍

迭代器主要的作用就是为了可以像数组那样实现指针向后移动到下一个数据。同时迭代器统一了所有容器&#xff0c;让所有容器可以通过迭代器互通数据。 那么下面我们来看看迭代器 数组的优势 我们数组的优势就是内存连续&#xff0c;那么我们将首地址的地址进行加减就可以访问…

【多线程】补充内容 {线程池;线程安全的单例模式;STL容器、智能指针的线程安全;其他常见的各种锁:自旋锁、读写锁}

一、线程池 1.1 概念 线程池一种线程使用模式&#xff1a; 线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。 而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务&#xff1a;&#xff08;线程池的优点&#xff09; 这避免了在处…

将真实世界带入实验室—如何使用ALPS进行网络损伤仿真测试

不完美的真实世界网络 不同于稳定、可控的传统网络实验室的网络环境&#xff0c;真实世界的网络环境面临着许多挑战和风险&#xff0c;这些挑战在很大程度上增加了网络的脆弱性和复杂性&#xff1a; &#xff08;1&#xff09;物理损伤&#xff1a;真实世界的网络基础设施&am…

Java扫码点餐系统奶茶店类型堂食配送小程序源码

&#x1f964;【奶茶新风尚&#xff01;扫码点餐系统&#xff0c;堂食配送两不误】&#x1f964; &#x1f3e0;【堂食新体验&#xff1a;一键下单&#xff0c;即享美味】&#x1f3e0; 踏入心仪的奶茶店&#xff0c;不再需要排队等候点单&#xff0c;只需拿起手机&#xff0…

TongHttpServer 简介

1. 概述 随着网络技术的飞速发展,高并发大用户场景越来越普遍,单一应用服务节点已经不能满足并发需求,为了提高整个系统可靠性,扩展性,吞吐率,通常将多个应用服务器通过硬负载/软负载组成集群,负载均衡器根据不同负载算法将请求分发到各个应用服务器节点。 Tong…

飞书打卡 快捷指令

使用快捷指令定时飞书打卡 在网上找了一圈&#xff0c;只有钉钉打卡的快捷指令&#xff0c;但是公司换飞书&#xff0c;哪个打工人不怕忘记打卡呢&#xff0c;所以自己研究了一下&#xff0c;其实也很简单。 找url 问题的最关键是打开飞书的打卡界面 如果只是打开飞书APP 很…