7种常见排序

1 直接插入排序

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


void InsertSort(int* a, int n)
{for (int i = 0; i < n - 1; ++i){//划分区间【0,end】int end = i;//保存需要插入的值int temp = a[end + 1];while (end >= 0){if (a[end] > temp) //这是temp,不是a[end+1]{a[end + 1] = a[end];end--;}else{break;}}a[end+1] = temp;}
}

直接插入排序的特性总结

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

2 希尔排序

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

其实就是是直接插入排序的优化,用分组的思想将数据进行预排序,将无序序列变得基本有序,最后使用直接插入排序。

 这里gap最好为N/3+1,这样对于普遍数据排序效率相对更高,更优。


void ShellSort(int* a, int n)
{//gap大于一为预排序,让数字接近有序int gap=n;while (gap > 1){gap = gap / 3 + 1; //保证最后一次一定是1//gap等于1相当于插入排序for (int i = 0; i < n - gap; i++){int end = i;int temp = a[end + gap];while (end >= 0){if (a[end] > temp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = temp;}printArray(a, n);}
}

希尔排序的特性总结:
1. 希尔排序是对直接插入排序的优化。


2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。


3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的
希尔排序的时间复杂度都不固定:

《数据结构(C语言版)》--- 严蔚敏

《数据结构-用面相对象方法与C++描述》--- 殷人昆

因为我们的gap是按照Knuth提出的方式取值的,而且Knuth进行了大量的试验统计,我们暂时就按照:O(N^1.25)~O(1.6*N^1.25)来算。

4. 稳定性:不稳定

3 选择排序

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

但是这是可以优化的,我们可以每次找出最大和最小的,将最大的放最后,最小的放最前面,就能完成升序,效率会快一半。


void SelectSort(int* a, int n)
{int begin = 0;int end = n - 1;while (begin < end){int max = a[begin];int min = a[begin];for (int i = begin; i <= end; i++){if (a[i] > a[max]){max = i;}if (a[i] < a[min]){min = i;}}Swap(&a[min], &a[begin]);if (max == begin){max = min;}Swap(&a[max], &a[end]);end--;begin++;}
}

 4 堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。


//堆排序//向下调整
void AjustDown(int*a,int n,int root)
{int parent = root;int child = parent * 2 + 1;while (child<n){if (child + 1 < n && a[child + 1] > a[child]){child++;}if (a[parent] < a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void HeapSort(int* a, int n)
{int parent = (n - 1 - 1) / 2;
//建堆for (int i = parent; i >= 0; i--){AjustDown(a, n, i);}printArray(a, n);int end = n-1;
//将堆顶放最后while (end > 0){Swap(&a[0], &a[end]);AjustDown(a, end, 0);end--;}}

 直接选择排序的特性总结:
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定
 

 5 冒泡排序

将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

void BubbleSort(int* a, int n)
{int end = n-1;while (end > 0){int overCase = 0;for (int i = 0; i < end; i++){if (a[i] > a[i + 1]){Swap(&a[i], &a[i + 1]);overCase = 1;}}if (overCase == 0){break;}end--;}}

冒泡排序的特性总结:
1. 冒泡排序是一种非常容易理解的排序
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定 

6 快排

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

// 假设按照升序对array数组中[left, right)区间中的元素进行排序
void QuickSort(int array[], int left, int right)
{
if(right - left <= 1)
return;
// 按照基准值对array数组的 [left, right)区间中的元素进行划分
int div = partion(array, left, right);
// 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
// 递归排[left, div)
QuickSort(array, left, div);
// 递归排[div+1, right)
QuickSort(array, div+1, right);
}

 上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像,同学们在写递归框架时可想想二叉树前序遍历规则即可快速写出来,后序只需分析如何按照基准值来对区间中数据进行划分的方式即可。将区间按照基准值划分为左右两半部分的常见方式有

1.左右指针

确定一个基准值,一般选取数组最后一个元素小标为key,然后L先从前往后遍历找到大于key的数,再R从后往前遍历找到小于key的数,然后交换L与R的数组元素,直到L与R指向同一个空间,此时再把key 与L或者R指向的元素交换,这只是其中一趟排序。

 

此时整个数组就被L和R指针所指向的空间分成了左右两块,左边的都小于8,右边都大于8。

//左右指针法
int PartSort1(int* a, int begin,int end)
{/*int midIndex=GetMidIndex(a,begin,end);Swap(&a[midIndex], &a[end]);*/int key = end;while (begin < end){//找大while (begin < end&&a[begin] <= a[key]){begin++;}//找小while (begin < end&&a[end] >= a[key]){end--;}Swap(&a[end], &a[begin]);}Swap(&a[key], &a[begin]);return begin;
}

2.挖坑法

这样就以5为中间值,左边都小于5,右边都大于5。

//挖坑法 
int PartSort3(int* a, int begin, int end)
{int mid = GetMidIndex(a, begin, end);Swap(&a[mid], &a[end]);int key = a[end];while (begin < end){while(begin < end && a[begin] <= key){begin++;}a[end] = a[begin];while (begin<end&&a[end] >= key){end--;}a[begin] = a[end];}a[begin] = key;return begin;
}

3.前后指针

这时就分出左边都小于5,右边都大于5。


//前后指针法
int PartSort2(int* a, int begin, int end)
{int prev = begin-1;int cur = begin;int keyIndex = end;while (cur < end){if (a[cur] <a[keyIndex]&&++prev!=cur)Swap(&a[prev], &a[cur]);cur++;}prev++;Swap(&a[prev], &a[keyIndex]);return prev;
}

4.快排代码

//找到中间大的数,优化处理
int GetMidIndex(int* a, int begin, int end)
{int mid = (begin + end) / 2;if (a[mid] < a[begin]){if (a[mid] > a[end]){return mid;}else if (a[a[begin] < a[end]]){return begin;}else{return end;}}else{if (a[mid] < a[end]){return mid;}else{return end;}}
}
//左右指针法
int PartSort1(int* a, int begin,int end)
{/*int midIndex=GetMidIndex(a,begin,end);Swap(&a[midIndex], &a[end]);*/int key = end;while (begin < end){//找大while (begin < end&&a[begin] <= a[key]){begin++;}//找小while (begin < end&&a[end] >= a[key]){end--;}Swap(&a[end], &a[begin]);}Swap(&a[key], &a[begin]);return begin;
}//前后指针法
int PartSort2(int* a, int begin, int end)
{int prev = begin-1;int cur = begin;int keyIndex = end;while (cur < end){if (a[cur] <a[keyIndex]&&++prev!=cur)Swap(&a[prev], &a[cur]);cur++;}prev++;Swap(&a[prev], &a[keyIndex]);return prev;
}//挖坑法 
int PartSort3(int* a, int begin, int end)
{int mid = GetMidIndex(a, begin, end);Swap(&a[mid], &a[end]);int key = a[end];while (begin < end){while(begin < end && a[begin] <= key){begin++;}a[end] = a[begin];while (begin<end&&a[end] >= key){end--;}a[begin] = a[end];}a[begin] = key;return begin;
}void QuickSort(int* a, int left,int right)
{if (left >= right) return;int div = PartSort1(a, left, right);QuickSort(a,left, div - 1);QuickSort(a,div+1,right);
}

5.快排优化

5.1 三数取中法选key

int GetMidIndex(int* a, int begin, int end)
{int mid = (begin + end) / 2;if (a[mid] < a[begin]){if (a[mid] > a[end]){return mid;}else if (a[a[begin] < a[end]]){return begin;}else{return end;}}else{if (a[mid] < a[end]){return mid;}else{return end;}}
}


5.2  递归到小的子区间时,可以考虑使用插入排序

void QuickSort(int* a, int left,int right)
{if (left >= right) return;if (right - left + 1 > 10){int div = PartSort3(a, left, right);QuickSort(a, left, div - 1);QuickSort(a, div + 1, right);}else{InsertSort(a+left, right - left + 1);}}

5.3 快排的非递归形式

这样是为了保证出栈时候,第一个就是数组的最左,第二个就是数组的最右。

//快排非递归
void QuickSortNonR(int* a, int begin, int end)
{Stack s;StackInit(&s);//先把得到的数组的末尾和头入栈StackPushBack(&s, end);StackPushBack(&s, begin);while (!StackEmpty(&s)){//得到需要排序数组的左指针int left = StackTop(&s);StackPopBack(&s);//出栈//得到右指针int right = StackTop(&s);StackPopBack(&s);//得到基准值,左边都小于他,右边都大于他int div = PartSort3(a, left, right);if (left < div - 1) //[left,div-1]区间大于1个元素就进栈,小于等于1个就不用排了{StackPushBack(&s, div - 1);StackPushBack(&s, left);}if (div + 1 < right)//[div,right]区间大于1个元素就进栈,小于等于1个就不用排了{StackPushBack(&s, right);StackPushBack(&s, div + 1);}}StackDestory(&s);//销毁栈
}

 7 归并排序(暂时没搞懂,后续更新)

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

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

相关文章

Ubuntu 24.04 安装 英特尔工具包 Intel® Toolkits

目录 1.采用用户界面 GUI 安装英特尔基本工具包 Intel oneAPI Base Toolkit 1.1 下载离线英特尔基本工具包 1.2 安装英特尔基本工具包 1.3 英特尔基本工具包 Intel oneAPI Base Toolkit 环境设置 2.安装英特尔高性能计算工具包 Intel HPC Toolkit 2.1 下载离线英特尔高性…

模型从 HuggingFace 转存到 ModelScope

由于 HuggingFace 网络访问比较慢&#xff0c;国内通常会使用魔搭下载模型&#xff0c;如果魔搭上还没有&#xff0c;需要从 HuggingFace 准存一下&#xff0c;本文将通过 Colab AliyunPan 的方式下载模型并进行转存。 登录Colab 并运行一下命令 安装依赖包&#xff0c;Hugg…

最新项目管理软件排行榜,90%大厂项目经理都在用!

本文是主流的热门项目管理软件排行榜&#xff0c;助力企业选型&#xff01; 项目管理软件排行榜就如同企业管理的指南针&#xff0c;能为企业在众多项目管理工具中找到最适合的那一款。 对于企业来说&#xff0c;如果没有好用的项目管理软件&#xff0c;就像航海者失去了罗盘&…

Python 数据分析笔记— Numpy 基本操作(上)

文章目录 学习内容&#xff1a;一、什么是数组、矩阵二、创建与访问数组三、矩阵基本操作 学习内容&#xff1a; 一、什么是数组、矩阵 数组&#xff08;Array&#xff09;&#xff1a;是有序的元素序列&#xff0c;可以是一维、二维、多维。 array1 [1,2,3] 或[a, b, c, d…

智能工厂监控升级:Sovit2D大屏展示和ARM计算机的完美搭档

在当今科技飞速发展的时代&#xff0c;智能工厂和环境监测领域对于高效、精准的监控系统的需求日益增长。Sovit2D 组态软件与 ARM 工业计算机的结合&#xff0c;为这些领域带来了全新的解决方案。 走进智能工厂的监控室&#xff0c;一台台 ARM 工业计算机正稳定地运行着 Sovit2…

Echarts可视化

echarts是一个基于javascripts的开源可视化图表库 画图步骤&#xff1a; 1.引入echarts.js文件 <script src" https://cdn.jsdelivr.net/npm/echarts5.5.1/dist/echarts.min.js"></script> 也可将文件下载到本地通过src引入。 2. 准备一个呈现图表的…

828华为云征文|华为云Flexus X实例docker部署harbor镜像仓库

828华为云征文&#xff5c;华为云Flexus X实例docker部署harbor镜像仓库 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求&#xff0c;一定不要错…

Django+Vue二手交易平台的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 需要的环境3.2 Django接口层3.3 实体类3.4 config.ini3.5 启动类3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作者&…

Having trouble using OpenAI API

题意&#xff1a;"使用OpenAI API遇到困难" 问题背景&#xff1a; I am having trouble with this code. I want to implement AI using OpenAI API in my React.js project but I cannot seem to get what the issue is. I ask it a question in the search bar in…

string详解

Golang详解string 文章目录 Golang详解stringGolang中为什么string是只读的&#xff1f;stirng和[]byte的转化原理[]byte转string一定需要内存拷贝吗&#xff1f;字符串拼接性能测试 Golang中为什么string是只读的&#xff1f; 在Go语言中&#xff0c;string其实就是一个结构体…

实验报告: lookie-lookie 项目测试与分析

目录 一、实验目的 二、实验环境 三、实验步骤 1. 下载与准备项目 1.1 从 GitHub 获取项目 1.2 查看项目文件结构 2. 运行项目 2.1 启动项目 2.2 浏览器设置 3. 项目体验 3.1 功能测试 3.2 运行截图 4. 文件结构分析 4.1 总体结构 4.2 主要文件和目录说明 5. 数…

09-03 周二 ansible部署和节点管理过程

09-03 周二 ansible部署和节点管理过程 时间版本修改人描述2024年9月3日10:08:58V0.1宋全恒新建文档&#xff0c; 简介 首先要找一个跳板机&#xff0c;来确保所有的机器都可以访问。然后我们围绕ansible来搭建环境&#xff0c;方便一键执行所有的命令&#xff0c;主要的任务是…

SQL语言的规则和规范

规则 是什么呢&#xff0c;规则就是我们最基本&#xff0c;每时每刻都要遵守的比如人行道靠右&#xff0c;不能逆行&#xff0c; 规范 呢就是锦上添花&#xff0c;如果你不这么做&#xff0c;是不那么道德&#xff0c;不那么好的&#xff0c;就像小学生见到老师要问好&#…

机器学习:opencv图像识别--图片运算、边界、阈值处理、平滑处理

目录 一、图片运算 1.加法 1. 2.add 3.加权相加 2.减法 二、图片边界 三、图像阈值处理 四、图像平滑处理 1.生成椒盐噪声 2.滤波器 1.均值滤波 2.方框滤波 3.高斯滤波 4.中值滤波 一、图片运算 1.加法 1. 直接将图片上每个像素点的值加上给定值或者两张图片…

wpf image source绑定相对路径方法

当使用image source绑定相对路径图片资源时&#xff0c;出现问题&#xff1a;未能找到路径C:\windows/System32…路径的一部分 解决方法&#xff1a; 将文件放到指定文件夹中包含在当前项目中 具体绑定语句为&#xff1a; <Image Stretch"Fill" x:Name"imgT…

(计算机论文)基于SpringBoot和Vue的台球赛事服务网站的设计与实现

毕业设计&#xff08;论文&#xff09; 博主可接毕设论文&#xff01;&#xff01;&#xff01; 基于SpringBoot和Vue的台球赛事服务网站的设计与实现 摘 要 在快速发展的信息时代&#xff0c;体育竞赛作为群众文化娱乐的一部分&#xff0c;已日益受到广泛关注。台球&#xff…

python 怎样计算字符串的长度

python 计算字符串长度&#xff0c;一个中文算两个字符&#xff0c;先转换成utf8&#xff0c;然后通过计算utf8的长度和len函数取得的长度&#xff0c;进行对比即可知道字符串内中文字符的数量&#xff0c;自然就可以计算出字符串的长度了。 valueu脚本12 length len(value) u…

排查SQL Server中的内存不足及其他疑难问题

文章目录 引言I DMV 资源信号灯资源信号灯 DMV sys.dm_exec_query_resource_semaphores( 确定查询执行内存的等待)查询性能计数器什么是内存授予?II DBCC MEMORYSTATUS 查询内存对象III DBCC 命令释放多个 SQL Server 内存缓存 - 临时度量值IV 等待资源池 %ls (%ld)中的内存…

统计学习与方法实战——K近邻算法

K近邻算法 K近邻算法备注k近邻模型算法距离度量 k k k值选择分类决策规则构造KDTree k k k近邻查找范围查询 代码结构总结 K近邻算法 备注 kNN是一种基本分类与回归方法. 多数表决规则等价于0-1损失函数下的经验风险最小化&#xff0c;支持多分类&#xff0c; 有别于前面的感…

QT做一个USB HID设备识别软件

1.下载 HidApi库&#xff1a;GitHub - yigityuce/HidApi: Human Interface Device Api (HidApi) with C 2.pro文件添加 DEFINES - UNICODE LIBS -lsetupapi 3.h文件 #ifndef My_Usb_Hid_Device_H #define My_Usb_Hid_Device_H#include <QWidget> #include <QStr…