数据结构第六课 -----排序

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


排序

  • **作者前言**
  • 直接插入排序
  • 冒泡排序
  • 希尔排序
  • 直接选择排序
  • 堆排序
  • 快速排序
      • hoare版本
    • 优化点
      • 三数取中
    • 小区间优化
    • 挖坑法
    • 前后指针版本
  • 疑惑

直接插入排序

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

思路: 我们要记得[0,end]是有序的,我们要把tmp的值插入到[0,end]就要进行判断,直到tmp等于数组的长度结束,这个过程中我们要注意到我们把tmp插入到[0,end] 是要遍历[0,end]的当我们判断当前的元素大于tmp,就把这个元素往后移动,我们就要往后一个元素比较,直到碰见比tmp小的元素,并再该元素后面插入,如果碰见了在[0,end]都没有小于tmp的元素,我们就要在下标为0的地方插入,

void InsertSort(int* a, int n)
{//[0,end] int i = 0;for (i = 0; i < n-1; i++){int end = i;int tmp = a[end + 1];while (end >= 0){if (a[end] > tmp){//往后移动a[end + 1] = a[end];end--;}else{break;}}//这个写法一箭双雕,一来可以防止end为-1的情况不用去判断,二来可以插入到a[end + 1]a[end + 1] = tmp;}
}

冒泡排序

在这里插入图片描述

// 冒泡排序
void Bubblisort(int* a, int n)
{int i = 0; for (i = 0; i < n - 1; i++){//如果该数组是一个有序数组,只需遍历一遍下面的就可以了,时间复杂度为O(N)bool excheng = false;int j = 0;for (j = 0; j < n - 1 - i; j++){if (a[j] > a[j + 1]){int c = a[j];a[j] = a[j + 1];a[j + 1] = c;excheng = true;}}if (excheng == false)break;}
}

时间复杂度是O(N^2), 最好的情况就是O(N)

希尔排序

在这里插入图片描述

分成两步:
1.预排序 (接近有序)
2.直接插入排序
思路:
在这里插入图片描述
相同颜色的框进行插入排序,因为多少种颜色是有gap的数值决定的,每一种颜色对应的是整个数组的一部分

//预排序int gap = 3;int i = 0;//有gap个数组for (i = 0; i < gap; i++){//每个数组进行插入排序int sub = i;while (sub <= n - 1 - gap){int end = sub;int top = a[end + gap];while (end >= 0){if (top < a[end]){a[end + gap] = a[end];end -= gap;}elsebreak;}a[end + gap] = top;sub += gap;}}

上面这种是一组组进行插入排序.如果是多组进行插入排序

在这里插入图片描述
思路就是我们仍然采用上面的方法,但是我们是多组进行插入排序,仍然是相同颜色的进行插入排序

//预排序int gap = 3;int i = 0;//有gap个数组for (i = 0; i <= n - 1 - gap; i++){//每个数进行插入排序int end = i;int top = a[end + gap];while (end >= 0){if (top < a[end]){a[end + gap] = a[end];end -= gap;}elsebreak;}a[end + gap] = top;}

预排序的特点:
gap越大,大的值更快调到后面,小的值可以更快的调到前面,越不接近有序
gap越小,跳得越慢,但是越接近有序,如果gap == 1就是直接插入排序

最终代码为

//希尔排序
void ShellSort(int* a, int n)
{//预排序int gap = 3;int i = 0;//有gap个数组for (i = 0; i <= n - 1 - gap; i++){//每个数进行插入排序int end = i;int top = a[end + gap];while (end >= 0){if (top < a[end]){a[end + gap] = a[end];end -= gap;}elsebreak;}a[end + gap] = top;}//直接插入排序InsertSort(a, n);
}

但是我们可以简化一下
我们可以抓住gap=1为直接插入排序

//希尔排序
void ShellSort(int* a, int n)
{//预排序int gap = n;while (gap > 1){//一来gap等于1时,就是直接插入排序,二来就是gap是随n增大的,//再还有就是gap越小,就越接近有序gap = gap / 3 + 1;int i = 0;//有gap个数组for (i = 0; i <= n - 1 - gap; i++){//每个数进行插入排序int end = i;int top = a[end + gap];while (end >= 0){if (top < a[end]){a[end + gap] = a[end];end -= gap;}elsebreak;}a[end + gap] = top;}}}

在这里插入图片描述
时间复杂度O(N ^1.3),这个有点难算,我们只需要理解大概就行

直接选择排序

在这里插入图片描述
思路:从开头开始找,找到最小的,然后进行和开头交换,然后再从剩下的后面继续寻找最小的,依次往后插入
思路图1:这个思路是很多人能想出来的

在这里插入图片描述
思路图2:

在这里插入图片描述

​这里我是使用了两边,左边插入最小的,右边插入最大的,插入好后,begin往前 ,end往后,直到begin等于end,就停止了

void excheng(int* a, int* b)
{int c = *a;*a = *b;*b = c;
}
//直接选择排序
void SelectSrot(int* a, int n)
{int min = 0, max = 0; //找出最大和最小int begin = 0, end = n - 1;// 在最大和最小的位置插入for (int i = begin + 1; i <= end; i++){int idx = i;while (idx <= end){//找出最小的值if (a[min] > a[idx])min = idx;//找到最大值if (a[max] < a[idx])max = idx;idx++;}excheng(&a[begin], &a[min]);//防止开头就是最大值,一旦最小值交换,就乱了if (max == begin)max = min;excheng(&a[end], &a[max]);begin++;end--;}
}

时间复杂度是 O(N^2)

堆排序

大家可以观看这部博客
堆排序
在这里插入图片描述

//堆排序
typedef int Heapdata;
void exchange(Heapdata* a, Heapdata* b)
{Heapdata e = *a;*a = *b;*b = e;
}
void Heapsort(Heapdata* heap, int size)
{//建大堆int i = 0;for (i = 1; i < size; i++){//向上调整int child = i;int parent = (child - 1) / 2;while (child > 0){if (heap[child] > heap[parent]){//交换exchange(&heap[child], &heap[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}}//开始升序排序while (size > 0){// 根节点和最后一个叶节点交换exchange(&heap[0], &heap[--size]);//向下调整int parent = 0;int child = parent * 2 + 1;while (child < size){if (child + 1 < size && heap[child] < heap[child + 1]){child += 1;}if (heap[child] > heap[parent])exchange(&heap[child], &heap[parent]);elsebreak;parent = child;child = parent * 2 + 1;}}}

快速排序

hoare版本

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止
在这里插入图片描述
这个图可能有点简陋
在这里插入图片描述
在这里插入图片描述
时间复杂度:每一次都会把当前数组的每个元素遍历一遍,然后再把key交换, 需要进行log(n)次递归
时间复杂度是:O(n*log(n))
在这里插入图片描述
复杂的话,就如同这个一样,这种情况就是有n层, 时间复杂度就是 1+2+3+…+n, 所以时间复杂度就是O(n^2)

//快速排序
void QuickSrot(int* a, int begin, int end)
{//当只有一个元素就不用进行了if (begin >= end)return;int key = begin;int left = begin;//这里不能begin加1 否则在遇到有序的时候就会排序出错int right = end;while (left < right){// 找最小while (left < right){if (a[right] < a[key]){break;}right--;}// 找最大while (left < right){if (a[left] > a[key]){break;}left++;}excheng(&a[right], &a[left]);}excheng(&a[right], &a[key]);//左QuickSrot(a, begin, right - 1);// 右QuickSrot(a, right + 1, end);
}

优化点

三数取中

思路:
我们可以在数组的前后和中间选取中位数,然后把中位数和开头进行交换,

int TriNum(int *a,int begin, int end)
{int mid = (begin - end) / 2 + end;if (begin > end){if (end > mid){return end;}else if(begin < mid){return begin;}return mid;}else{if (begin > mid){return begin;}else if (end < mid){return end;}elsereturn mid;}
}
//快速排序
void QuickSrot(int* a, int begin, int end)
{//当只有一个元素就不用进行了if (begin >= end)return;//三数取中int key = 0;key = TriNum(a, begin, end);exchange(&a[begin], &a[key]);key = begin;int left = begin;int right = end;//普通方法//int key = begin;//int left = begin;//这里不能begin加1 否则在遇到有序的时候就会排序出错//int right = end;while (left < right){// 找最小while (left < right){if (a[right] < a[key]){break;}right--;}// 找最大while (left < right){if (a[left] > a[key]){break;}left++;}excheng(&a[right], &a[left]);}excheng(&a[right], &a[key]);//左QuickSrot(a, begin, right - 1);// 右QuickSrot(a, right + 1, end);
}

小区间优化

当我们在使用快速排序的时候,一直排序知道递归到还剩下该数组的10%的数没有排序,我们如果使用递归就很对栈的空间浪费很大。那我们可以选择使用插入排序,

//快速排序
void QuickSrot(int* a, int begin, int end)
{//当只有一个元素就不用进行了if (begin >= end)return;if (end - begin  + 1 <= 10){//插入排序InsertSort(a + begin, end - begin + 1);//我们要清楚要从哪里开始插入排序}else{//三数取中int key = 0;key = TriNum(a, begin, end);excheng(&a[begin], &a[key]);key = begin;int left = begin;int right = end;//普通方法,有可能会栈溢出//int key = begin;//int left = begin;//这里不能begin加1 否则在遇到有序的时候就会排序出错//int right = end;while (left < right){// 找最小while (left < right){if (a[right] < a[key]){break;}right--;}// 找最大while (left < right){if (a[left] > a[key]){break;}left++;}excheng(&a[right], &a[left]);}excheng(&a[right], &a[key]);//左QuickSrot(a, begin, right - 1);// 右QuickSrot(a, right + 1, end);}}

挖坑法

在这里插入图片描述

//挖坑法
void QuickSrot2(int* a, int begin, int end)
{if (begin >= end)return;if (end - begin + 1 <= 10){InsertSort(a + begin, end - begin + 1);}else{//三数取中int key = TriNum(a, begin, end);excheng(&a[key], &a[begin]);//坑key = begin;int num = a[key];int left = begin;int right = end;while (left < right){//找小while (left < right){if (a[right] < num){a[key] = a[right];key = right;break;}right--;}//找大while (left < right){if (a[left] > num){a[key] = a[left];key = left;break;}left++;}}a[key] = num;//左QuickSrot(a, begin, right - 1);// 右QuickSrot(a, right + 1, end);}}

前后指针版本

在这里插入图片描述
思路:
cur遇见比key大的值,cur++
cur遇见比key小的值,prev++,交换prev和cur的值交换,然后cur++
在这里插入图片描述

//前后指针版本
// 快速排序版本3
void QuickSrot3(int* a, int begin, int end)
{if (begin >= end)return;int key = TriNum(a, begin, end);excheng(&a[key], &a[begin]);key = begin;int prev = begin;int cur = begin + 1;while (cur <= end){//cur 比较if (a[cur] < a[key] && ++prev != cur)//增加++prev != cur可以有效解决相同位置进行交换{exchange(&a[cur], &a[prev]);}cur++;}exchange(&a[key], &a[prev]);//左QuickSrot(a, begin, prev - 1);// 右QuickSrot(a, prev + 1, end);
}

疑惑

在这里插入图片描述

  1. 为什么相遇位置比key小
    原因:是right先走
    两种情况:
    (1).R遇见L —>(L和R交换后,R先走)R没有找到比key小的,一直走,直到R遇见L,(特殊情况除外)
    (2)L遇见R----->(R找到小了),然后L没有找到比key大的,一直走,直到L遇见R,(特殊情况除外)

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

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

相关文章

【Canvas】记录一次从0到1绘制风场空间分布图的过程

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热衷分享有趣实用的文章&#xff0c;希望大家多多支持&#xff0c;一起进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 背景 前置知识 风场数据 绘制风场 准备工作 生成二维网格 获取…

【BI】FineBI功能学习路径-20231211

FineBI功能学习路径 https://help.fanruan.com/finebi/doc-view-1757.html 编辑数据概述 1.1 调整数据结构 1.2 简化数据 2.1上下合并 2.2其他表添加列 2.3左右合并 新增分析指标 函数参考 https://help.fanruan.com/finereport/doc-view-1897.html 数值函数 日期函数 文…

【unity小技巧】FPS游戏后坐力制作思路

参考原视频链接 &#xff1a;https://www.bilibili.com/video/BV1j44y1S7fX/ 注意&#xff1a;本文为学习笔记记录&#xff0c;推荐支持原作者&#xff0c;去看原视频自己手敲代码理解更加深入 免责声明&#xff1a;向宇的博客免责声明 文章目录 前言不加后座力效果简单添加后座…

如何在Cloudflare创建自己的反向代理

大家在使用Cloudflare做反向代理的时候会遇到一个问题&#xff0c;命名已经配置好了&#xff0c;但是还是访问不了&#xff0c;是因为Cloudflare的workers.dev域名在中国大陆区域已经被污染无法访问&#xff0c;所以需要自有域名进行解析。 本文的主要内容有以下三部分 1、域…

Linux系统编程:高级IO总结

非阻塞IO基本概念 高级IO核心就一个概念&#xff1a;非阻塞IO。 与该概念相对的&#xff0c;就是我们之前学习过的阻塞IO。 非阻塞IO&#xff08;Non-blocking I/O&#xff09;是一种IO模型&#xff0c;用于实现异步IO操作&#xff0c;使应用程序能够在等待IO操作完成的同时…

洛谷 P8802 [蓝桥杯 2022 国 B] 出差

文章目录 [蓝桥杯 2022 国 B] 出差题目链接题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 思路解析CODE [蓝桥杯 2022 国 B] 出差 题目链接 https://www.luogu.com.cn/problem/P8802 题目描述 A \mathrm{A} A 国有 N N N 个城市&#xff0c;编号为 1 … N …

数据库范式(详细介绍)

目录 第一范式&#xff08;原子性&#xff09; 第二范式&#xff08;主键唯一性&#xff09; 第三范式&#xff08;原子性主键唯一性&#xff09; BC范式(3NFplus) 第一范式&#xff08;原子性&#xff09; 确保每列保证原子性&#xff0c;保证这个属性&#xff08;字段&am…

SpringBoot AOP切面实现对自定义注解的属性动态修改

文章目录 需求问题解决方案示例代码 需求 项目中共用了一个redis&#xff0c;而项目中部分代码使用了JetCache的Cached注解。所以需要给Cached动态配置area属性值&#xff0c;用来区分dev和test环境。 问题 自定义注解的属性值需要常量值&#xff0c;即static final修饰&…

学习-面试java基础-(集合)

String 为什么不可变&#xff1f; 1线程安全 2支持hash映射和缓存。因为String的hash值经常会使用到&#xff0c;比如作为 Map 的键&#xff0c;不可变的特性使得 hash 值也不会变&#xff0c;不需要重新计算。 3出于安全考虑。网络地址URL、文件路径path、密码通常情况下都是以…

Python之Requests库使用总结

概述 Requests是python中一个很Pythonic的HTTP库&#xff0c;用于构建HTTP请求与解析响应 Requests开发哲学 Beautiful is better than ugly.(美丽优于丑陋) Explicit is better than implicit.(直白优于含蓄) Simple is better than complex.(简单优于复杂) Complex is bett…

回顾【数学基础】找出断层,继续前进, 使用chatGPT学习并解决实际问题:微积分

已经学过的算术、代数、几何。跳过。 从微积分开始 想象一下&#xff0c;你在画一条曲线&#xff0c;或者在一个大草地上奔跑。微积分就是一种数学工具&#xff0c;帮助我们了解这条曲线的形状&#xff0c;或者你奔跑的方式。 微分&#xff08;就像研究曲线上的每一小点&…

FFmpeg的AVIOPROBE

文章目录 定义 可能你一直有疑问&#xff0c;ffmpeg的avformat是怎么提前知道码流是编码格式或者容器&#xff1f;恭喜你&#xff0c;看到这里&#xff0c;你找到答案了&#xff0c;在这里&#xff0c;ffmpeg通过这些probe函数来提前获取码流的编码格式。 看到下面的avs2_prob…

C++1114新标准——统一初始化(Uniform Initialization)、Initializer_list(初始化列表)

系列文章目录 C11&14新标准——Variadic templates&#xff08;数量不定的模板参数&#xff09; C11&14新标准——Uniform Initialization&#xff08;统一初始化&#xff09;、Initializer_list&#xff08;初始化列表&#xff09; 文章目录 系列文章目录1. 定义2. I…

装饰者模式(Decorator Pattern)

1 什么是装饰者模式&#xff1f; 1.1 Head First Design Pattern 定义 装饰者模式动态地将责任附加到对象上。若要扩展功能&#xff0c;装饰者提供了比继承更有弹性的替代方案。 1.2 大佬博客 设计模式是什么鬼&#xff08;装饰&#xff09; 2 装饰者模式 2.1 基本介绍 …

Goby 漏洞发布| 亿赛通电子文档安全管理系统 LinkFilterService 接口权限绕过漏洞

漏洞名称&#xff1a;亿赛通电子文档安全管理系统 LinkFilterService 接口权限绕过漏洞 English Name&#xff1a;Esafenet Electronic Document Security Management System LinkFilterService API Permission Bypass Vulnerability CVSS core: 9.3 影响资产数&#xff1a;…

MySQL BinLog 数据还原恢复

博文目录 文章目录 查看状态查看 binlog 开关及存储路径查看 binlog 配置 如 存储格式 binlog_format查看当前还存在的日志查看当前正在使用的日志 切换日志确定日志确定日志文件日志格式改写日志简要说明确定日志位置以事件为单位查看日志分析日志 还原数据 查看状态 查看 b…

智能优化算法应用:基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.花授粉算法4.实验参数设定5.算法结果6.参考文…

设计模式(2)--对象创建(1)--抽象工厂

1. 意图 提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。 2. 四种角色 抽象产品(Product)、具体产品(Concrete Product)、抽象工厂(Abstract Factory)、具体工厂(Concrete Factory)。 3. 优点 3.1 分离了具体的类。Client只需使用抽象工厂类…

解析代理IP在跨境电商和社媒营销中的关键作用

跨境电商和社媒营销领域的从业者深知&#xff0c;代理IP的价值愈发凸显。在推广营销的过程中&#xff0c;频繁遇到因IP关联而封禁账号的情况&#xff0c;或因使用不安全IP而导致异常问题。 这些问题促使人们开始高度重视代理IP的作用。但实际上&#xff0c;代理IP究竟是何物&a…

(数据结构)单链表的定义

#include<stdio.h> typedef struct LNode {int data;struct LNode* next; }LNode,*LinkList; //LNode为结构体类型&#xff0c;LinkList为指向单链表的指针 //初始化一个空的单链表 void InitList(LinkList L) {L NULL; //空表&#xff0c;暂时没有任何节点 } //判断单…