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

常见排序算法汇总

排序算法汇总

这篇文章说明下排序算法,直接开始。

1.冒泡排序

最简单直观的排序算法了,新手入门的第一个排序算法,也非常直观,最大的数字像泡泡一样一个个的“冒”到数组的最后面。

算法思想:反复遍历要排序的序列,每次比较相邻的两个元素,如果顺序不正确就交换它们。这样每次遍历都会将最大的元素放到末尾。

排序的时间复杂度O(n²),如果设置标志为(如果发生数据交换flag=1,默认为0)复杂度为O(n),,因为是原地排序,基本不用

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

2.选择排序

算法思想:每次从未排序的部分选择最小的元素,放到已排序部分的末尾,重复这个过程。时间复杂度:O(n²),无论怎样都是O(n²),空间复杂度O(1),基本不用

void selectionSort(std::vector<int> &arr) {int n = arr.size();for (int i = 0; i < n - 1; ++i) {int minIndex = i; // 假设当前元素为最小值的索引for (int j = i + 1; j < n; ++j) { // 在未排序部分查找最小值if (arr[j] < arr[minIndex]) {minIndex = j; // 更新最小值索引}}// 将找到的最小值与当前元素交换if (minIndex != i) {std::swap(arr[i], arr[minIndex]);}}
}

3.插入排序

算法思想:将数组分为已排序和未排序部分,从未排序部分取元素,在已排序部分找到合适的位置插入。时间复杂度O(n²),空间复杂度O(1)。

void insertionSort(std::vector<int>& arr) {int n = arr.size();  // 获取数组的大小for (int i = 1; i < n; i++) {  // 从第二个元素开始int key = arr[i];  // 当前待插入的元素int j = i - 1;// 在已排序部分中找到合适的位置插入 keywhile (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];  // 向后移动元素j--;  // 移动到前一个元素}arr[j + 1] = key;  // 插入 key}
}

4.快速排序

算法思想:选择一个基准元素,将数组划分为比基准小的部分和比基准大的部分,递归地对这两个部分排序。时间复杂度O(n log n),空间复杂度O(log n) 。

void fastSort(vector<int> &nums, int low, int high) {if (low >= high)return;int pivot = nums[high], i = low;for (int j = low; j < high; j++) {if (nums[j] < pivot) {if (i != j)swap(nums[i], nums[j]);i++;}}swap(nums[i], nums[high]);fastSort(nums, low, i - 1);fastSort(nums, i + 1, high);
}

5.归并排序

算法思想:采用分治法,将数组分成两个子数组分别排序,再将它们合并成一个有序数组。时间复杂度O(n log n),空间复杂度O(n) 。

//递归版本
void mergeSort(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);vector<int> tmp(right - left + 1);int count = 0;int i = left, j = mid + 1;while (i <= mid && j <= right) {if (nums[i] < nums[j]) {tmp[count++] = nums[i++];} else {tmp[count++] = nums[j++];}}while (i <= mid) {tmp[count++] = nums[i++];}while (j <= right) {tmp[count++] = nums[j++];}for (int p = 0; p < tmp.size(); p++) {nums[left + p] = tmp[p];}
}
//迭代版本
void mergeSortIterative(std::vector<int> &nums) {int n = nums.size();for (int currentsize = 1; currentsize < n - 1; currentsize *= 2)for (int left = 0; left < n - 1; left += 2 * currentsize) {int mid = min(left + currentsize - 1, n - 1);int right = min(left + 2 * currentsize - 1, n - 1);int n1 = mid - left + 1;int n2 = right - mid;vector<int> leftArr(n1), rightArr(n2);for (int i = 0; i < n1; i++)leftArr[i] = nums[left + i];for (int i = 0; i < n2; i++)rightArr[i] = nums[mid + i + 1];int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (leftArr[i] < rightArr[j]) {nums[k] = leftArr[i++];} else {nums[k] = rightArr[j++];}k++;}while (i < n1) {nums[k++] = leftArr[i++];}while (j < n2) {nums[k++] = rightArr[j++];}}
}

6.堆排序

算法思想:使用二叉堆这种数据结构,先构建最大堆(或最小堆),然后依次将堆顶元素移除,重新调整堆。时间复杂度O(n log n),空间复杂度O(1)(不用递归的话)

void heapify(vector<int> &nums, int n, int i) {if(i>n)return;int largest = i;int left = 2 * i + 1, right = 2 * i + 2;if (left < n && nums[left] > nums[largest])largest = left;if (right < n && nums[right] > nums[largest])largest = right;if (largest != i) {swap(nums[i], nums[largest]);heapify(nums, n, largest);}}void heapSort(vector<int> &nums) {int n = nums.size();for(int i=n/2-1;i>=0;i--) {heapify(nums,n,i);}for(int i=n-1;i>0;i--) {swap(nums[0],nums[i]);heapify(nums,i,0);}
}

排序算法的总结表格:

排序算法最好时间复杂度最坏时间复杂度平均时间复杂度空间复杂度稳定性
冒泡排序O(n)O(n²)O(n²)O(1)稳定
选择排序O(n²)O(n²)O(n²)O(1)不稳定
插入排序O(n)O(n²)O(n²)O(1)稳定
归并排序O(n log n)O(n log n)O(n log n)O(n)稳定
快速排序O(n log n)O(n²)O(n log n)O(log n)不稳定
堆排序O(n log n)O(n log n)O(n log n)O(1)不稳定

7.文末解释一下算法时间复杂中的log n,有些人不理解

快速排序的平均时间复杂度为 O(n log n),是因为它在理想情况下可以将问题规模递归减半,而每次递归的划分过程需要 O(n) 的操作。通过递归树的结构,我们可以直观理解为什么时间复杂度为 O(n log n)

1. 每一层的操作需要 O(n) 的时间

在快速排序的每一层递归中,主要的开销来自于划分(partition)操作。这个操作的过程是选取一个基准元素(pivot),然后从两边扫描数组,交换元素,使得基准元素的左边都比它小,右边都比它大。

无论基准元素选得如何,每次划分需要遍历整个数组。因此,在每一层递归中,划分操作的时间复杂度是 O(n),其中 n 是当前数组的长度。

2. 递归的层数为 log n

在理想情况下,快速排序的每次递归都能将数组大致划分为相等的两部分,即每次递归之后,数组的规模缩小为原来的 1/2。这个过程相当于将问题规模递归地减半,直到数组大小缩减到 1

因此,总共需要递归 log n 层(递归树的高度),这里的 log n 表示递归树的层数,也就是快速排序的递归深度。

3. 总时间复杂度为 O(n log n)

  • 每层的时间复杂度:在递归树的每一层,需要 O(n) 的时间来对数组进行划分。
  • 递归树的层数:递归树的高度为 log n,表示总共要递归 log n 层。

因此,整个快速排序的总时间复杂度就是:
总时间=每层所需的时间×递归的层数=O(n)×O(logn)=O(nlogn)

递归树示意:

可以将快速排序的递归过程看作是一个递归树,每一层是对整个数组的遍历,每一层都需要 O(n) 的时间来进行划分。递归树的层数是 log n,总共 log n 层。

举例说明递归树结构:

               O(n)----------------|                |O(n/2)           O(n/2)-------           -------|      |          |      |O(n/4) O(n/4)     O(n/4) O(n/4)----------------------------...       (共 log n 层)

4. 平均时间复杂度为 O(n log n) 的解释

在理想情况下,每次划分都能把数组平分成两半,快速排序的递归树的高度为 log n。每一层递归处理的元素总数为 n(即整个数组的长度),由于有 log n 层,所以整个快速排序的总时间复杂度为 O(n log n)

5. 总结

  • 每一层快速排序的递归操作需要 O(n) 的时间来进行划分。
  • 总共有 log n 层递归,即递归树的高度为 log n
  • 因此,快速排序的平均时间复杂度是 O(n log n)

不过需要注意,在最坏情况下(当每次划分都极不平衡,如数组是完全有序的),递归树的高度会退化为 n,此时时间复杂度为 O(n^2)。通过随机化选择基准元素,可以有效避免这种最坏情况的发生,从而保证平均时间复杂度为 O(n log n)

相关文章:

常见排序算法汇总

排序算法汇总 这篇文章说明下排序算法&#xff0c;直接开始。 1.冒泡排序 最简单直观的排序算法了&#xff0c;新手入门的第一个排序算法&#xff0c;也非常直观&#xff0c;最大的数字像泡泡一样一个个的“冒”到数组的最后面。 算法思想&#xff1a;反复遍历要排序的序列…...

Golang | Leetcode Golang题解之第459题重复的子字符串

题目&#xff1a; 题解&#xff1a; func repeatedSubstringPattern(s string) bool {return kmp(s s, s) }func kmp(query, pattern string) bool {n, m : len(query), len(pattern)fail : make([]int, m)for i : 0; i < m; i {fail[i] -1}for i : 1; i < m; i {j : …...

0.计网和操作系统

0.计网和操作系统 熟悉计算机网络和操作系统知识&#xff0c;包括 TCP/IP、UDP、HTTP、DNS 协议等。 常见的页面置换算法&#xff1a; 先进先出&#xff08;FIFO&#xff09;算法&#xff1a;将最早进入内存的页面替换出去。最近最少使用&#xff08;LRU&#xff09;算法&am…...

探索Prompt Engineering:开启大型语言模型潜力的钥匙

前言 什么是Prompt&#xff1f;Prompt Engineering? Prompt可以理解为向语言模型提出的问题或者指令&#xff0c;它是激发模型产生特定类型响应的“触发器”。 Prompt Engineering&#xff0c;即提示工程&#xff0c;是近年来随着大型语言模型&#xff08;LLM&#xff0c;Larg…...

滚雪球学Oracle[3.3讲]:数据定义语言(DDL)

全文目录&#xff1a; 前言一、约束的高级使用1.1 主键&#xff08;Primary Key&#xff09;案例演示&#xff1a;定义主键 1.2 唯一性约束&#xff08;Unique&#xff09;案例演示&#xff1a;定义唯一性约束 1.3 外键&#xff08;Foreign Key&#xff09;案例演示&#xff1a…...

ssrf学习(ctfhub靶场)

ssrf练习 目录 ssrf类型 漏洞形成原理&#xff08;来自网络&#xff09; 靶场题目 第一题&#xff08;url探测网站下文件&#xff09; 第二关&#xff08;使用伪协议&#xff09; 关于http和file协议的理解 file协议 http协议 第三关&#xff08;端口扫描&#xff09…...

ElasticSearch之网络配置

对官方文档Networking的阅读笔记。 ES集群中的节点&#xff0c;支持处理两类通信平面 集群内节点之间的通信&#xff0c;官方文档称之为transport layer。集群外的通信&#xff0c;处理客户端下发的请求&#xff0c;比如数据的CRUD&#xff0c;检索等&#xff0c;官方文档称之…...

【C语言进阶】系统测试与调试

1. 引言 在开始本教程的深度学习之前&#xff0c;我们需要了解整个教程的目标及其结构&#xff0c;以及为何进阶学习是提升C语言技能的关键。 目标和结构&#xff1a; 教程目标&#xff1a;本教程旨在通过系统化的学习&#xff0c;从单元测试、系统集成测试到调试技巧&#xf…...

多个单链表的合成

建立两个非递减有序单链表&#xff0c;然后合并成一个非递增有序的单链表。 注意&#xff1a;建立非递减有序的单链表&#xff0c;需要采用创建单链表的算法 输入格式: 1 9 5 7 3 0 2 8 4 6 0 输出格式: 9 8 7 6 5 4 3 2 1 输入样例: 在这里给出一组输入。例如&#xf…...

『建议收藏』ChatGPT Canvas功能进阶使用指南!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…...

Ollama 运行视觉语言模型LLaVA

Ollama的LLaVA&#xff08;大型语言和视觉助手&#xff09;模型集已更新至 1.6 版&#xff0c;支持&#xff1a; 更高的图像分辨率&#xff1a;支持高达 4 倍的像素&#xff0c;使模型能够掌握更多细节。改进的文本识别和推理能力&#xff1a;在附加文档、图表和图表数据集上进…...

gdb 调试 linux 应用程序的技巧介绍

使用 gdb 来调试 Linux 应用程序时&#xff0c;可以显著提高开发和调试的效率。gdb&#xff08;GNU 调试器&#xff09;是一款功能强大的调试工具&#xff0c;适用于调试各类 C、C 程序。它允许我们在运行程序时检查其状态&#xff0c;设置断点&#xff0c;跟踪变量值的变化&am…...

Java项目实战II基于Java+Spring Boot+MySQL的房产销售系统(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着房地产市场的蓬勃发展&#xff0c;房产销售业务日益复杂&#xff0c;传统的手工管理方式已难以满…...

aws(学习笔记第一课) AWS CLI,创建ec2 server以及drawio进行aws画图

aws(学习笔记第一课) 使用AWS CLI 学习内容&#xff1a; 使用AWS CLI配置密钥对创建ec2 server使用drawio&#xff08;vscode插件&#xff09;进行AWS的画图 1. 使用AWS CLI 注册AWS账号 AWS是通用的云计算平台&#xff0c;可以提供ec2&#xff0c;vpc&#xff0c;SNS以及clo…...

【Python】Eventlet 异步网络库简介

Eventlet 是一个 Python 的异步网络库&#xff0c;它使用协程&#xff08;green threads&#xff09;来简化并发编程。通过非阻塞的 I/O 操作&#xff0c;Eventlet 使得你可以轻松编写高性能的网络应用程序&#xff0c;而无需处理复杂的回调逻辑或编写多线程代码。它广泛应用于…...

【JNI】数组的基本使用

在上一期讲了基本类型的基本使用&#xff0c;这期来说一说数组的基本使用 HelloJNI.java&#xff1a;实现myArray函数&#xff0c;把一个整型数组转换为双精度型数组 public class HelloJNI { static {System.loadLibrary("hello"); }private native String HelloW…...

React跨平台

React的跨平台应用开发详解如下&#xff1a; 一、跨平台能力 React本身是一个用于构建用户界面的JavaScript库&#xff0c;但它通过React Native等框架实现了跨平台应用开发的能力。React Native允许开发者使用JavaScript和React来编写原生应用&#xff0c;这些应用可以在iOS和…...

如何在 SQL 中更新表中的记录?

当你需要修改数据库中已存在的数据时&#xff0c;UPDATE 语句是你的首选工具。 这允许你更改表中一条或多条记录的特定字段值。 下面我将详细介绍如何使用 UPDATE 语句&#xff0c;并提供一些开发建议和注意事项。 基础用法 假设我们有一个名为 employees 的表&#xff0c;…...

宠物饮水机的水箱低液位提醒如何实现?

ICMAN液位检测芯片轻松实现宠物饮水机的水箱低液位提醒功能&#xff01; 工作原理 &#xff1a; 基于双通道电容式单点液位检测原理 方案特点&#xff1a; 液位检测精度高达1mm&#xff0c;超强抗干扰&#xff0c;动态CS 10V 为家用电器水位提醒的应用提供了一种简单而又有…...

EXCEL_光标百分比

Public Sub InitCells()Dim iSheet As LongFor iSheet Sheets.Count To 1 Step -1Sheets(iSheet).ActivateActiveWindow.Zoom 85ActiveWindow.ScrollRow 1ActiveWindow.ScrollColumn 1Sheets(iSheet).Range("A1").ActivateNext iSheetEnd Sub对日项目中的文档满天…...

(一)Web 网站服务之 Apache

一、Apache 的作用和特点 作用&#xff1a;Apache 是一款开源的网站服务器端软件&#xff0c;为网站的运行提供了稳定的基础。特点&#xff1a; 开源免费&#xff1a;这使得任何人都可以免费使用和修改它。模块化设计&#xff1a;具有高度的灵活性&#xff0c;可以根据需求选择…...

英语词汇小程序小程序|英语词汇小程序系统|基于java的四六级词汇小程序设计与实现(源码+数据库+文档)

英语词汇小程序 目录 基于java的四六级词汇小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&a…...

AI学习指南深度学习篇-学习率衰减的实现机制

AI学习指南深度学习篇-学习率衰减的实现机制 前言 在深度学习中&#xff0c;学习率是影响模型训练的重要超参数之一。合理的学习率设置不仅可以加速模型收敛&#xff0c;还可以避免训练过程中出现各种问题&#xff0c;如过拟合或训练不收敛。学习率衰减是一种动态调整学习率的…...

My_qsort() -自己写的 qsort 函数

2024 - 10 - 05 - 笔记 - 21 作者(Author)&#xff1a;郑龙浩 / 仟濹(网名) My_qsort()- 自己写的qsort函数 My_qsort为自己写的qsort函数&#xff0c;但是采用的不是快速排序&#xff0c;而是冒泡排序&#xff0c;是为了模仿qsort函数而尝试写出来的函数。 思路&#xff1a…...

《向量数据库指南》——Mlivus Cloud打造生产级AI应用利器

哈哈,各位向量数据库和AI应用领域的朋友们,大家好!我是大禹智库的向量数据库高级研究员王帅旭,也是《向量数据库指南》的作者。今天,我要和大家聊聊如何使用Mlivus Cloud来搭建生产级AI应用。这可是个热门话题哦,相信大家都非常感兴趣! 《向量数据库指南》 使用Mlivus …...

Electron 进程通信

预加载&#xff08;preload&#xff09;脚本只能访问部分 Node.js API&#xff0c;但是主进程可以访问全部API。此时&#xff0c;需要使用进程通信。 比如&#xff0c;在preload.js中&#xff0c;不能访问__dirname&#xff0c;不能使用 Node 中的 fs 模块&#xff0c;但主进程…...

Kubernetes资源详解

华子目录 1.Kubernetes中的资源1.1资源管理介绍1.2资源管理方式1.2.1命令式对象管理1.2.2kubectl常见command命令1.2.3资源类型1.2.4常用资源类型 基本命令示例运行和调试命令示例高级命令示例总结 其他命令示例create和apply区别案例显示命名空间查看命名空间中的pod如何对外暴…...

C++11之线程

编译环境&#xff1a;Qt join&#xff1a;阻塞当前线程&#xff0c;直到线程函数退出 detach&#xff1a;将线程对象与线程函数分离&#xff0c;线程不依赖线程对象管理 注&#xff1a;join和detach两者必选其一&#xff0c;否则线程对象的回收会影响线程的回收&#xff0c;导致…...

界星空科技漆包线行业称重系统

万界星空科技为漆包线行业提供的称重系统是其MES制造执行系统解决方案中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、系统概述 万界星空科技漆包线行业称重系统&#xff0c;是集成在MES系统中的一个功能模块&#xff0c;专门用于漆包线生产过程中的重量检…...

RabbitMQ的高级特性-事务

事务&#xff1a;RabbitMQ是基于AMQP协议实现的, 该协议实现了事务机制, 因此RabbitMQ也⽀持事务机制. SpringAMQP也提供了对事务相关的操作. RabbitMQ事务允许开发者确保消息的发送和接收是原⼦性的, 要么全部成功, 要么全部失败 配置事务管理器&#xff1a; Bean public Ra…...