十大基础排序算法

排序算法分类

排序:将一组对象按照某种逻辑顺序重新排列的过程。

  • 按照待排序数据的规模分为:

    1. 内部排序:数据量不大,全部存在内存中;
    2. 外部排序:数据量很大,无法一次性全部存在内存中,因此排序中需要访问外存。
  • 按照排序是否稳定分为:

    1. 稳定排序:相等的元素在排序前后的相对位置不变。例如,a等于b,且原序列a在b前,排序后a仍在b前,则为稳定排序。
    2. 不稳定排序:相等元素在排序前后的相对位置可能发生变化。
  • 按照是否需要额外内存分为:

    1. 原地排序:在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
    2. 非原地排序:需要额外内存空间存储数组副本以辅助排序。
  • 按照排序方式分为:

    1. 比较类排序:通过比较来决定元素间的相对次序。
    2. 非比较类排序:不通过元素间的比较进行排序。
      在这里插入图片描述

比较类排序

冒泡排序

冒泡排序是一种典型的交换排序

算法原理:

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这一步结束后,排在最后的元素会是所有数据中最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

冒泡排序基本代码如下:

void BubbleSort(vector<int>& nums){const int size = nums.size();for(int i = 0; i < size; ++i)for(int j = 0; j < size-i-1; ++j)if(nums[j] > nums[j+1])swap(nums[j], nums[j+1]);
}

性能评价:

  • nums[j] == nums[j+1]时,我们并不交换它们。所以冒泡排序是稳定的;
  • 共循环了(n-1)+(n-2)+…+2+1=n(n-1)/2,所以时间复杂度是O(n^2)。

快速排序

快速排序是从冒泡排序演变而来的,实际上是在冒泡排序基础上的递归分治法。
快速排序在每一轮挑选一个基准元素,并让其他比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成了两个部分。

快排也用了分治策略,其本质框架类似二叉树的前序遍历。

其实现代码如下:

void QuickSort(std::vector<int>& nums, int left, int right){if(left >= right){return;}//"治"int i = left;int j = right;while(i < j){while(i < j && nums[j] > nums[left])     --j;while(i < j && nums[i] <= nums[left])    ++i;std::swap(nums[i], nums[j]);}std::swap(nums[i], nums[left]);//“分”QuickSort(nums, left, i - 1);QuickSort(nums, i + 1, right);
}

注意事项

  1. 如果选取数列的第一个元素为基准元素,则从right所指向的元素开始与基准元素进行比较;如果选取数列的最后一个元素为基准元素,则从left所指向的元素开始与基准元素进行比较。
  2. 如果选取数列的第一个元素为基准元素,left所指向的元素与基准元素第一次对比时,left下标与基准元素下标相等(即:判断条件中添加等号);如果选取数列的最后一个元素为基准元素,right所指向的元素与基准元素第一次对比时,right下标与基准元素下标相等。

时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定

插入排序

基本思想:将待排序数据看成由已排序未排序两部分组成。对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

算法流程:

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。

其实现代码如下:

void InsertSort(vector<int>& nums){const int size = nums.size();for(int i = 1; i < size; ++i){int curr = nums[i];int j = i - 1;while(j >= 0 && curr < nums[j]){nums[j+1] = nums[j];--j;}nums[j+1] = curr;}
}

性能评价:

  • 插入排序是稳定的。
  • 时间复杂度为O(n^2)。

希尔排序

在插入排序中,当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.

希尔排序是对插入排序的优化。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序
在这里插入图片描述

其实现代码如下:

void ShellSort(std::vector<int>& nums){const int size = nums.size();for(int gap = size / 2; gap > 0; gap /= 2){for(int i = gap; i < size; ++i){int curr = nums[i];int j = i - gap;while(j >= 0 && curr < nums[j]){nums[j+gap] = nums[j];j -= gap;}nums[j+gap] = curr;}}
}

选择排序

基本思想:首先在未排序数据找到最小的数,然后把该最小数放到排序序列的末尾,直到所有数据排序完毕。

其实现代码如下:

void SelectionSort(vector<int>& nums){const int size = nums.size();for(int i = 0; i < size-1; ++i){int minIndex = i;for(int j = i+1; j < size; ++j)if(nums[j] < nums[minIndex])minIndex = j;swap(nums[i], nums[minIndex]);}
}

性能评价:

  • 简单选择排序是不稳定排序;
  • 无论什么数据进去,它的比较次数都是n(n-1)/2,所以时间复杂度是O(n^2)。

堆排序

首先将等待排序的数组构造成一个大根堆,构造结束后整个数组当中的最大值就是堆顶元素;
然后将堆顶元素与数组末尾元素交换位置,交换结束后数组末尾元素为最大值,剩下其他的待排序的数组个数为n-1个;
将剩余的n-1个数再次构造成一个大根堆,再将堆顶元素与数组第n-1个位置的元素交换位置,重复上述步骤可以最终得到一个有序数组。

其实现代码如下:

//堆调整
void Heapify(std::vector<int>& nums, int index, int heap_size){int parent_index = index;int leftChild_index = 2 * parent_index + 1;while(leftChild_index < heap_size){int maxValue_index = leftChild_index+1 < heap_size && nums[leftChild_index+1] > nums[leftChild_index] ? leftChild_index+1 : leftChild_index;maxValue_index = nums[maxValue_index] > nums[parent_index] ? maxValue_index : parent_index;if(maxValue_index == parent_index)return;std::swap(nums[maxValue_index], nums[parent_index]);parent_index = maxValue_index;leftChild_index = 2 * parent_index + 1;} 
}
//堆排序
void HeapSort(std::vector<int>& nums){if(nums.size() < 2)return;int heap_size = nums.size();//从下标最大的父节点开始。(最后一个元素的下标是n-1,最后一个父节点的下标是n/2-1)for(int i = heap_size/2 - 1; i >= 0; --i)Heapify(nums, i, heap_size);std::swap(nums[0], nums[--heap_size]);while(heap_size > 0){Heapify(nums, 0, heap_size);std::swap(nums[0], nums[--heap_size]);}
}

时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定

归并排序

简单归并排序即二路归并排序。

归并排序采用分治策略,其本质框架类似二叉树的后序遍历,左右子树的递归就是“分”,根结点的处理部分就是“治”。

在这里插入图片描述

其实现代码如下:

std::vector<int> temp;
void MergeSort(std::vector<int>& nums, int left, int right){if(left >= right){return;}int mid = left + (right - left) / 2;//“分”MergeSort(nums, left, mid);MergeSort(nums, mid + 1, right);//"治"int i = left;int j = mid + 1;int t = left;while(i <= mid && j <= right){if(nums[i] <= nums[j]){temp[t++] = nums[i++];}else{temp[t++] = nums[j++];}}while(i <= mid){temp[t++] = nums[i++];}while(j <= right){temp[t++] = nums[j++];}for(int k = left; k <= right; ++k){nums[k] = temp[k];}
}

时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定

非比较类排序

基数排序

计数排序

桶排序

总结

在这里插入图片描述

不稳定排序记忆口诀:一堆(堆排序)作业,心态不稳,快(快速排序)选择(选择排序)一些(希尔排序)朋友出去玩。

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

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

相关文章

Vue2尚品汇前台项目笔记——(1)项目初始化

Vue2尚品汇前台项目笔记 一、项目初始化 使用[脚手架创建项目&#xff0c;具体参考之前的脚手架配置笔记&#xff0c;我起名叫vue_shop_test 1.脚手架目录分析 node_modules文件夹&#xff1a;项目依赖文件夹 public文件夹&#xff1a;一般放置一些静态资源&#xff08;图…

Java项目:20 基于SSM实现的支教管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 ssm支教管理系统&#xff08;前台后台&#xff09; 前台角色&#xff1a;支教学校志愿者 支教学校功能模块&#xff1a;支教学校查询报名职位…

【数据结构】单向循环链表

一、mian函数 #include <stdio.h> #include "./3.looplinklist.h" int main(int argc, const char *argv[]) {looplinklist* head create_looplinklist();insertHead_looplinklist(head,100);insertHead_looplinklist(head,200);insertHead_looplinklist(hea…

瑞盟MS5188N——16bit、8 通道、500kSPS、 SAR 型 ADC

产品简述 MS5188N 是 8 通道、 16bit 、电荷再分配逐次逼近型模数 转换器&#xff0c;采用单电源供电。 MS5188N 拥有多通道、低功耗数据采集系统所需的所有 组成部分&#xff0c;包括&#xff1a;无失码的真 16 位 SAR ADC &#xff1b;用于将输入配 置为单端输入…

【Flink状态管理(八)】Checkpoint:CheckpointBarrier对齐后Checkpoint的完成、通知与对学习状态管理源码的思考

文章目录 一. 调用StreamTask执行Checkpoint操作1. 执行Checkpoint总体代码流程1.1. StreamTask.checkpointState()1.2. executeCheckpointing1.3. 将算子中的状态快照操作封装在OperatorSnapshotFutures中1.4. 算子状态进行快照1.5. 状态数据快照持久化 二. CheckpointCoordin…

图的遍历-----深度优先遍历(dfs),广度优先遍历(bfs)【java详解】

目录 简单介绍&#xff1a;什么是深度、广度优先遍历&#xff1f; 深度优先搜索&#xff08;DFS&#xff0c;Depth First Search&#xff09;&#xff1a; 大致图解&#xff1a; 广度优先搜索&#xff08;BFS&#xff0c;Breadth First Search&#xff09;&#xff1a; 大致图…

Python学习笔记——自定义函数(传递任意数量的实参)

Python允许函数从调用语句中收集任意数量的实参。例如下面自定义函数制作一个披萨&#xff0c;它需要接受很多配料&#xff0c;但无法预先确定顾客要点多少种配料。 下面行数只有一个形参*toppings&#xff0c;不管调用语句提供多少个实参&#xff0c;这个参数都会收集到&…

用 LangChain 和 Milvus 从零搭建 LLM 应用

如何从零搭建一个 LLM 应用&#xff1f;不妨试试 LangChain Milvus 的组合拳。 作为开发 LLM 应用的框架&#xff0c;LangChain 内部不仅包含诸多模块&#xff0c;而且支持外部集成&#xff1b;Milvus 同样可以支持诸多 LLM 集成&#xff0c;二者结合除了可以轻松搭建一个 LL…

在Discord上添加自己的服务器并邀请midjourney机器人加入

我开发的chatgpt网站&#xff1a; https://chat.xutongbao.top

vue2--多设备访问本地调试项目

背景 在vue2开发阶段&#xff0c;为了更好的和小伙伴对项目进行讨论&#xff0c;需要让小伙伴可以看到自己本地的项目。 方案 修改vue2项目配置 在本地进行项目调试时&#xff0c;都是使用的127.0.0.1:8080&#xff0c;为了让局域网中的其他小伙伴可以访问&#xff0c;需要…

阿里云国际-在阿里云服务器上快速搭建幻兽帕鲁多人服务器

幻兽帕鲁是最近流行的新型生存游戏。该游戏一夜之间变得极为流行&#xff0c;同时在线玩家数量达到了200万。然而&#xff0c;幻兽帕鲁的服务器难以应对大量玩家的压力。为解决这一问题&#xff0c;幻兽帕鲁允许玩家建立专用服务器&#xff0c;其提供以下优势&#xff1a; &am…

Docker中如何删除某个镜像

1. 停止使用镜像的容器 首先&#xff0c;您需要停止所有正在使用该镜像的容器。您可以使用 docker stop 命令来停止容器&#xff1a; docker stop 11184993a106如果有多个容器使用该镜像&#xff0c;您需要对每个容器都执行停止命令。您可以通过 docker ps -a | grep core-ba…

数据结构 计算结构体大小

一、规则&#xff1a; 操作系统制定对齐量&#xff1a; 64位操作系统&#xff0c;默认8Byte对齐 32位操作系统&#xff0c;默认4Byte对齐 结构体对齐规则&#xff1a; 1.结构体整体的大小&#xff0c;需要是最大成员对齐量的整数倍 2.结构体中每一个成员的偏移量需要存在…

Selenium常见问题解析

1、元素定位失败&#xff1a; 在使用Selenium自动化测试时&#xff0c;最常见的问题之一是无法正确地定位元素&#xff0c;这可能导致后续操作失败。解决方法包括使用不同的定位方式&#xff08;如xpath、CSS selector、id等&#xff09;&#xff0c;等待页面加载完全后再进行…

【Oracle】玩转Oracle数据库(三):数据库的创建和管理

前言 嘿&#xff0c;各位数据库小能手们&#xff01;今天我们要进入数据库的创世纪&#xff0c;探索Oracle数据库的创建和管理&#xff01;&#x1f527;&#x1f4bb; 在这篇博文【Oracle】玩转Oracle数据库&#xff08;三&#xff09;&#xff1a;数据库的创建和管理中&#…

详解动态内存管理!

目录 ​编辑 1.为什么要用动态内存分配 2.malloc和free 2.1 malloc 2.2 free 3.calloc和realloc 3.1 calloc 3.2 realloc 4.常见的动态内存的错误 4.1 对NULL的解引用操作 4.2 对动态内存开辟空间的越界访问 4.3 对非动态内存开辟空间用free释放 4.4 使用free释放动…

【北京游戏业:出海竞争实力全面】

本文将深入分析北京的游戏行业发展。在上海、广州、北京、深圳、成都、杭州、福建七大游戏产业中心城市中&#xff0c;北京无疑是出海竞争力最强的游戏产业集群。本文将全面剖析北京游戏行业的发展现状。 北京是中国游戏产业的发源地。拥有从游戏引擎到美术设计等完整的产业链…

如何在Shopee平台上选择爆款商品:借鉴爆款属性的有效策略

在当今激烈竞争的电商市场中&#xff0c;想要在Shopee平台上取得成功&#xff0c;卖家需要精心选择潜在的热销产品。借鉴爆款商品的属性是一种行之有效的策略&#xff0c;能够帮助卖家快速找到市场上的热门商品。通过分析市场趋势、竞品表现、社交媒体趋势等多方面因素&#xf…

【EI会议征稿通知】第四届自动化控制、算法与智能仿生学术会议(ACAIB 2024)

第四届自动化控制、算法与智能仿生学术会议(ACAIB 2024) 2024 4th Conference on Automation Control, Algorithm and Intelligent Bionics 第四届自动化控制、算法与智能仿生学术会议&#xff08;ACAIB 2024&#xff09;将于2024年6月7日-9日在中国银川举行。 本届大会由北…

leetcode hot100 完全平方数

本题中&#xff0c;是给一个整数n&#xff0c;让用完全平方数凑出这个整数&#xff0c;注意&#xff0c;题中给了n的范围&#xff0c;是大于等于1的&#xff0c;也就是说&#xff0c;dp[0]我们可以先不考虑。 整个问题可以抽象成完全背包问题的变形形式&#xff0c;物品就是这…