七大基于比较的排序算法(JAVA)

news2024/11/26 10:42:11

目录

冒泡排序

优化:

堆排序

插入排序

希尔排序

归并排序

快速排序

优化

选择排序 


 排序算法的稳定性大小相同的元素在排序前后相对位置相同就称其为稳定的排序。

注:一个本身就是稳定的排序 是可以实现为不稳定的排序的 ;但是相反 一个本身就不稳定的排序 是不可能实现为稳定的排序的。

稳定的排序算法:插入排序 冒泡排序 归并排序

冒泡排序

时间复杂度: o(n^2)   如果加了优化  最好情况O(N)
空间复杂度:O(1)
稳定性: 稳定

    public static void bubbleSort(int[] array){

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

    private static void swap(int[] array, int minIndex, int i) {
        int tmp = array[i];
        array[i] = array[minIndex];
        array[minIndex] = tmp;
    }

优化:

     public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            boolean flg = false;
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j] > array[j+1]) {
                    swap(array,j,j+1);
                    flg = true;
                }
            }
            if(!flg) {
                return;
            }
        }
    }

堆排序

时间复杂度:O(n*logN)    N^1.3 -->
空间复杂度:O(1)
稳定性:不稳定
数据量非常 大的时候 堆排 一定比希尔快

堆排序的原理:

  1. 用一个大根堆的堆顶元素和最后一个元素交换
  2. 使数组长度减一
  3. 在重新将堆调整为大根堆

    public static void heapSort(int[] array){

        createHeap(array);
        for (int i = 0; i < array.length - 1; i++) {
            swap(array, 0, array.length-1-i);
            shiftDown(array, 0, array.length-1-i);
        }
    }

    private static void createHeap(int[] array) {
        for (int i = (array.length-1-1)/2; i >= 0; i--) {
            shiftDown(array, i, array.length);
        }
    }

    private static void shiftDown(int[] array, int i, int length) {//length个元素
        int child = i * 2 + 1;
        while (child < length) {
            if (child + 1 < length && array[child] < array[child+1]) {
                child++;
            }
            if (array[child] > array[i]) {
                swap(array, child, i);
                i = child;
            }else {
                break;
            }
            child = i * 2 + 1;
        }
    }
    private static void swap(int[] array, int minIndex, int i) {
        int tmp = array[i];
        array[i] = array[minIndex];
        array[minIndex] = tmp;
    }

插入排序

时间复杂度:
        最好情况:数据完全有序的时候 O(N)
        最坏情况:数据完全逆序的时候 O(N^2)
空间复杂度:O(1)
稳定性:稳定


插入排序的原理

  1. 从左边第一位开始挨个令其成为关键码
  2. 从左到右把待排序的记录按其关键码值的大小逐个插入到左边已经排好序的有序序列中
  3. 直到所有的记录插入完为止,得到一个新的有序序列
    public static void insertSort(int[] array){

        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];
            int j = i - 1;
            for (; j >= 0 ; j--) {
                //如果此处改为array[j] >= tmp就会变成不稳定排序
                if (array[j] > tmp) {
                    array[j+1] = array[j];
                }else{
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

希尔排序

时间复杂度:
             约等于:n^1.3 - n^1.5
复杂度:O(1)
稳定性:不稳定

希尔排序其实就是对插入排序的一种优化

基本原理:

  1. 先按照步长将数组分为若干组
  2. 对每组进行插入排序
  3. 减小步长重复以上步骤

    public static void shellSort(int[] array){

        int gap = array.length;
        while (gap > 1) {
            gap = gap / 2;
            shell(array, gap);
        }
    }

    private static void shell(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;
        }
    }

归并排序

时间复杂度: 0(N*logN)
空间复杂度:O(n)
稳定性: 稳定

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

可参考:icon-default.png?t=N7T8http://t.csdnimg.cn/Yd62c

    public void mergerSort(int[] nums, int left, int right) {//right:数组长度减一
        if (left >= right) {
            return;
        }
        int mid = (left + right) / 2;
        mergerSort(nums, left, mid);
        mergerSort(nums, mid + 1, right);
        merger(nums, left, mid, right);
    }

    private void merger(int[] nums, int left, int mid, int right) {
        int[] tmp = new int[right-left+1];
        int i = 0;
        int l = left;
        int r = mid + 1;
        while (l <= mid && r <= right) {
            if (nums[l] < nums[r]) {
                tmp[i++] = nums[l++];
            }else {
                tmp[i++] = nums[r++];
            }
        }
        while (l <= mid) {
            tmp[i++] = nums[l++];
        }
        while (r <= right) {
            tmp[i++] = nums[r++];
        }
        i = 0;
        for (int j = 0; j < tmp.length; j++) {
            nums[left++] = tmp[j];
        }
    }

快速排序

时间复杂度:
        最好情况:O(N*logN)   满二叉树/完全二叉树
        最坏情况:O(N^2) 单分支的树
空间复杂度:
        最好情况:O(logN)   满二叉树/完全二叉树
        最坏情况:O(N)   单 分支的树
稳定性:不稳定

快速排序基本原理

  1. 任取待排序元素序列中的某元素作为基准值
  2. 按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值
  3. 每个子序列重复该过程,直到所有元素都排列在相应位置上为止

有Hoare法   挖坑版法  前后指针法
这里只介绍Hoare法

    public static void quickSort(int[] array){

        quick(array, 0, array.length-1);
    }

    private static void quick(int[] array, int left, int right) {
        if (left >= right) {
            return;
        }
        int Index = findSwap(array, left, right);
        quick(array, left, Index-1);
        quick(array, Index+1, right);

    }
    
    private static int findSwap(int[] array, int left, int right) {
        int key = array[left];
        int keyIndex = left;
        while (left < right) {
            //必须right先走
            //如果是left先走,两个相遇的地方一定比key大
            while (left < right && array[right] >= key) {
                right--;
            }
            while (left < right && array[left] <= key) {
                left++;
            }
            swap(array, right, left);
        }
        if (left == right) {
            swap(array, keyIndex, left);
        }
        return left;
    }

    private static void swap(int[] array, int minIndex, int i) {
        int tmp = array[i];
        array[i] = array[minIndex];
        array[minIndex] = tmp;
    }

优化

利用三数取中法来避免但分支书的形成(尽量降低树的高度)

    public int[] sortArray(int[] nums) {
        //快速排序
        quickSort(nums, 0, nums.length-1);
        return nums;
    }

    private void quickSort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        //三数取中法
        swap(nums, left, threeNumMid(nums, left, right));
        //也可以在这里加一个判断当左右之间的数据个数小于一定值然后调用插入排序
        //因为在排序过程中数组会趋近于有序所以插入排序的效率会很快
        int pivot = quick(nums, left, right);
        quickSort(nums, left, pivot-1);
        quickSort(nums, pivot+1, right);
    }

    private int threeNumMid(int[] nums, int left, int right) {
        int mid = (left + right) / 2;
        if (nums[left] > nums[right]) {
            if (nums[mid] > nums[left]) {
                return left;
            }else if (nums[mid] < nums[right]) {
                return right;
            }else {
                return mid;
            }
        }else {
            if (nums[mid] < nums[left]) {
                return left;
            }else if (nums[mid] > nums[right]) {
                return right;
            }else {
                return mid;
            }
        }
    }

    private int quick(int[] nums, int left, int right) {
        int index = left;
        int key = nums[left];
        while (left < right) {
            while (left < right && nums[right] >= key) {
                right--;
            }
            while (left < right && nums[left] <= key) {
                left++;
            }
            swap(nums, right, left);
        }
        swap(nums, index, left);
        return left;
    }

    private void swap(int[] nums, int left, int right) {
        int tmp = nums[left];
        nums[left] = nums[right];
        nums[right] = tmp;
    }

选择排序 

时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:不稳定的排序

选择排序基本原理:

  1. 从左至右每一次从待排序的数据元素中选出最小(或最大)的一个元素
  2. 将其放在待排序元素的起始位置,已有序元素的最后边
  3. 重复上述步骤直到全部待排序的数据元素排完 。
    public static void selectSort(int[] array){

        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i+1; j < array.length; j++) {
                if (array[minIndex] > array[j]) {
                    minIndex = j;
                }
            }
            swap(array, minIndex, i);
        }
    }

    private static void swap(int[] array, int minIndex, int i) {
        int tmp = array[i];
        array[i] = array[minIndex];
        array[minIndex] = tmp;
    }

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

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

相关文章

JavaSE学习之--抽象类,接口,内部类

&#x1f495;"没有眼泪我们就会迷路&#xff0c;彻底变成石头&#xff0c;我们的心会变成冰凌&#xff0c;吻会变成冰块。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JavaSE学习之--抽象类&#xff0c;接口&#xff0c;内部类 目录 一.抽象…

【牛客网】OR59 字符串中找出连续最长的数字串

题目 思路 创建两个字符串 temp 和 ret 创建指针i用来遍历字符串通过i遍历字符串,如果遇到数字则将这个数组加到字符串temp中 i,如果遇到字母,则判断temp字符串的长度和ret字符串的长度,如果temp<ret则说明这个字符串不是要的字符串,如果temp>ret则说明此时temp字符串是…

线性表的链式存储结构——链表

一、顺序表优缺点 优点&#xff1a;我们知道顺序表结构简单&#xff0c;便于随机访问表中任一元素&#xff1b; 缺点&#xff1a;顺序存储结构不利于插入和删除&#xff0c;不利于扩充&#xff0c;也容易造成空间浪费。 二、链表的定义 ①&#xff1a;概念&#xff1a; 用一组任…

springmvc-页面跳转表单标签其他标签tomcat控制台中文乱码问题

1. WEB-INF下页面跳转 容器启动后&#xff0c;如何默认显示web-inf目录下的系统首页。 2. ModelAttribute来注解非请求处理方法 用途&#xff1a;预加载数据&#xff0c;会在每个RequestMapping方法执行之前调用。 特点&#xff1a;无需返回视图&#xff0c;返回类型void 示例…

【计算机网络黑皮书】应用层

【事先声明】 这是对于中科大的计算机网络的网课的学习笔记&#xff0c;感谢郑烇老师的无偿分享 书籍是《计算机网络&#xff08;自顶向下方法 第6版&#xff09;》 需要的可以私信我&#xff0c;无偿分享&#xff0c;课程简介下也有 课程连接 目录 应用层网络应用的原理应用架…

[BJDCTF2020]The mystery of ip

打开环境 点击flag&#xff0c;提示ip&#xff0c;这里确实就比较容易联想到x-forwarded-for 点击hint 这个好像没啥用 使用bp抓包 添加请求头 X-Forwarded-For:1 试一下 发现ip可控 后来查了发现 PHP可能存在Twig模版注入漏洞 参考https://www.cnblogs.com/zzjdbk/p/13…

Scala第十七章节

Scala第十七章节 scala总目录 文档资料下载 章节目标 了解集合的相关概念掌握Traversable集合的用法掌握随机学生序列案例 1. 集合 1.1 概述 但凡了解过编程的人都知道程序 算法 数据结构这句话, 它是由著名的瑞士计算机科学家尼古拉斯沃斯提出来的, 而他也是1984年图灵…

ADO连接Access的前期绑定方法实例(下)

【分享成果&#xff0c;随喜正能量】眾生多悲苦&#xff0c;發願‬菩提心。願今天所有聽見我、看見我、憶念我的眾生&#xff0c;因我心而‬生喜悅&#xff01;除消身心的痛苦&#xff01;種下脫解‬的種子&#xff01;願我等‬身心念力所及之處一切眾切‬生因佛得度&#xff0…

【AI视野·今日CV 计算机视觉论文速览 第258期】Mon, 2 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Mon, 2 Oct 2023 (showing first 100 of 112 entries) Totally 100 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Multi-task View Synthesis with Neural Radiance Fields Authors Shuhong Zheng, Zh…

Vue的模板语法

Vue的模板语法 Vue 使用一种基于 HTML 的模板语法&#xff0c;使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML&#xff0c;可以被符合规范的浏览器和 HTML 解析器解析。 测试准备 为了方便测试&#xff0c;先将vue-base项…

【AI视野·今日Robot 机器人论文速览 第四十五期】Mon, 2 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Mon, 2 Oct 2023 Totally 42 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Learning Decentralized Flocking Controllers with Spatio-Temporal Graph Neural Network Authors Siji Chen, Yanshen Sun, …

守护进程解析

什么是守护进程&#xff1f; - 知乎 什么是守护进程&#xff1a;生存期长的一种进程&#xff0c;没有控制终端。它们常常在系统引导装入时启动&#xff0c;仅在系统关闭时才终止。 进程组 &#xff1a; 每个进程除了有一个进程ID之外&#xff0c;还属于一个进程组进程组是一…

【已解决】opencv 交叉编译 ffmpeg选项始终为NO

一、opencv 交叉编译没有 ffmpeg &#xff0c;会导致视频打不开 在交叉编译时候&#xff0c;发现在 pc 端能用 opencv 打开的视频&#xff0c;但是在 rv1126 上打不开。在网上查了很久&#xff0c;原因可能是 交叉编译过程 ffmpeg 造成的。之前 ffmpeg 是直接用 apt 安装的&am…

LeetCode 周赛上分之旅 #49 再探内向基环树

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

1300*C. Coin Rows(枚举模拟)

解析&#xff1a; 两人都绝对聪明&#xff0c;Alice先走&#xff0c;尽量让Bob所能拿的分数最少&#xff0c;Alice有一次往下走的机会&#xff0c;剩余没走过的点正好分为两断断开的区域&#xff0c;所以Bob的最大分数要么在第一格向下或者在最后一列向下。 遍历区间&#xff0…

笔训day2

选择题 1、输出格式 此题与昨天的题类似&#xff0c;有“-”号时是左对齐&#xff0c;%-m.n m表示宽度&#xff0c;n表示左起取n位数。 2、常量指针和指针常量 //两种都是常量指针 const int *p1; int const *p2; //指针常量 int* const p3 3、字符数组和字符指针 4、函数…

国庆节看这里,有你意想不到的收货!(建议收藏)

计算机视觉研究院专栏 作者&#xff1a;Edison_G “国庆长假&#xff0c;每个人都安耐不住了&#xff0c;但是&#xff0c;在你静心、游玩的时候&#xff0c;还是可以阅读今天的分享&#xff0c;干货满满&#xff01; 公众号ID&#xff5c;ComputerVisionGzq 学习群&#xff5c…

基于SSM的医院住院综合服务管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

数据结构与算法(C语言版)P9---哈夫曼树

1、哈夫曼树的基本概念 &#xff08;1&#xff09;路径&#xff1a;从树中一个结点到另一个结点之间的__分支__构成这两个结点间的路径。 &#xff08;2&#xff09;__结点的路径长度&#xff1a;__两结点间路径上的分支树。 练习&#xff1a;计算下面二叉树结点之间的路径长…

1.7.C++项目:仿muduo库实现并发服务器之Poller模块的设计

项目完整在&#xff1a; 文章目录 一、Poller模块&#xff1a;描述符IO事件监控模块二、提供的功能三、实现思想&#xff08;一&#xff09;功能&#xff08;二&#xff09;意义&#xff08;三&#xff09;功能设计 四、封装思想五、代码&#xff08;一&#xff09;框架&#…