常见排序算法汇总

news2024/10/6 11:24:04

排序算法汇总

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

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;

        // 在已排序部分中找到合适的位置插入 key
        while (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)

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

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

相关文章

【Canvas与艺术】金属底座洞眼红心按钮

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>金属底座洞眼红心按钮</title><style type"text/css&q…

校企合作必备无人机兴趣班技术详解

校企合作中的无人机兴趣班技术详解&#xff0c;可以从以下几个方面进行阐述&#xff1a; 一、合作背景与目标 随着无人机技术的飞速发展&#xff0c;无人机在航拍、农业、环境监测、应急救援等多个领域展现出巨大的应用潜力。市场对无人机专业人才的需求日益增长&#xff0c;…

STM32中断——外部中断

目录 一、概述 二、外部中断&#xff08;Extern Interrupt简称EXTI&#xff09; 三、实例-对射式红外传感器 1、配置中断&#xff1a; 2 、完整代码 一、概述 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件(中断源)&#xff0c;使得CPU暂停当…

【WebGis开发 - Cesium】三维可视化项目教程---视点管理

目录 引言一、基础功能探索1. 镜头视角获取2. 镜头视角移动 二、进一步封装代码1. 封装hooks函数2. 看下效果3. 如何使用该hooks函数 三、总结 引言 本教程主要是围绕Cesium这一开源三维框架开展的可视化项目教程。总结一下相关从业经验&#xff0c;如果有什么疑问或更好的见解…

SQL自用小结

推荐一下这个知识点总结 《数据库系统概论》第五版 学习笔记总目录 1. SQL概述 SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是一种用于定义、查询、更新和控制关系数据库的标准化语言。 它包含了数据定义语言&#xff08;DDL&#xff0…

(19)MATLAB使用Nakagami 分布对象生成Nakagami-m分布

文章目录 前言一、生成Nakagami分布随机变量的MATLAB代码1.仿真代码2.运行结果 二、传输信号经过衰落信道 前言 MATLAB在R2013a版本中开始引入Nakagami分布对象&#xff0c;可以用来生成Nakagami随机变量。下面给出一个使用实例&#xff0c;用于生成服从Nakagami 分布的随机变…

实战五:模拟10086查询功能

问题描述&#xff1a; 输入1&#xff0c;显示当前余额;输入2&#xff0c;显示当前的剩余流量&#xff0c;单位为G;输入3&#xff0c;显示当前的剩余通话&#xff0c;单位为分钟;输入0,退出自助查询系统。 编程&#xff1a; 1.方法一&#xff1a; # (1)初始化变量 answer y…

Java.数据结构.HashMap

目录 1基本概念 2数据结构 3常用操作 3.1 put(K key, V value)&#xff1a;插入键值对。 3.2 get(Object key)&#xff1a;根据键获取值。 3.3 remove(Object key)&#xff1a;移除键值对。 3.4 containsKey(Object key)&#xff1a;判断Map中是否包含指定的键。 3.5 c…

【Orange Pi 5 嵌入式应用编程】-用户空间SPI通信

用户空间SPI通信 文章目录 用户空间SPI通信1、理解SPI通信协议1.1 什么是SPI通信协议1.2 SPI如何工作?1.3 SPI数据传输步骤1.4 SPI的优缺点2、嵌入式Linux系统中的SPI通信3、Orange Pi 5 配置与编程3.1 Orange Pi 5开发板配置SPI3.2 SPI编程实现3.2.1 SPI用户空间函数定义3.2.…

Kafka 快速入门

目录 介绍 KafKa 相关术语 ​编辑 Kafka的工作流程 生产者向kafka发送数据的流程 Kafka选择分区的模式 Kafka选择分区的模式 数据消费 kafka的文件存储机制 topic、partition和segment 存储和查找message的过程 数据写入过程 数据查找过程 注意事项 kafka管理UI …

基于Springboot+Vue的高校学术交流平台 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

论文阅读笔记-LogME: Practical Assessment of Pre-trained Models for Transfer Learning

前言 在NLP领域,预训练模型(准确的说应该是预训练语言模型)似乎已经成为各大任务必备的模块了,经常有看到文章称后BERT时代或后XXX时代,分析对比了许多主流模型的优缺点,这些相对而言有些停留在理论层面,可是有时候对于手上正在解决的任务,要用到预训练语言模型时,面…

Spring Boot项目的创建与使用

1.通过IDE创建Spring Boot项目 2.目录结构 3.新建TestController控制器 Controller public class TestController {RequestMapping("/test")public ModelAndView test(RequestParam(name "name", defaultValue "刘德华") String name){ModelA…

Pikachu-unsafe upfileupload-getimagesize

什么是getimagesize()&#xff1f; getimagesize()是PHP中用于获取图像的大小和格式的函数。它可以返回一个包含图像的宽度、高度、类型和MIME类型的数组。 由于返回的这个类型可以被伪造&#xff0c;如果用这个函数来获取图片类型&#xff0c;从而判断是否时图片的话&#xff…

matplotlib字体警告

import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] "Arial" plt.rcParams["figure.figsize"] (3, 3) plt.rcParams[font.size] 12sc.pl.umap(adata_concat, color[batch_name, Ground Truth, mclust], ncols3, wspace0.5, showTrue)结果如…

谷歌 DeepMind 发布 AlphaChip:AI 加速芯片设计,效率提升惊人!

近日&#xff0c;谷歌 DeepMind 公布了其最新的 AI 系统 ——AlphaChip。这一系统致力于加速和优化计算机芯片的开发&#xff0c;AlphaChip 所设计的芯片布局已经在谷歌的 AI 加速器中得到应用。 AlphaChip 的工作原理类似于我们之前所听说的 AlphaGo 和 AlphaZero&#xff0c…

NASA:北极植被地块 ATLAS 项目 北坡和苏厄德半岛,明尼苏达州,1998-2000 年

目录 简介 摘要 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 Arctic Vegetation Plots ATLAS Project North Slope and Seward Peninsula, AK, 1998-2000 简介 文档修订日期&#xff1a;2018-12-31 数据集版本&#xff1a;1 本数据集提供了在北极陆地-大气系统…

模拟算法(5)_数青蛙

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 模拟算法(5)_数青蛙 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目链接…

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

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

旅游平台|智慧旅游平台|基于java的智慧旅游平台设计与实现(源码+数据库+文档)

智慧旅游平台 目录 基于java的智慧旅游平台设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;阿里云开发…