冒泡排序、插入排序、快速排序、堆排序、希尔排序、归并排序

目录

        • 冒泡排序
        • 插入排序
        • 快速排序(未优化版本)
        • 快速排序(优化版本)
        • 堆排序
        • 希尔排序
        • 归并排序
        • 各排序时间消耗对比

冒泡排序

冒泡排序核心逻辑就是对数组从第一个位置开始进行遍历,如果发现该元素比下一个元素大,则交换位置,如果不大,就拿着下一个比该元素大的元素向下继续比较,以此类推一直比较到最后,每一轮下来就会把当前最大的元素放到最后所以每一轮会确定一个最大元素。

    public void bubbleSort(int[] array) {for (int i = 0; i < array.length; i++) {int flag = 0;for (int j = 1; j < array.length-i; j++) {if (array[j - 1] > array[j]) {swap(array,j-1,j);flag = 1;}}if (flag == 0) {break;}}}

这里做了一个优化,当某一轮发现一个元素都没有移动的时候,就表示这个数组已经是有序的了,不理解的可以举一个已经有序的例子推敲一下,所以定义一个flag如果为0就表示一整伦下来都没有发生过移动直接跳出循环,排序完成。

时间复杂度:O(N^2)

稳定性:稳定

空间复杂度:O(1)

插入排序
    public void insertSort(int[] array) {for (int i = 1; i < array.length; i++) {int j = i - 1;int tmp = array[i];for (; j >= 0; j--) {if (array[j] >= tmp) {array[j+1] = array[j];} else {break;}}array[j+1] = tmp;}}

时间复杂度:O(N^2)

稳定性:稳定

空间复杂度:O(1)

快速排序(未优化版本)
	public void quickSort (int[] array) {quick(array,0,array.length-1);}private void quick(int[] array, int start, int end) {if (start >= end) {return;}// 一个是霍尔法一个是挖坑法,两个都可int part = partition1(array,start,end); // 霍尔法//int part = partition2(array,start,end); // 挖坑法quick(array,start,part-1);quick(array,part+1,end);}private int partition1(int[] array, int left, int right) {int tmp = array[left];int tmpIndex = left;while (left < right) {while (left < right && array[right] >= tmp) {right--;}while (left < right && array[left] <= tmp) {left++;}swap(array,left,right);}swap(array,tmpIndex,left);return left;}private int partition2(int[] array, int left ,int right) {int tmp = array[left];while (left < right) {while (left < right && array[right] >= tmp) {right--;}array[left] = array[right];while (left < right && array[left] <= tmp) {left++;}array[right] = array[left];}array[left] = tmp;return left;}

最好时间复杂度:O(N*logN)

最坏时间复杂度:O(N^2)

空间复杂度:O(logN)

稳定性:不稳定

快速排序(优化版本)
	public void quickSort (int[] array) {quick(array,0,array.length-1);}private void quick(int[] array, int start, int end) {if (start >= end) {return;}// 优化1(如果是少量的数据,直接插入排序速度是很快的,所以我们用直接插入排序处理数量小于等于15个的情况,不要小看这个优化,因为quickSort是树形的递归模式,在最后一层会有大量的数据存在,这个时候我们直接不进行递归直接进行插入排序可以节省大量的开销)if (end - start + 1 <= 15) {insertWithQuick(array,start,end);return;}// 优化2(三数取中优化,如果当一个数组比较趋于有序的情况下,那么构造出来的二叉树就是变成了一个链表,所以才会有时间复杂度区域O(N^2),我们只要打破这个顺序就好,我们直接去一个较为中间的值作为基准值就能均分了)int midIndex = findMidIndex(array,start,end);swap(array,start,midIndex);// 一个是霍尔法一个是挖坑法,两个都可int part = partition1(array,start,end); // 霍尔法//int part = partition2(array,start,end); // 挖坑法quick(array,start,part-1);quick(array,part+1,end);}private int partition1(int[] array, int left, int right) {int tmp = array[left];int tmpIndex = left;while (left < right) {while (left < right && array[right] >= tmp) {right--;}while (left < right && array[left] <= tmp) {left++;}swap(array,left,right);}swap(array,tmpIndex,left);return left;}private int partition2(int[] array, int left ,int right) {int tmp = array[left];while (left < right) {while (left < right && array[right] >= tmp) {right--;}array[left] = array[right];while (left < right && array[left] <= tmp) {left++;}array[right] = array[left];}array[left] = tmp;return left;}// 使用插入排序进行优化private void insertWithQuick(int[] array, int start, int end) {for (int i = start; i <= end; i++) {int j = i - 1;int tmp = array[i];for (; j >= start; j--) {if (array[j] >= tmp) {array[j+1] = array[j];} else {break;}}array[j+1] = tmp;}}// 使用三数取中找到中值下标private int findMidIndex(int[] array, int start, int end) {int midIndex = start + (end - start) / 2;if (array[start] > array[end]) {// end  startif (array[midIndex] < array[end]) {return end;} else if (array[midIndex] > array[start]) {return start;} else {return midIndex;}} else {// start  endif (array[midIndex] < array[start]) {return start;} else if (array[midIndex] > array[end]) {return end;} else {return midIndex;}}}

优化后的时间复杂度将会无限趋近于O(N*logN),空间复杂度不变

堆排序
    public void heapSort (int[] array) {createBigHeap(array);int end = array.length-1;while (end >= 0) {swap(array,0,end);end--;siftDown(array,0,end);}}private void createBigHeap(int[] array) {for (int parent = (array.length-2); parent >= 0; parent--) {siftDown(array,parent,array.length-1);}}private void siftDown(int[] array, int parent, int end) {int child = parent * 2 + 1;while (child <= end) {if (child + 1 <= end && array[child+1] > array[child]) {child++;}if (array[child] > array[parent]) {swap(array,child,parent);parent = child;child = child * 2 + 1;} else {break;}}}

时间复杂度:O(N*logN)

空间复杂度:O(logN)

稳定性:不稳定

希尔排序
    public void shallSort (int[] array) {int gap = array.length / 2;while (gap > 0) {shall(array,gap);gap /= 2;}}private void shall(int[] array, int gap) {for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i - gap;for (; j >= 0; j -= gap) {if (array[j] >= tmp) {array[j + gap] = array[j];} else {break;}}array[j+gap] = tmp;}}

希尔排序就是直接插入排序的升级版本

时间复杂度:不好计算业界公认的大概是O(N^1.3)

空间复杂度:O(1)

稳定性:不稳定

归并排序
    public void mergeSort(int[] array) {mergeFun(array,0,array.length-1);}private void mergeFun(int[] array, int start, int end) {if (start >= end) {return;}int midIndex = start + (end - start) / 2;mergeFun(array,start,midIndex);mergeFun(array,midIndex+1,end);// mergemerge(array, start, end, midIndex);}private void merge(int[] array, int start, int end, int midIndex) {int rs = midIndex + 1 , k = 0, tmpIndex = start;int[] tmpArray = new int[end - start +1];while (start <= midIndex && rs <= end) {if (array[start] < array[rs]) {tmpArray[k++] = array[start++];} else {tmpArray[k++] = array[rs++];}}while (start <= midIndex) {tmpArray[k++] = array[start++];}while (rs <= end) {tmpArray[k++] = array[rs++];}for (int j = tmpIndex; j <= end; j++) {array[j] = tmpArray[j - tmpIndex];}}

时间复杂度:O(N*logN)

空间复杂度:O(N)

稳定性:稳定

各排序时间消耗对比

为了更直观的观察每个排序有时间效率,我将这几个排序进行了一个对比,先随机生成要给数组大小为100000的随机数,随机数范围是0-10000,之后分别计算各个排序所消耗的时间单位是毫秒

public static void main(String[] args) {Sort sort = new Sort();// 原数组int[] array = createRandomNumber(100_000,10_000);// copy数组int[] array1 = Arrays.copyOf(array, array.length);long start1 = System.currentTimeMillis();sort.quickSort(array1);System.out.println("quickSort : " + (System.currentTimeMillis()-start1) );int[] array2 = Arrays.copyOf(array, array.length);long start2 = System.currentTimeMillis();sort.shallSort(array2);System.out.println("shallSort : " + (System.currentTimeMillis()-start2) );int[] array3 = Arrays.copyOf(array, array.length);long start3 = System.currentTimeMillis();sort.heapSort(array3);System.out.println("heapSort : " + (System.currentTimeMillis()-start3) );int[] array4 = Arrays.copyOf(array, array.length);long start4 = System.currentTimeMillis();sort.mergeSort(array4);System.out.println("mergeSort : " + (System.currentTimeMillis()-start4) );int[] array5 = Arrays.copyOf(array, array.length);long start5 = System.currentTimeMillis();sort.insertSort(array5);System.out.println("insertSort : " + (System.currentTimeMillis()-start5) );int[] array6 = Arrays.copyOf(array, array.length);long start6 = System.currentTimeMillis();sort.bubbleSort(array6);System.out.println("bubbleSort : " + (System.currentTimeMillis()-start6) );}private static int[] createRandomNumber (int size, int range) {int[] array = new int[size];for (int i = 0; i < size; i++) {array[i] = new Random().nextInt(range);}return array;}

在这里插入图片描述

所以大家还是少用冒泡吧,虽然简单但是效率感人~ 快排还是牛掰

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

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

相关文章

JavaScript:表单及正则表达式验证

今天我要介绍的是在JavaScript中关于表单验证内容的知识点介绍&#xff1a; 关于表单验证&#xff0c;我接下来则直接将内容以及效果显示出来并作注解&#xff0c;这样可以清晰看见这个表达验证的妙用&#xff1a; <form id"ff" action"https://www.baidu.…

天元证券|调仓曝光!首批科技基金一季报出炉

4月15日&#xff0c;中欧基金、永赢基金、长城基金等公募基金公司旗下部分权益类基金产品一季报出炉。 券商中国记者梳理发现&#xff0c;永赢信息产业智选混合主要聚焦信息技术领域布局&#xff0c;前十大重仓股中9只股票属于信息技术行业&#xff0c;合计占基金资产净值比例达…

SpringAI版本更新:向量数据库不可用的解决方案!

Spring AI 前两天&#xff08;4.10 日&#xff09;更新了 1.0.0-M7 版本后&#xff0c;原来的 SimpleVectorStore 内存级别的向量数据库就不能用了&#xff0c;Spring AI 将其全部源码删除了。 此时我们就需要一种成本更低的解决方案来解决这个问题&#xff0c;如何解决呢&…

Sklearn入门之datasets的基本用法

、 Sklearn全称:Scipy-toolkit Learn是 一个基于scipy实现的的开源机器学习库。它提供了大量的算法和工具&#xff0c;用于数据挖掘和数据分析&#xff0c;包括分类、回归、聚类等多种任务。本文我将带你了解并入门Sklearn下的datasets在机器学习中的基本用法。 获取方式 pi…

优化 Dockerfile 性能之实践(Practice of Optimizing Dockerfile Performance)

优化 Dockerfile 性能之实践 构建 Docker 镜像时&#xff0c;Dockerfile 的性能会显著影响构建过程的效率。经过优化的 Dockerfile 可以缩短构建时间、最小化镜像大小并提高整体容器性能。在本文中&#xff0c;我们将探讨优化 Dockerfile 性能的最佳实践。 尽量减少层数 影响…

出现 ERR_CERT_COMMON_NAME_INVALID | 301 302 重定向的解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 爬虫神器,无代码爬取,就来:bright.cn 1. 问题所示 执行代码时,出现如下提示: GET https://xxxx/admin-api/system

C语言 —— 指尖跃迁 刻印永恒 - 文件操作

目录 1. 什么是文件 1.1 程序文件 1.2 数据文件 1.3 文件名 2. 二进制文件和文本文件 3. 文件的打开与关闭 3.1 流和标准流 3.2 文件指针 3.3 文件的打开与关闭 fopen fclose 4. 文件的顺序读写 4.1 fgetc和fputc fgetc fputc 4.2 fgets和fputs fgets fputs…

用css给div列表加个序号

用 CSS 的 counter 相关属性来为列表添加序号。以下是具体的代码&#xff0c;我将以 HTML 文件的形式提供&#xff0c;并且会运行展示效果&#xff1a; .as-div {// counter-reset: my-counter; /* 计数器名称是my-counter */// counter-reset: small-apple; /* 计数器名称是s…

Rust : 关于*const () 与type erase

*const () 可以替代泛型&#xff0c;更加灵活。 一、 代码 //use std::mem::transmute; trait Work {fn process(&self); } struct Foo(String);impl Work for Foo {fn process(&self) {println!("process work from Foo : {}", self.0);} } struct Bar(S…

【专题刷题】双指针(二)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

吉尔吉斯斯坦工商会代表团赴齐河德瑞新能源汽车考察

德州齐河&#xff0c;2025年4月15日电 时中美贸易突变之际&#xff0c;乘国家一带一路之风。 展中国新能源之宏图&#xff0c;塑国贸体系之新方向。 今日上午&#xff0c;吉尔吉斯斯坦共和国工商会代表团一行三人受邀抵达济南&#xff0c;开启对德瑞新能源科技有限公司&…

【记录condapack打包环境到超算上顺利运行】

以安装CLRNet为例子 本地Linux系统上的操作步骤。 由于官方的安装包的步骤&#xff0c;执行condapack的时候会报错&#xff0c;所以使用以下步骤进行安装包。 安装其他 Python 依赖包 pip install -r requirements.txt✅ 二、构建并打包项目&#xff08;核心步骤&#xff…

Windows OpenUtau-v0.1.529-开源歌曲合成软件[提供MIDI编辑、歌词调整、音色修改 等功能,音乐创作者的必备工具]

Windows OpenUtau 链接&#xff1a;https://pan.xunlei.com/s/VONy_Refvo6_813Ig--nu5_rA1?pwdejzc# 引擎&#xff08;Resampler&#xff09;和拼接器&#xff08;Wavtool&#xff09;是UTAU协议中音频处理的两大组件。前端编辑器通过调用引擎和拼接器&#xff0c;对音频进行…

虚拟卡可以解决订阅 ChatGPT 时无法付款的问题

在全球掀起 AI 热潮的今天&#xff0c;因为工作的需要有些朋友要用ChatGPT&#xff0c;它也成为了不少人日常学习、工作、创作和编程的得力助手。然而&#xff0c;不少用户在尝试订阅 ChatGPT Plus&#xff08;付费版&#xff09;时&#xff0c;却遇到了一个令人头疼的问题——…

设计模式之状态模式:优雅管理对象行为变化

引言 状态模式&#xff08;State Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许对象在其内部状态改变时改变它的行为&#xff0c;使对象看起来似乎修改了它的类。状态模式将状态转移逻辑和状态相关行为封装在独立的状态类中&#xff0c;完美解决了复杂条件判断问…

【算法】归并排序

算法系列七&#xff1a;归并排序 一、归并排序的递归探寻 1.思路 2.搭建 2.1设计过掉不符情况&#xff08;在最底层时&#xff09; 2.2查验能实现基础排序&#xff08;在最底层往上点时&#xff09; 2.3跳转结果继续往上回搭 3.实质 4.实现 二、递归的调用栈 1.递归的…

线束线缆从二维设计到虚拟验证全流程解决方案

一、传统设计中的痛点 线缆的开发设计是横跨多专业多学科的庞大工程&#xff0c;通常会划分为几大阶段逐次推进&#xff0c;由于每个阶段的工作任务不同&#xff0c;所以在不同设计阶段使用的工具也完全不同&#xff0c;由此导致整个设计流程中工程师常常要跨平台协作&#xf…

【智驾中的大模型 -1】自动驾驶场景中的大模型

1. 前言 我们知道&#xff0c;大模型现在很火爆&#xff0c;尤其是 deepseek 风靡全球后&#xff0c;大模型毫无疑问成为为中国新质生产力的代表。百度创始人李彦宏也说&#xff1a;“2025 年可能会成为 AI 智能体爆发的元年”。 随着科技的飞速发展&#xff0c;大模型的影响…

个人博客系统后端 - 注册登录功能实现指南

一、功能概述 个人博客系统的注册登录功能包括&#xff1a; 用户注册&#xff1a;新用户可以通过提供用户名、密码、邮箱等信息创建账号用户登录&#xff1a;已注册用户可以通过用户名和密码进行身份验证&#xff0c;获取JWT令牌身份验证&#xff1a;使用JWT令牌访问需要认证…

投行交易与风控系统的消费侧幂等架构设计与实战

1.背景和痛点 1.1 资金操作敏感性场景 核心需求&#xff1a; 交易唯一性&#xff1a;资金类操作必须保证全局唯一执行计算原子性&#xff1a;风控指标计算需具备事务性特征审计追溯&#xff1a;所有操作需保留完整幂等轨迹 1.2 业务损失统计 二、技术挑战与架构设计 2.1 分…