时间复杂度为 O(n^2) 的排序算法

news2024/11/26 14:35:40

大家好,我是 方圆。对于小规模数据,我们可以选用时间复杂度为 O(n2) 的排序算法,因为时间复杂度并不代表实际代码的执行时间,而且它也省去了低阶、系数和常数,仅代表的增长趋势,所以在小规模数据情况下, O(n2) 的排序算法可能会比 O(nlogn) 的排序算法执行效率高。不过随着数据规模增大, O(nlogn) 的排序算法是不二选择。本篇我们主要对 O(n2) 的排序算法进行介绍,在介绍之前,我们先了解一下算法特性:

  • 算法特性:

    • 稳定性:经排序后,若等值元素之间的相对位置不变则为稳定排序算法,否则为不稳定排序算法

    • 原地排序:是否借助额外辅助空间

    • 自适应性: 自适应性排序受输入数据的影响,即最佳/平均/最差时间复杂度不等,而非自适应排序时间复杂度恒定

本篇我们将着重介绍插入排序,选择排序和冒泡排序了解即可。

插入排序

插入排序的工作方式像 整理手中的扑克牌一样,即不断地将每一张牌插入到其他已经有序的牌中适当的位置。

插入排序的当前索引元素左侧的所有元素都是有序的:若当前索引为 i,则 [0, i - 1] 区间内的元素始终有序,这种性质被称为 循环不变式,即在第一次迭代、迭代过程中和迭代结束时,这种性质始终保持不变。

不过,这些有序元素的索引位置暂时不能确定,因为它们可能需要为更小的元素腾出空间而向右移动。插入排序的代码实现如下:

    private void sort(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            int base = nums[i];

            int j = i - 1;
            while (j >= 0 && nums[j] > base) {
                nums[j + 1] = nums[j--];
            }
            nums[j + 1] = base;
        }
    }

它的实现逻辑是取未排序区间中的某个元素为基准数 base,将 base 与其左侧已排序区间元素依次比较大小,并"插入"到正确位置。插入排序对 部分有序(数组中每个元素距离它的最终位置都不远或数组中只有几个元素的位置不正确等情况)的数组排序效率很高。事实上,当逆序很少或数据量不大(n2和nlogn比较接近)时,插入排序可能比其他任何排序算法都要快,这也是一些编程语言的内置排序算法在针对小数据量数据排序时选择使用插入排序的原因。

算法特性:

  • 空间复杂度:O(1)

  • 原地排序

  • 稳定排序

  • 自适应排序:当数组为升序时,时间复杂度为 O(n);当数组为降序时,时间复杂度为 O(n2)

希尔排序

插入排序对于大规模乱序数组排序很慢,因为它只会交换相邻的元素,所以元素只能一步步地从一端移动到另一端,如果最小的元素恰好在数组的最右端,要将它移动到正确的位置需要移动 N - 1 次。

希尔排序是基于插入排序改进的排序算法,它可以交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。它的思想是使数组中间隔为 h 的元素有序(h 有序数组),如下图为间隔为 4 的有序数组:

希尔排序.jpg

排序之初 h 较大,这样我们能将较小的元素尽可能移动到靠近左端的位置,为实现更小的 h 有序创造便利,最后一次循环时 h 为 1,便是我们熟悉的插入排序。这就是希尔排序的过程,代码实现如下:

    private void sort(int[] nums) {
        int N = nums.length;
        int h = 1;
        while (h < N / 3) {
            h = 3 * h + 1;
        }

        while (h >= 1) {
            for (int i = h; i < N; i++) {
                int base = nums[i];

                int j = i - h;
                while (j >= 0 && nums[j] > base) {
                    nums[j + h] = nums[j];
                    j -= h;
                }
                nums[j + h] = base;
            }

            h /= 3;
        }
    }

希尔排序更高效的原因是它权衡了子数组的规模和有序性,它也可以用于大型数组。排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。


选择排序

选择排序的实现非常简单:每次选择未排序数组中的最小值,将其放到已排序区间的末尾,代码实现如下:

    private void sort(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            int min = i;
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[j] < nums[min]) {
                    min = j;
                }
            }
            swap(nums, i, min);
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

算法特性:

  • 空间复杂度:O(1)

  • 原地排序

  • 非稳定排序:会改变等值元素之间的相对位置

  • 非自适应排序:最好/平均/最坏时间复杂度均为 O(n2)

冒泡排序

冒泡排序通过 连续地比较与交换相邻元素实现排序,每轮循环会将未被排序区间内的最大值移动到数组的最右端,这个过程就像是气泡从底部升到顶部一样,代码实现如下:

    public void sort(int[] nums) {
        for (int i = nums.length - 1; i > 0; i--) {
            // 没有发生元素交换的标志位
            boolean flag = true;
            for (int j = 0; j < i; j++) {
                if (nums[j] > nums[j + 1]) {
                    swap(nums, j, j + 1);
                    flag = false;
                }
            }

            if (flag) {
                break;
            }
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

算法特性:

  • 空间复杂度:O(1)

  • 原地排序

  • 稳定排序

  • 自适应排序:经过优化后最佳时间复杂度为 O(n)


巨人的肩膀

  • 《算法导论 第三版》第 2.1 章

  • 《算法 第四版》第 2.1 章

  • 《Hello 算法》第 11 章

  • 排序算法-希尔排序

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

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

相关文章

PAM从入门到精通(一)

本文参考以下博文&#xff1a; PAM模块详解及sudo命令 PAM 的应用开发和内部实现源码分析 PAM详解&#xff08;一&#xff09;PAM介绍 百度百科 —— PAM Oracle Solaris 10 开发者安全性指南 —— PAM 框架介绍 特此致谢&#xff01; 零、引言 身份认证是操作系统安全的…

Oracle-truncate误删数据恢复

前言&#xff1a; truncate操作误删数据之后想恢复数据通常比较困难&#xff0c;因为truncate操作属于ddl操作无法使用直接undo闪回查询方式恢复数据&#xff0c;并且由于空间大小、备份时间以及变更操作不规范原因&#xff0c;往往在执行操作之前没有对表进行CTAS备份或者其他…

【Java】枚举 Enum

枚举 Enum 枚举的使用Enum 类的常用方法枚举优缺点用枚举实现一个单例模式 枚举的主要用途是&#xff1a;将一组常量组织起来&#xff0c;在这之前表示一组常量通常使用定义常量的方式&#xff1a; public static int final RED 1; public static int final GREEN 2; publi…

vue3 状态管理pinia

1. 什么是Pinia Pinia 是 Vue 的专属的最新状态管理库 &#xff0c;是 Vuex 状态管理工具的替代品 特点优势: 提供更加简单的API(去掉了mutation)提供符合组合式风格的API(和Vue3新语法统一)去掉modules的概念,每一个store都是一个独立的模块配合TypeScript更加友好,提供可靠的…

微信里写周报添加到公司办公平台的方法

概要 微信和公司用的办公平台互通&#xff0c;我们已经说过几篇。 这次将给大家介绍&#xff0c;如何在微信里写周报内容&#xff0c;添加到公司办公平台的周报应用里。 工作中&#xff0c;如果出差在外&#xff0c;或者回到家想要汇报一周的工作情况的时候&#xff0c;不用…

Druid连接池最小连接数设置失效问题

问题发现&#xff1a; 配置 当项目启动后 线程池确实是初始化了5条连接&#xff0c;但是当项目运行一段时间后&#xff0c;5条连接确消失了&#xff0c;只会程序用到得时候&#xff0c;再去初始化连接&#xff0c;这样有点违背了参数设置得意义&#xff0c;后来通过查阅资料发…

简单好用的文档管理系统MinDoc

什么是 MinDoc &#xff1f; MinDoc 是一款针对 IT团队开发的简单好用的文档管理系统。MinDoc 的前身是 SmartWiki 文档系统。SmartWiki 是基于 PHP 框架 laravel 开发的一款文档管理系统。因 PHP 的部署对普通用户来说太复杂&#xff0c;所以改用 Golang 开发。可以方便用户部…

vue 01

安装vscode 按照如下方式汉化 给vscode 安装插件 Vetur 安装node.js 下载地址https://nodejs.org/en/download/&#xff0c;选择windows msi 在cmd下检查如下&#xff1a; 检查nodejs版本:node --version 检查npm的安装版本&#xff1a;npm -v 执行命令&#xff1a; npm i…

学习rsync

文章目录 一、rsync介绍二、rsync的特点三、本地文件同步四、远程文件同步五、免密文件同步和更改端口后的文件同步六、rsync作为系统服务七、应用举例七、给rsync服务添加密码八、rsync搭配inotify进行实时同步九、xinetd托管rsyncd服务 一、rsync介绍 1.sync同步&#xff1a…

Python玫瑰花

系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮爱心https://want…

常见的作物模型应用技巧!DSSAT模型、APSIM模型、WOFOST模型与PCSE模型等应用

①最新DSSAT作物模型建模方法及应用 DSSAT模型内核算法是基于Fortran语言开发的&#xff0c;软件界面是基于C进行开发。了解和熟悉DSSAT模型的关键算法和软件的操作是学习DSSAT模型的基础。此外&#xff0c;想要成为一名优秀的作物模型使用者与科研团队不可或缺的人才&#xff…

Windows 安装 nvm 提示 ‘“node“‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Windows 安装 nvm 提示 ‘“node”’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 解决办法 先卸载电脑中原有 nodejs 版本&#xff0c;再安装 nvm 即可。 安装完成之后记得重新打开终端 使用 安装 nodejs 18 添加环境变量 在 Path 里添加这两个变量名 结果 现…

XPS测试常见问题及解答(二)-科学指南针

在做X 射线光电子能谱(XPS)测试时&#xff0c;科学指南针检测平台工作人员在与很多同学沟通中了解到&#xff0c;好多同学仅仅是通过文献或者师兄师姐的推荐对XPS测试有了解&#xff0c;但是对于其原理还属于小白阶段&#xff0c;针对此&#xff0c;科学指南针检测平台团队组织…

认识京东联盟API,获取APPkey和APPsecret|直接调用KEY方式

做过淘客开发的一定接触过淘宝API开发。 而做京东联盟软件自然离不开京东联盟API。 京东联盟API目前上线的有很多。京东平台商品API。 https://jos.jd.com/api/list.htm?id117 Paste_Image.png 但是京东联盟API获取比较难&#xff0c;没办法在线申请&#xff0c;需要找官方…

NuGet包使用方法

NuGet包使用方法 必备条件 安装包括 dotnet CLI 的 .NET Core SDK。 从 Visual Studio 2017 开始&#xff0c;dotnet CLI 将自动随任何与 .NET Core 相关的工作负载一起安装。 如果你还没有帐户&#xff0c;请在 nuget.org 上注册一个免费帐户。 创建新帐户会发送确认电子邮…

Everything和SVN结合使用-在Everything中显示SVN

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

实录分享 | Alluxio 在网易大数据的应用与优化

欢迎来到【微直播间】&#xff0c;2min纵览大咖观点 本次分享主要包括四个方面&#xff1a; 背景介绍&#xff1b;对象存储场景优化&#xff1b;Impala 引擎适配&#xff1b;通用功能增强。 一、 背景介绍 网易有数大数据基础平台NDH&#xff1a;NDH 是网易对标 Cloudera C…

【Linux学习笔记】代码编译工具gcc/g++

1. 程序的翻译1.1. 预处理1.2. 编译1.3. 汇编1.4. 链接 2. 动态链接和静态链接2.1. 动态链接2.2. 静态链接2.3. 动态链接和静态链接的区别2.4. 动态链接和静态链接的验证 3. make/makefile3.1. 依赖方法和依赖关系3.2. 写一个makefile文件3.3. PHONY的意义3.4. makefile的推导规…

Ubuntu:VS Code IDE安装ESP-IDF【保姆级】(草稿)

物联网开发学习笔记——目录索引 Visual Studio Code&#xff08;简称“VS Code”&#xff09;是Microsoft向开发者们提供的一款真正的跨平台编辑器。 参考&#xff1a; VS Code官网&#xff1a;Visual Studio Code - Code Editing. Redefined 乐鑫官网&#xff1a;ESP-IDF …

[网站部署03]宝塔+worldPress部署Ripro主题网站

1.下载好主题网站上传到下方目录即可 下载地址&#xff1a;请自行百度搜索&#xff0c;官网收费 下载好压缩包上传到/www/wwwroot/你的网站目录/wp-content/themes 2.回到Worldpress后台点击外观可以看到主题网站 http://192.168.49.128/wp-admin/themes.php 剩下的就是设置…