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

news2025/5/24 23:07:57

目录

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

冒泡排序

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

    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  start
            if (array[midIndex] < array[end]) {
                return end;
            } else if (array[midIndex] > array[start]) {
                return start;
            } else {
                return midIndex;
            }
        } else {
            // start  end
            if (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);

        // merge
        merge(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.coloradmin.cn/o/2336608.html

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

相关文章

CD27.【C++ Dev】类和对象 (18)友元和内部类

目录 1.友元 友元函数 几个特点 友元类 格式 代码示例 2.内部类(了解即可) 计算有内部类的类的大小 分析 注意:内部类不能直接定义 内部类是外部类的友元类 3.练习 承接CD21.【C Dev】类和对象(12) 流插入运算符的重载文章 1.友元 友元函数 在CD21.【C Dev】类和…

QT安装详细步骤

下载 清华源 &#xff1a; 清华源 1. 2. 3. 4.

Unity游戏多语言工具包

由于一开始的代码没有考虑多语言场景&#xff0c;导致代码中提示框和UI显示直接用了中文&#xff0c;最近开始提取代码的中文&#xff0c;提取起来太麻烦&#xff0c;所以拓展了之前的多语言包&#xff0c;降低了操作复杂度。最后把工具代码提取出来到单独项目里面&#xff0c;…

实验三 I/O地址译码

一、实验目的 掌握I/O地址译码电路的工作原理。 二、实验电路 实验电路如图1所示&#xff0c;其中74LS74为D触发器&#xff0c;可直接使用实验台上数字电路实验区的D触发器&#xff0c;74LS138为地址译码器&#xff0c; Y0&#xff1a;280H&#xff5e;287H&…

视觉语言导航(VLN):连接语言、视觉与行动的桥梁

文章目录 1. 引言&#xff1a;什么是VLN及其重要性&#xff1f;2. VLN问题定义3. 核心挑战4. 基石&#xff1a;关键数据集与模拟器5. 评估指标6. 主要方法与技术演进6.1 前CLIP时代&#xff1a;奠定基础6.2 后CLIP时代&#xff1a;视觉与语言的统一 7. 最新进展与前沿趋势 (202…

计算机网络中科大 - 第7章 网络安全(详细解析)-以及案例

目录 &#x1f6e1;️ 第8章&#xff1a;网络安全&#xff08;Network Security&#xff09;优化整合笔记&#x1f4cc; 本章学习目标 一、网络安全概念二、加密技术&#xff08;Encryption&#xff09;1. 对称加密&#xff08;Symmetric Key&#xff09;2. 公钥加密&#xff0…

XCTF-web(四)

unserialize3 需要反序列化一下&#xff1a;O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;} php_rce 题目提示rce漏洞&#xff0c;测试一下&#xff1a;?s/Index/\think\app/invokefunction&functioncall_user_func_array&vars[0]phpinfo&vars[1][]1 flag&#xff1…

在Vue项目中查询所有版本号为 1.1.9 的依赖包名 的具体方法,支持 npm/yarn/pnpm 等主流工具

以下是 在Vue项目中查询所有版本号为 1.1.9 的依赖包名 的具体方法&#xff0c;支持 npm/yarn/pnpm 等主流工具&#xff1a; 一、使用 npm 1. 直接过滤依赖树 npm ls --depth0 | grep "1.1.9"说明&#xff1a; npm ls --depth0&#xff1a;仅显示直接依赖&#xf…

若依微服务版启动小程序后端

目录标题 本地启动&#xff0c;dev对应 nacos里的 xxx-xxx-dev配置文件 本地启动&#xff0c;dev对应 nacos里的 xxx-xxx-dev配置文件

莒县第六实验小学:举行“阅读世界 丰盈自我”淘书会

4月16日&#xff0c;莒县第六实验小学校园内书香四溢、笑语盈盈&#xff0c;以“阅读世界 丰盈自我”为主题的第二十四届读书节之“淘书会”活动火热开启。全校师生齐聚一堂&#xff0c;以书会友、共享阅读之乐&#xff0c;为春日校园增添了一抹浓厚的文化气息。 活动在悠扬的诵…

国产数据库与Oracle数据库事务差异分析

数据库中的ACID是事务的基本特性&#xff0c;而在Oracle等数据库迁移到国产数据库国产中&#xff0c;可能因为不同数据库事务处理机制的不同&#xff0c;在迁移后的业务逻辑处理上存在差异。本文简要介绍了事务的ACID属性、事务的隔离级别、回滚机制和超时机制&#xff0c;并总…

C++学习记录:

今天我们来学习一门新的语言&#xff0c;也是C语言最著名的一个分支语言&#xff1a;C。 在C的学习中&#xff0c;我们主要学习的三大组成部分&#xff1a;语法、STL、数据结构。 C的介绍 C的历史可追溯至1979年&#xff0c;当时贝尔实验室的本贾尼斯特劳斯特卢普博士在面对复杂…

等离子体浸没离子注入(PIII)

一、PIII 是什么&#xff1f;基本原理和工艺 想象一下&#xff0c;你有一块金属或者硅片&#xff08;就是做芯片的那种材料&#xff09;&#xff0c;你想给它的表面“升级”&#xff0c;让它变得更硬、更耐磨&#xff0c;或者有其他特殊功能。怎么做呢&#xff1f;PIII 就像是用…

idea中提高编译速度研究

探索过程&#xff1a; 有三种情况&#xff1a; 第一种&#xff1a; idea中用eclipse编译器编译springboot项目&#xff0c;然后debug启动Application报错找不到类。 有待继续研究。 第二种&#xff1a; idea中用javac编译器编译springboot项目&#xff0c;重新构建用时&a…

静态链接part2

编译 语义分析 由语义分析器完成&#xff0c;这个步骤只是完成了对表达式的语法层面的分析&#xff0c;它并不了解这个语句是否真的有意义&#xff08;例如在C语言中两个指针做乘法运算&#xff0c;这个语句在语法上是合法的&#xff0c;但是没有什么意义&#xff1b;还有同样…

Vue3+Vite+TypeScript+Element Plus开发-17.Tags-组件构建

系列文档目录 Vue3ViteTypeScript安装 Element Plus安装与配置 主页设计与router配置 静态菜单设计 Pinia引入 Header响应式菜单缩展 Mockjs引用与Axios封装 登录设计 登录成功跳转主页 多用户动态加载菜单 Pinia持久化 动态路由 -动态增加路由 动态路由-动态删除…

3D语义地图中的全局路径规划!iPPD:基于3D语义地图的指令引导路径规划视觉语言导航

作者&#xff1a; Zehao Wang, Mingxiao Li, Minye Wu, Marie-Francine Moens, Tinne Tuytelaars 单位&#xff1a;鲁汶大学电气工程系&#xff0c;鲁汶大学计算机科学系 论文标题&#xff1a; Instruction-guided path planning with 3D semantic maps for vision-language …

ShellScript脚本编程

语法基础 脚本结构 我们先从这个小demo程序来窥探一下我们shell脚本的程序结构 #!/bin/bash# 注释信息echo_str"hello world"test(){echo $echo_str }test echo_str 首先我们可以通过文本编辑器(在这里我们使用linux自带文本编辑神器vim)&#xff0c;新建一个文件…

【HarmonyOS 5】敏感信息本地存储详解

【HarmonyOS 5】敏感信息本地存储详解 前言 鸿蒙其实自身已经通过多层次的安全机制&#xff0c;确保用户敏感信息本地存储安全。不过再此基础上&#xff0c;用户敏感信息一般三方应用还需要再进行加密存储。 本文章会从鸿蒙自身的安全机制进行展开&#xff0c;最后再说明本地…

探索鸿蒙沉浸式:打造无界交互体验

一、鸿蒙沉浸式简介 在鸿蒙系统中&#xff0c;沉浸式是一种极具特色的设计理念&#xff0c;它致力于让用户在使用应用时能够全身心投入到内容本身&#xff0c;而尽可能减少被系统界面元素的干扰。通常来说&#xff0c;就是将应用的内容区巧妙地延伸到状态栏和导航栏所在的界面…