数据结构初阶排序全解
目录
1>>排序前言
2>>插入排序
2.1>>直接插入排序
2.2>>希尔排序
3>>选择排序
3.1>>直接选择排序
3.2>>堆排序
4>>交换排序
4.1冒泡排序
4.2快速排序
5>>归并排序
6>>测试
test.c
sort.h
sort.c
7>>总结
1>>排序前言
排序顾名思义,就是将一组乱序的数,按从大到小或者从小到大进行排列的操作。
常见的排序如下
可以看到排序也是有分类的,既然有分类,那么这边给出宝子们一个思考,在最后测试的时候给出答案,思考1:排序方法这么多,哪个最好呢?最差的有什么用呢?
那么废话不多说,今天的重点内容就是理解并写出一个个排序算法,现在直接上高速,带着宝子们攻破一个个排序算法!
这边给出各个排序算法的声明,会在对应内容进行解释,宝子们先有个印象即可~~
2>>插入排序
2.1>>直接插入排序
直插排序类似生活中的扑克牌,每拿到一张新牌,就要插入到手中的有序扑克牌中。那靠这个思路就可以写出步骤:
1.设置新插入的牌tmp
2.比较之前的每一个牌,找到比tmp小的,将整体往后移动腾出空间
3.插入到这张牌后面
代码如下:

设置end为每次手中牌的末尾,tmp为新插入的牌,循环end>=0进入循环,如果比较发现手中牌比插入牌大,那么将手中牌往后移动一位,若小,跳出循环,将这张牌后一张牌,也就是空出来的位置赋值tmp,也就是新插入的牌。
2.2>>希尔排序
希尔排序相当于直接插入排序的最优化法,什么意思呢?就是通过预排序,将整个数组提升到接近有序的状态,最后再用直插排序进行排序,这样会快很多,那怎么实现呢?就是通过分组,将每隔n/3+1个数两两分为一组,先实现一次预备排序,这里直接来看代码进行解释


刚开始令gap等于n,只要gap大于1那么就进入循环,每次gap等于gap/3+1,每次都进行预排序,当gap为1时就是直接插入排序啦,代码也只需要更改直接插入排序里面为1的值即可。
3>>选择排序
3.1>>直接选择排序
思路:
1.定义begin和end代表开始与结束,每次循环begin++,end--直到begin>=end
2.找出数组内最大值和最小值
3.将最大值和end交换,最小值与begin交换
代码如下:

代码就是定义begin为0,end为末尾值,然后循环遍历找最大值下标和最小值下标,在出循环的时候进行交换即可。
注意:当begin等于max的时候,此时交换相当于原地不动,因此需要让max等于min让它实现原地交换一次,在跟end互换。如 9 3 5 1begin为9,max也为9,end为1,min也为1,实现上面交换,1 3 5 9,max又跟end交换,9 3 5 1,所以需要避免这种情况。
3.2>>堆排序
1.要实现堆排序,首先得要是一个堆,那么第一个循环就要把堆建立,双亲结点向下调整思想,从最后一个结点的双亲结点开始(最后一个结点是n-1)它的双亲结点是-1然后除2,依次向下调整,这样就是一个堆。
2.将这个棵树的每一个子树都想象成一个堆,然后:
3.从最后一个结点开始,到0为止,每次交换它的最后一个结点和第0个结点,然后向下调整,这样就能够从大/从小排序

4>>交换排序
4.1冒泡排序
需要十个数就用数组存储,那么两两相邻的相比不就是数组两个相邻元素的比较吗?所以使用j和j+1进行比较,这里要注意j要<9,因为这样操作的就是0-8下标的值,j+1就不会越界,并且每次循环都将一个最大的放到最右边了,所以j<9-i,每次循环少循环一次。
到这里,基本框架已经完成,我们只需再完善一下:如果我们输入的十个数是9 0 1 2 3 4 5 6 7 8,那么会发现,即使我们第一次循环就已经排序完成,但是循环还是进行了,那么此时我们就可以加入一个布尔值变量,在循环开始定义为1,如果对数值进行两两替换,那么布尔值就为0,若出来为1就跳出循环即可,这种操作广泛用于各种循环和一些满足条件跳出的代码,可以充分减少运行次数。

4.2快速排序
快速排序讲一种最经典的排序找基准值法——hoare法


如何实现快速排序呢?就要通过递归的思想实现,每次找到一个基准值,使得左边的数都小于它,右边的数都大于它。
那么hoare方法就是设定基准值为0下标值,定义left和right,从右边往左找比基准值小的,从左往右找比基准值小的,然后进行交换,最后当left>right时,交换基准值和right,返回right就是基准值啦!
5>>归并排序
这个比较复杂,但是也还好,容我细说

以上素材来源网络,如有侵权告知删除。
借用一下,通过这张图片来理解,所谓归并,就是一个数组微分积分的过程,将一个无序数组,不断的拆解,拆成单个单个有序数组,实现两个有序数组的排序,这就是归并。
那么代码怎么实现呢?
首先,这是一个递归的过程,每次都进行二分,分成左右序列,
0-3为新无序数列,4-7为新无序数列,分到它为有序为止,也就是
单个的时候,本身就是一个有序的
比较10,6,谁小谁先放,然后依次放入新数组,此时需要一个新数组暂时存排序后的值,然后赋值给原数组。来看代码吧
void _MergeSort(int* arr,int left, int right,int* tmp) {if (left >= right)return; int mid = left + (right - left) / 2;//分成左右序列_MergeSort(arr, left, mid, tmp);_MergeSort(arr, mid+1, right, tmp);//定义两个假有序数组int begin1 = left;int end1 = mid;int begin2 = mid + 1;int end2 = right;int index = begin1;//index表示第二个暂存数组的下标值while (begin1 <= end1 && begin2 <= end2) {if (arr[begin1] > arr[begin2]) {tmp[index++] = arr[begin2++];}else{tmp[index++] = arr[begin1++];}}while (begin1 <= end1) {tmp[index++] = arr[begin1++];}while (begin2 <= end2) {tmp[index++] = arr[begin2++];}//最后把暂存数组值放到原数组for (int i = left; i <= right; i++) {arr[i] = tmp[i];}
}
void MergeSort(int* arr, int n) {int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n - 1, tmp);free(tmp);
}
希望我的讲解能帮助大家理解归并排序。
6>>测试
接下来测试每个排序的时间复杂度

这里能看到快排和归并是最快的,还有堆排序,这边没有导入它的代码,下来可以自己尝试噢,希尔其次,冒泡排序最次,那解决前面的疑问,为什么还要冒泡排序呢?因为它有教学意义,较为简单,更好理解。
test.c
#include"sort.h"
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void PrintArr(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}void test() {int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };int n = sizeof(a) / sizeof(a[0]);printf("排序之前:");PrintArr(a, n);MergeSort(a, n);//quicksort(a, 0, n - 1);printf("排序之后:");PrintArr(a, n);
} void TestOP()
{srand(time(0));const int N = 100000;int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);int* a3 = (int*)malloc(sizeof(int) * N);//int* a4 = (int*)malloc(sizeof(int) * N);int* a5 = (int*)malloc(sizeof(int) * N);int* a6 = (int*)malloc(sizeof(int) * N);//int* a7 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; ++i){a1[i] = rand();a2[i] = a1[i];a3[i] = a1[i];//a4[i] = a1[i];a5[i] = a1[i];a6[i] = a1[i];//a7[i] = a1[i];}int begin1 = clock();insertsort(a1, N);int end1 = clock();int begin2 = clock();shellsort(a2, N);int end2 = clock();int begin3 = clock();selectsort(a3, N);int end3 = clock();//int begin4 = clock();//HeapSort(a4, N);//int end4 = clock();int begin5 = clock();quicksort(a5, 0, N - 1);int end5 = clock();int begin6 = clock();MergeSort(a6, N);int end6 = clock();//int begin7 = clock();//BubbleSort(a7, N);//int end7 = clock();printf("InsertSort:%d\n", end1 - begin1);printf("ShellSort:%d\n", end2 - begin2);printf("SelectSort:%d\n", end3 - begin3);//printf("HeapSort:%d\n", end4 - begin4);printf("QuickSort:%d\n", end5 - begin5);printf("MergeSort:%d\n", end6 - begin6);//printf("BubbleSort:%d\n", end7 - begin7);//free(a1);//free(a2);//free(a3);//free(a4);//free(a5);//free(a6);//free(a7);
}int main()
{//test();TestOP();return 0;
}
sort.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
#include"stack.h"
void insertsort(int* arr, int n);//直插排序
void shellsort(int* arr, int n);//希尔排序void selectsort(int* arr, int n);//选择排序
void HeapSort(int* arr, int n);//堆排序void BubbleSort(int* arr, int n);//冒泡排序
void quicksort(int* arr, int left, int right);//快排
void QuickSortNonR(int* arr, int left, int right);//非递归借栈快排void MergeSort(int* arr, int n);//归并排序
sort.c
#include"sort.h"
#include"stack.h"void insertsort(int* arr, int n) {for (int i = 0; i < n - 1; i++) {int end = i;int tmp = arr[end + 1];while (end >= 0) {if (arr[end] > tmp) {arr[end + 1] = arr[end];end--;}else {break;}}arr[end + 1] = tmp;}
}void shellsort(int* arr, int n) {int gap = n;while (gap > 1) {gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++) {int end = i;int tmp = arr[end + gap];while (end >= 0) {if (arr[end] > tmp) {arr[end + gap] = arr[end];end-=gap;}else {break;}}arr[end + gap] = tmp;}}
}
void swap(int* x, int* y) {int tmp = *x;*x = *y;*y = tmp;
}
void selectsort(int* arr, int n) {int end = n - 1;int begin = 0;while(begin<end){int min = begin;int max = begin;for (int i = begin + 1; i <=end; i++) {if (arr[i] < arr[min])min = i;if (arr[i] > arr[max])max = i;}if (begin == max)max = min;swap(&arr[min], &arr[begin]);swap(&arr[max], &arr[end]);begin++;end--;}
}// 你这个是什么方法hoare找基准值
int _quicksort(int* arr, int left, int right) {int keyi = left;left++;while (left <= right) {while (left <= right && arr[right] > arr[keyi])right--;while (left <= right && arr[left] < arr[keyi])left++;if (left<=right)swap(&arr[left++], &arr[right--]);}swap(&arr[right], &arr[keyi]);return right;
}
int _quicksort1(int* arr, int left, int right) {//挖洞法//hole等于初始值,right从右从右往左找小,left找大int hole = left;int key = arr[hole];while (left < right) {while (left<right && arr[right]>key) {right--;}arr[hole] = arr[right];hole = right;while (left<right && arr[left]<key) {left++;}arr[hole] = arr[left];hole = left;}arr[hole] = key;return hole;
}int _quicksort2(int* arr, int left, int right) {//前后指针int prev = left;int key = left;int pcur = left + 1;while (pcur <= right) {if (arr[pcur] < arr[key]&& ++prev != pcur) {swap(&arr[pcur], &arr[prev]);}pcur++;}swap(&arr[prev], &arr[key]);return prev;
}
void quicksort(int* arr, int left, int right) {//找基准值//right从右往左找比基准值小,left从左往右找比基准值大,找到实现交换,// left>right交换right和基准值if (left >= right)return;int keyi = _quicksort(arr,left,right);quicksort(arr, left, keyi-1);quicksort(arr, keyi+1, right);
}void QuickSortNonR(int* arr, int left, int right) {stack st;stinit(&st);stenter(&st, right);stenter(&st, left);while (!stackempty(&st)) {int begin = stackTop(&st);stackpop(&st);int end = stackTop(&st);stackpop(&st);//双指针找基准值划分左右序列int prev = begin;int key = begin;int pcur = begin + 1;while (pcur <= end) {if (arr[pcur] < arr[key] && ++prev != pcur) {swap(&arr[pcur], &arr[prev]);}pcur++;}swap(&arr[prev], &arr[key]);key = prev;//基准值下标为key//划分左序列(左子树)[begin,key-]和右序列[key+1,end]if (key + 1 < end) {stenter(&st, end);stenter(&st, key+1);}if (key - 1 > begin) {stenter(&st, key-1);stenter(&st,begin);}}struin(&st);
}
void _MergeSort(int* arr,int left, int right,int* tmp) {if (left >= right)return; int mid = left + (right - left) / 2;//分成左右序列_MergeSort(arr, left, mid, tmp);_MergeSort(arr, mid+1, right, tmp);//定义两个假有序数组int begin1 = left;int end1 = mid;int begin2 = mid + 1;int end2 = right;int index = begin1;//index表示第二个暂存数组的下标值while (begin1 <= end1 && begin2 <= end2) {if (arr[begin1] > arr[begin2]) {tmp[index++] = arr[begin2++];}else{tmp[index++] = arr[begin1++];}}while (begin1 <= end1) {tmp[index++] = arr[begin1++];}while (begin2 <= end2) {tmp[index++] = arr[begin2++];}//最后把暂存数组值放到原数组for (int i = left; i <= right; i++) {arr[i] = tmp[i];}
}
void MergeSort(int* arr, int n) {int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n - 1, tmp);free(tmp);
}
7>>总结
今天讲解了各种类型的排序算法,最常用的还是时间复杂度最小的堆排序、快排、归并排序,希望这篇文章对大家有用,如果有问题欢迎评论区一起探讨,谢谢宝子们的观看,期待与你下篇再见~~
相关文章:
数据结构初阶排序全解
目录 1>>排序前言 2>>插入排序 2.1>>直接插入排序 2.2>>希尔排序 3>>选择排序 3.1>>直接选择排序 3.2>>堆排序 4>>交换排序 4.1冒泡排序 4.2快速排序 5>>归并排序 6>>测试 test.c sort.h sort.c 7…...
MySQL的SQL语句之触发器的创建和应用
触发器 Trigger 一.触发器 作用:当检测到某种数据表发生数据变化时,自动执行操作,保证数据的完整性,保证数据的一致性。 1.创建一个触发器 如上图所示,查看这个create的帮助信息的时候,这个create trig…...
myWebserver 介绍
项目总结 项目准备过程中,主要阅读了《Linux 高性能服务器编程》游双 一书。源码参考的是:TinyWebServer,我在此源码的基础上做了一定的优化和修改。 我的代码:Github: myWebserver: 我的C服务器项目 我的 Webserver 项目总结&…...
钉钉平台开发小程序
一、下载小程序开发者工具 官网地址:小程序开发工具 - 钉钉开放平台 客户端类型 下载链接 MacOS x64 https://ur.alipay.com/volans-demo_MiniProgramStudio-x64.dmg MacOS arm64 https://ur.alipay.com/volans-demo_MiniProgramStudio-arm64.dmg Windows ht…...
九识智能与徐工汽车达成战略合作,共绘商用车未来新蓝图
近日,九识智能与徐工汽车签署战略合作协议,标志着双方在智能驾驶技术与新能源商用车融合应用、联合生产及市场推广等方面迈入深度合作的新篇章,将共同引领智能驾驶技术商业化浪潮。 近年来,在国家智能化发展战略的引领下ÿ…...
Serverless + AI 让应用开发更简单
本文整理自 2024 云栖大会,阿里云智能高级技术专家,史明伟演讲议题《Serverless AI 让应用开发更简单》 随着云计算和人工智能(AI)技术的飞速发展,企业对于高效、灵活且成本效益高的解决方案的需求日益增长。本文旨在…...
外包功能测试就干了4周,技术退步太明显了。。。。。
先说一下自己的情况,大专生,21年通过校招进入武汉某软件公司,干了差不多3个星期的功能测试,那年国庆,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我才在一个外包企业干了4周的功…...
外观模式及运用场景
外观模式(Facade Pattern)是一种结构性设计模式,它为复杂子系统提供一个统一的接口,从而简化与这些子系统的交互。通过外观模式,客户端可以更轻松地使用复杂系统,而不必了解其内部实现。接下来,…...
PyQt5实战——多脚本集合包,UI以及工程布局(二)
个人博客:苏三有春的博客 系列往期: PyQt5实战——多脚本集合包,前言与环境配置(一) 布局 2.1 UI页面布局 整体框架分为分为三个部分,垂直分布。 第一个部分为功能选择按钮(如UTF-8转换&#…...
Python 数据结构对比:列表与数组的选择指南
文章目录 💯前言💯Python中的列表(list)和数组(array)的详细对比1. 数据类型的灵活性2. 性能与效率3. 功能与操作4. 使用场景5. 数据结构选择的考量6. 实际应用案例7. 结论 💯小结 💯…...
gem5运行简单RISC-V全系统模拟
简单记录gem5中运行最简单的RISC-V Full System Simulation的过程 首先是编译RISC-V和m5term,这部分不多写了,官网均有对应教程。 之后直接使用官方在configs/example/gem5_library目录下的riscv-fs.py 运行如下命令 ./build/RISCV/gem5.opt configs/…...
洛谷 P1195 口袋的天空
自用。 题目传送门:口袋的天空 - 洛谷 题解:Inori_333 参考题解:题解 P1195 【口袋的天空】 - 洛谷专栏 /*P1195 口袋的天空https://www.luogu.com.cn/problem/P11952024/11/03 submit:inori333 */#include <iostream> #include &…...
ffmpeg视频滤镜:膨胀操作-dilation
滤镜介绍 dilation 官网链接 > FFmpeg Filters Documentation 膨胀滤镜会使图片变的更亮,会让细节别的更明显。膨胀也是形态学中的一种操作,在opencv中也有响应的算子。此外膨胀结合此前腐蚀操作,可以构成开闭操作。 开操作是先腐蚀…...
3.3 windows,ReactOS系统中页面的换出----2,结构体PHYSICAL_PAGE
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目…...
lvgl
lvgl 目录 lvgl Lvgl移植到STM32 -- 1、下载LVGL源码 -- 2、将必要文件复制到工程目录 -- 3、修改配置文件 将lvgl与底层屏幕结合到一块 -- lvgl也需要有定时器,专门给自己做了一个函数,告诉lvgl经过了多长时间(ms(毫秒)级别) 编写代码 lvgl的中文教程手册网站…...
【django】RESTful API 设计指南
目录 一、协议 二、域名 三、版本(Versioning) 四、路径(Endpoint) 五、HTTP动词 5.1 CRUD操作: 5.2 其他动词: 六、过滤信息(Filtering) 七、状态码(Status Co…...
提升大数据量分页查询性能:深分页优化全解
前言 在处理数据量逐渐增大的数据库表时,优化查询性能是一个常见的挑战。朋友们可能会建议说,创建索引不就能解决问题了吗?然而,当数据量达到相当规模时,简单的索引可能不足以应对所有情况。这时,可能会有…...
WPF 实现冒泡排序可视化
WPF 实现冒泡排序可视化 实现冒泡排序代码就不过多讲解,主要是实现动画效果思路,本demo使用MVVM模式编写,读者可自行参考部分核心代码,即可实现如视频所示效果。 对于新手了解算法相关知识应该有些许帮助,至于其它类型…...
Claude 3.5 新功能 支持对 100 页的PDF 图像、图表和图形进行可视化分析
Claude 3.5 Sonnet发布PDF图像预览新功能,允许用户分析长度不超过100页的PDF中的视觉内容。 此功能使用户能够轻松上传文档并提取信息,特别适用于包含图表、图形和其他视觉元素的研究论文和技术文档。 视觉PDF分析:用户现在可以从包含各种视觉…...
正式开源:从 Greenplum 到 Cloudberry 迁移工具 cbcopy 发布
Cloudberry Database 作为 Greenplum 衍生版本和首选开源替代,由 Greenplum 原始团队成员创建,与 Greenplum 保持原生兼容,并能实现无缝迁移,且具备更新的 PostgreSQL 内核和更丰富的功能。GitHub: https://github.com/cloudberry…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
