当前位置: 首页 > news >正文

排序《数据结构》

排序 《数据结构》

  • 1.排序的概念及其运用
    • 1.1 排序的概念
    • 1.2 排序运用
    • 1.3常见的排序算法
    • 1.4 排序动图演示
  • 2.常见排序算法的实现
    • 2.1 插入排序
    • 2.2希尔排序
    • 2.3 快排
      • 左边做keyi,右边先走,可以保证相遇位置比keyi小
    • 2.4 快速排序优化
      • 快排(非递归)
    • 2.6堆排序
    • 2.7 归并排序

1.排序的概念及其运用

1.1 排序的概念

1、排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
2、稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
3、 内部排序:数据元素全部放在内存中的排序。
4、外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不断地在内外存之间移动数据的排序。

1.2 排序运用

在这里插入图片描述

在这里插入图片描述

1.3常见的排序算法

在这里插入图片描述

1.4 排序动图演示

插入排序

void InsertSort(int* a,int n)//n为数组大小

在这里插入图片描述

希尔排序

void ShellSort(int* a,int n)//n为数组大小

在这里插入图片描述

选择排序

void SelectSort(int*a, int n);//n为数组大小

在这里插入图片描述

堆排序

voidAdjustDwon(int*a, int n, int parent);//向下调整
{
// 先假设左孩子小
int child = parent * 2 + 1;while (child < n)  // child >= n说明孩子不存在,调整到叶子了
{// 找出小的那个孩子if (child + 1 < n && a[child + 1] < a[child]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}
}
}
voidHeapSort(int*a, int n);

在这里插入图片描述

快排

void QuickSort(int* a,int n);

在这里插入图片描述

2.常见排序算法的实现

2.1 插入排序

基本思想:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,
直到所有的记录插入完为止,得到一个新的有序序列。

根据以上文字:
我们可以用(玩扑克牌来实例化)

在这里插入图片描述

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

插入排序特性总结:
1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1),它是一种稳定的排序算法
4. 稳定性:稳定

插入排序的实现

void InsertSort(int* a,int n)
{
for(int 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--;}elsebreak;//以防tmp是数组中最小的数}
a[end+1]=tmp;}}

2.2希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

在这里插入图片描述

希尔排序的特性总结:1. 希尔排序是对直接插入排序的优化。2. 当gap > 1时都是预排序,目的是让数组更接近于有序。 当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3.  希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定:大概是n^(1.3)

在这里插入图片描述

4. 稳定性:不稳定
void ShellSort(int* a,int n)
{
while(gap>1){// +1保证最后一个gap一定是1// gap > 1时是预排序// gap == 1时是插入排序int gap=(3/n)+1;//第一趟for(int i=0;i<n-gap;i++){int end=i;int tmp=a[end+1];while(end>=0){if(a[end]>tmp){a[end+1]=a[end];end-=gap;}elsebreak;}a[end+1]=tmp;}}}

2.3 快排

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

特点总结:

快速排序的特性总结:
快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
时间复杂度:O(N*logN)
空间复杂度:O(logN)
稳定性:不稳定

1、hoare版本
void QuickSort(int*a,int left,int right)
{if(right<=left){return ;}int begin=lef;int keyi=left;int end=right;while(begin<end){while(begin<end&&a[keyi]<=a[begin]){begin++;}while(begin<end&&a[keyi]>=a[end]){end--;}Swap(&a[begin],&a[end]);//交换
}
Swap(&a[begin],a[keyi]);
keyi=begin;
QuickSort(a,left,keyi-1);
QuickSort(a,keyi+1,right);
}

左边做keyi,右边先走,可以保证相遇位置比keyi小

相遇场景分析:
L遇R: R先走,停下来,那么R停下的条件是比keyi小的位置,
L没找到大的,遇到R停下来了

在这里插入图片描述

 R遇L:

在这里插入图片描述

那么我们可以得出:keyi在左边,R先走,keyi在右边,L先走

2、挖坑法

在这里插入图片描述
3、双指针表达法
在这里插入图片描述

代码实现:

int partSort1(int* a, int left, int right)//双指针排序法
{int prve = left;int cur = prve + 1;int keyi = left;while (cur <= right){if (a[keyi] < a[cur] && ++prve != cur){Swap(&a[prve], &a[cur]);cur++;}cur++;}Swap(&a[prve], &a[keyi]);return prve;
}
void QuickSort(int* a, int left, int right)
{if (left >= right){return;}if ((right - left + 1) < 10){insertSort(a + left, right - left + 1);}else{int keyi = partSort1(a, left, right);QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);}
}

2.4 快速排序优化

  1. 三数取中法选key
int order(int* a, int left, int right)
{int midi = (left + right) / 2;if (a[left] > a[midi]){if (a[midi] > a[right]){return midi;}else if (a[left] > a[right]){return right;}else{return left;}}else if(a[midi]<a[right]){return midi;}else{if (a[left] < a[right]){return right;}elsereturn left;}}
  1. 递归到小的子区间时,可以考虑使用插入排序
void insertSort(int* a, int n)
{for (int 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;}}a[end + 1] = tmp;}
}void QuickSort(int* a, int left, int right)
{if (left >= right){return;}if ((right - left+1) < 10)//小区间优化{insertSort(a+left, right - left + 1);}else{int midi = order(a, left, right);Swap(&a[midi], &a[left]);int keyi = left;int begin = left, end = right;while (begin < end){while (begin < end && a[end] >= a[keyi]){--end;}while (begin < end && a[begin] <= a[keyi]){++begin;}Swap(&a[begin], &a[end]);}Swap(&a[begin], &a[keyi]);keyi = begin;QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);}
}

快排(非递归)

用栈来代替递归

 先把区间left和right入栈,然后分隔区间,在令分隔的右区间先入栈,左区间后入栈(因为栈后进先出的原则),那么弹出来的就是左区间下标,在对坐下标进行处理,每一次出栈都代表着区间排序,
等栈为空时,那么排序就完成了
void QuickSortNonR(int* a, int left, int right)
{
ST st;
STInit(&st);
STPush(&st, right);//进栈
STPush(&st, left);//进栈
while()
left = STTop(&st);
STPop(&st);
right= STTop(&st);
STPop(&st);
int begin = left;
int end = right;
int keyi = begin;
while (begin < end)//交换
{while (begin < end && a[end] >= a[keyi]){end--;}while (begin < end && a[begin] <= a[keyi]){begin++;}Swap(&a[begin],&a[end]);
}
Swap(&a[keyi], &a[begin]);keyi = begin;
// [left, keyi-1] keyi [keyi+1, right]
if (keyi + 1 < right ){STPush(&st, right);//右区间的右下标(入栈)STPush(&st, keyi + 1);//右区间的左下标(入栈)}if (left < keyi - 1){STPush(&st, keyi - 1);//左区间的右下标(入栈)STPush(&st, left);//左区间的坐下标(入栈)}}STDestroy(&st);
}

2.6堆排序

直接选择排序的特性总结:
堆排序使用堆来选数,效率就高了很多。
时间复杂度:O(N*logN)
空间复杂度:O(1)
稳定性:不稳定

实现代码:

void headsport(int* arr, int n)
{//时间复杂度O(N)for (int i = (n-1-1)/2;i >=0;i--){AdjustDown(arr,n,i);//向下调整建堆}int end = n - 1;//取最后一位数据while (end > 0)
{Swap(&arr[0], &arr[end]);//交换AdjustDown(arr, end, 0);//在向下建堆end--;}
}

2.7 归并排序

基本思想
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and
Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有
序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:

在这里插入图片描述

特性总结:

 1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。2. 时间复杂度:O(N*logN)3.  空间复杂度:O(N)4.  稳定性:稳定

代码实现:

void _mergeSort(int* a, int* tmp ,int begin, int end)
{if (end-begin<1){return;}int mid = (begin + end) / 2;//如果[begin,mid-1],[mid,end]有序就归并_mergeSort(a, tmp, begin, mid);_mergeSort(a, tmp, mid+1, end);//归并int begin1 = begin;int begin2 = mid+1;int end1 = mid;int end2 = end;int i = begin;while (begin1<=end1&&begin2<=end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}elsetmp[i++] = a[begin2++];}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a+begin, tmp+begin,(end-begin+1)*sizeof(int));
}void mergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}_mergeSort(a, tmp, 0, n - 1);
}

排序部分结束啦!!!感谢大家观看

相关文章:

排序《数据结构》

排序 《数据结构》 1.排序的概念及其运用1.1 排序的概念1.2 排序运用1.3常见的排序算法1.4 排序动图演示 2.常见排序算法的实现2.1 插入排序2.2希尔排序2.3 快排左边做keyi&#xff0c;右边先走&#xff0c;可以保证相遇位置比keyi小 2.4 快速排序优化快排&#xff08;非递归&a…...

flutter 提示框2 Dialog

flutter 提示框 写在点击的方法体中 child里放自己喜欢的 showDialog( context: context, builder: (BuildContext context) { final Dialog alertDialog Dialog( backgroundColor: Colors.transparent,shadowColor:Colors.transparent,child: Container(height: mediawi…...

如何选择SDR无线图传方案

在开源软件定义无线电&#xff08;SDR&#xff09;领域&#xff0c;有几个项目提供了无线图传的解决方案。以下是一些开源SDR无线图传方案&#xff1a; 1. **OpenHD**&#xff1a;这是一个远程高清数字图像传输的开源解决方案&#xff0c;它使用SDR技术来实现高清视频的无线传…...

关于Python类中方法__init__()解析

# import numpy as npclass Car():def __init__(self, maker, name, year):self.maker makerself.name nameself.year yearprint(self.searchMakrt() "123")def searchMakrt(self):print("汽车制作厂家为&#xff1a; " self.maker)# passreturn &quo…...

微信小程序 自定义组件

1. 微信小程序 自定义组件 微信小程序支持组件化开发&#xff0c;这有助于我们复用代码&#xff0c;提高开发效率。下面我将给出一个简单的微信小程序组件化示例&#xff0c;包括一个自定义组件的创建和使用。 1.1. 创建自定义组件 首先&#xff0c;在项目的 components 目录…...

Mac+Pycharm配置PyQt6教程

安装包 pip install PyQt6 PyQt6-tools #查看Qt版本 pip show PyQt6 pip show pyqt6-tools 配置扩展工具 QTD(界面设计) Program&#xff1a;/Users/wan/PycharmProjects/NewDemo/venv/lib/python3.11/site-packages/qt6_applications/Qt/bin/Designer.app Working directo…...

如何保证Redis与Mysql双写一致性?

https://www.cnblogs.com/coderacademy/p/18137480 延迟双删 对于上面链接的文章&#xff0c;里面的延迟双删没有给出具体的例子&#xff0c;也没有直接指出具体解决的问题是针对那种缓存策略&#xff0c;这里补充一下&#xff0c;延时双删缓存针对的是Cache aside pattern(缓…...

9.8笔试记录

1.在c中哪些运算符不能重载? 在 C 中&#xff0c;有以下几个运算符不能被重载&#xff1a; . &#xff1a;成员访问运算符。例如obj.member中的.不能被重载。 :: &#xff1a;作用域解析运算符。用于指定命名空间、类等的作用域&#xff0c;不能被重载。 ?: &#xff1…...

SRE-系统管理篇

SRE-系统管理篇 进程管理 进程的概念: 运行起来的程序,命令,服务等等都可以称作进行,进程都是运行在内存当中的。 程序的概念: 一般指安装包,程序代码,应用它们存放在磁盘上面的。 守护进程的概念: 守护进程,一直运行的进程,也可以叫做服务。 进程的分类 僵…...

傅里叶级数,傅里叶变换

先读文章&#xff1a;傅里叶分析之掐死教程&#xff08;完整版&#xff09;更新于2014.06.06 - 知乎 (zhihu.com) 傅里叶级数 一、内容&#xff1a;每个周期性函数都可以表示为无穷多个不同频率的正弦函数的叠加。 二、公式&#xff1a; 三、从时域到频域所保留的三点信息&…...

零知识证明在BSV网络上的应用

​​发表时间&#xff1a;2023年6月15日 2024年7月19日&#xff0c;BSV区块链主网上成功通过使用零知识证明验证了一笔交易。 零知识证明是一种技术&#xff0c;它允许一方&#xff08;证明者&#xff09;在不透露任何秘密的情况下&#xff0c;向另一方&#xff08;验证者&…...

无任何门槛!3分钟5步,发布属于你的第一个智能体小程序,99%的人还不知道怎么用

相信大家都用微信小程序&#xff0c;但是大部分人应该还没有过属于自己的小程序吧。 今天程哥就带大家花三分钟用五步&#xff0c;来创建一个属于自己的微信小程序。 之前Coze在发布渠道里也有发布小程序的渠道&#xff0c;但是试过的人都知道&#xff0c;这个是有一定门槛的…...

怎么强制撤销excel工作表保护?

经常不是用的Excel文件设置了工作表保护&#xff0c;偶尔打开文件的时候想要编辑文件&#xff0c;但是发现忘记了密码&#xff0c;那么这种情况&#xff0c;我们怎么强制撤销excel工作表保护&#xff1f;今天分享两种解决方法。 方法一、 将excel文件转换为其他文件格式&…...

每天学习一个字符串类函数之memmove函数

目录 前言&#xff1a; 一、头文件 二、memmove函数的作用 三、理解memmove函数的定义 1、返回类型 2、参数 四、使用memmove函数 案例1&#xff1a; 案例2&#xff1a; 五、解决数据拷贝之前被覆盖的方法 六、模拟实现memmove函数 前言&#xff1a; 上一篇博客&#xff0c;我…...

【机器人工具箱Robotics Toolbox开发笔记(十三)】三自由度机器人圆弧轨迹规划仿真实例

在实际应用场景中,我们通常预先明确了目标末端的运动轨迹,随后引导机器人进行相应的动作。本实例具体展示了如何基于给定的两个点,计算出末端的精确位姿,并以此为基础,进一步规划出一条平滑的圆弧轨迹供机器人执行。这样的流程确保了机器人能够沿着预定的路径,精准且高效…...

软件工程-图书管理系统的概要设计

软件概要设计说明书 目录 软件概要设计说明书 一、引言 1.1 编写目的 1.2 背景 1.3 定义 1.3.1特定对象 1.3.2专业术语 1.4 参考资料 二、总体设计 2.1 需求规定 2.1.1信息要求 2.1.2功能要求 2.2 运行环境 2.3 基本概要设计和处理流程 2.4 体系结构设计 2.5 模…...

springboot 整合swagger

没有多余废话&#xff0c;就是干 spring-boot 2.7.8 springfox-boot-starter 3.0.0 结构 POM.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/…...

Flutter 进阶:绘制加载动画

绘制加载动画&#xff1a;由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类&#xff1a;LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态&#xff0c;而 Load…...

【深度学习】梯度下降法

梯度就是导数&#xff0c;而梯度下降法就是一种通过求目标函数的导数来寻找目标函数最小化的方法。梯度下降目的是找到目标函数最小化时的取值所对应的自变量的值&#xff0c;目的是为了找自变量X。 最优化问题在机器学习中有非常重要的地位&#xff0c;很多机器学习算法最后都…...

基于机器学习的电商优惠券核销预测

1. 项目简介 随着移动互联网的快速发展&#xff0c;O2O&#xff08;Online to Offline&#xff09;模式已成为电商领域的一大亮点。优惠券作为一种有效的营销工具&#xff0c;被广泛应用于吸引新客户和激活老用户。然而&#xff0c;传统的随机投放方式往往效率低下&#xff0c;…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...