排序-八大排序FollowUp

news2024/11/17 23:36:38

FollowUp

1.插入排序

(1).直接插入排序

时间复杂度:
最坏情况下:0(n^2)
最好情况下:0(n)
当数据越有序 排序越快

适用于: 待排序序列 已经基本上趋于有序了!
空间复杂度:0(1)
稳定性:稳定的

   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--) {
                    //这里加不加等号 和稳定有关系
                    // 但是:本身就是一个稳定的排序 可以实现为不稳定的排序
                    // 但是 本身就是一个不稳定的排序 是不可能变成一个稳定的排序的
                if(array[j] > tmp){
                    array[j + 1] = array[j];
                }else {
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

 (2).希尔排序(缩小增量排序)

重点是最后还是会把整体作一组来直接插入排序

  public static void shellSort(int[] array){
        int gap = array.length;
        while(gap > 1){
            shell(array,gap);
            gap /= 2;
        }
    }
    public 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;
        }
    }

 2.选择排序

(1).直接选择排序

在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

    public static void selectSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            int mixIndex = i;
            for (int j = i+1; j < array.length; j++) {
                if(array[mixIndex] > array[j]){
                    mixIndex = j;
                }
            }
            int tmp = array[i];
            array[i] = array[mixIndex];
            array[mixIndex] = tmp;
        }
    }

【直接选择排序的特性总结】
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

(2.)双向选择排序:

 public static void selectSort2(int[] array){

        int left = 0;
        int right = array.length-1;
        while(left < right){
            int minIndex = left;
            int maxIndex = left;
            for (int i = left+1; i < right; i++) {
                if(array[i] > array[maxIndex]){
                    maxIndex = i;
                }
                if(array[i] < array[minIndex]){
                    minIndex = i;
                }
                swap(array,left,minIndex);
                //防止最大的是在第一个的时候
                if(maxIndex == left){
                    maxIndex = minIndex;
                }
                swap(array,right,maxIndex);
                left++;
                right--;

            }
        }
    }

(3).堆排序

具体的思路在PriorityQueue(一)——用堆实现优先级队列

    public static void heapSort(int[] array){
        creatHeap(array);
        int end = array.length-1;
        while(end > 0){
           swap(array,0,end);
           siftDown(array,0,end);
           end--;
        }
    }

    private static void creatHeap(int[] array) {
        for (int parent = (array.length-1-1)/2; parent >= 0 ; parent--) {
            siftDown(array,parent,array.length);
        }
    }

    private static void siftDown(int[] array,int parent,int len) {
        int child = 2*parent + 1;
        while(child < len){
            if(child +1 < len && array[child] < array[child+1]){
                child++;
            }
            if(array[child] > array[parent]){
                swap(array,child,parent);
                parent = child;
                child = 2*parent + 1;
            }else {
                break;
            }

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

3.交换排序

(1).冒泡排序

优化:

时间复杂度:0(N^2)
如果加了优化:最好情况下 可以达到0(n)

空间复杂度:0(1)

稳定性:稳定的排序
优化:每一趟都需要判断 上一趟 有没有交换

    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){
                break;
            }
        }
    }
  public static void swap(int[] array, int i, int j){
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

(2).快速排序 

 
时间复杂度
最好的情况下:0(N*logN) 最坏情况下:0(N^2)逆宇|有序空间复杂度:
最好的情况下:0(logN) 最坏情况下:0(N)逆序/有序
稳定性:不稳定

快排最好和最坏情况分析

Hoare法

记录下key L和R相向出发,R找比Key小的值,L找比Key大的值,R先找找到后,L再找,两个找到交换;直到L和R相遇,相遇的位置为最后L找到的小于Key的值(让R先找的原因),此时的L就是pivot ,将Key和L交换

然后以pivot为中点,将它左右两边的循环以上操作也就是递归直到传入的L和R为相同的,那么任何一个以pivot为中点的数组都变成有序的了

pivot指的是l和r相遇的位置 

  public static void  quickSort(int[] array){
        quick(array,0, array.length-1);
    }

    private static void quick(int[] array,int start,int end) {
        if(start >= end){
            return;
        }
        int pivot = partitionHoare(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }

    private static int partitionHoare(int[] array, int left, int right) {
        int tmp = array[left];
        int i = left;
        while(left < right){
            while(left < right && array[right] >= tmp){
                right--;
            }
            while (left < right && array[left] <= tmp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,i,left);
        return left;
    }

总结:

 

 

 挖坑法

向将L的第一个位置为key,也就是坑位置,然后还是R先走找到比key小的就将R下标的值给坑位,此时R为坑位,L再走,找到比L大的值,放到坑位,L此时变为坑位,直到R和L相遇,还是保证L和R相遇的时候,是R找的比Key小的放到坑位里,然后将相遇的坑位放入Key

   public static void  quickSort(int[] array){
        quick(array,0, array.length-1);
    }

    private static void quick(int[] array,int start,int end) {
        if(start >= end){
            return;
        }
        int pivot = partitionHole(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }
    private static int partitionHole(int[] array, int left, int right) {
        int tmp = array[left];
        int t = 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;
    }

总结: 

前后指针法

cur指向left加1的位置,prev指向left的位置,cur往前走,当遇到一个小于left下标值,并且此时cur和prev指向的不是同一个位置,那么cur和prev下标的值互换,直到cur超过right此时将prev和left下标的值互换,并返回prev,即是相对的中间位置

 public static void quickSort(int[] array) {
        quick(array, 0, array.length - 1);
    }
public static int partition(int[] array, int left, int right){
        int prev = left;
        int cur = left + 1;
        while (cur <= right){
            if(array[cur] < array[left] && array[++prev] != array[cur]){
                swap(array,prev,cur);
            }
            cur++;
        }
        swap(array,left,prev);
        return prev;
    }
    private static void quick(int[] array,int start,int end) {
        if(start >= end){
            return;
        }
        if(end - start + 1 <= 15){
            insertSort(array,start,end);
            return;
        }
        int index = middleNume(array,start,end);
        swap(array,start,index);
        int pivot = partition(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }

优化

 public static void  quickSort(int[] array){
        quick(array,0, array.length-1);
    }    
private static void quick(int[] array,int start,int end) {
        if(start >= end){
            return;
        }
        if(end - start + 1 <= 15){
            insertSort(array,start,end);
            return;
        }
        int index = middleNume(array,start,end);
        swap(array,start,index);
        int pivot = partitionHoare(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }

    private static int middleNume(int[] array, int left, int right) {
        int mid = (left + right)/2;
        if(array[left] < array[right] ){
            if(array[mid] < array[left]){
                return left;
            }else if(array[mid] > array[right]){
                return right;
            }else {
                return mid;
            }
        }else {
            if(array[mid] < array[right]){
                return right;
            }else if(array[mid] > array[left]){
                return left;
            }else {
                return mid;
            }
        }
    }
    public static void insertSort(int[] array,int left,int right){
        for (int i = left+1; i <= right; i++) {
            int tmp = array[i];
            int j = i - 1;
            for (; j >= left ; j--) {
                if(array[j] > tmp){
                    array[j + 1] = array[j];
                }else {
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

非递归的方法 

  public static void  quickSortNor(int[] array){
        int start = 0;
        int end = array.length -1;
        Stack<Integer> stack =new Stack<>();
        int pivot = partitionHoare(array,start,end);
       if(pivot - 1 > start){
           stack.push(start);
           stack.push(pivot-1);
       }
       if(pivot+1 < end){
           stack.push(pivot+1);
           stack.push(end);
       }
       while(!stack.empty()){
           end =stack.pop();
           start = stack.pop();
           pivot = partitionHoare(array,start,end);

           if(pivot - 1 > start){
               stack.push(start);
               stack.push(pivot-1);
           }
           if(pivot+1 < end){
               stack.push(pivot+1);
               stack.push(end);
           }

       }
  }
    private static int partitionHoare(int[] array, int left, int right) {
        int tmp = array[left];
        int i = left;
        while(left < right){
            while(left < right && array[right] >= tmp){
                right--;
            }
            while (left < right && array[left] <= tmp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,i,left);
        return left;
    }

4. 归并排序

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

空间复杂度:0(logN)

稳定性:稳定的

排序目前为止3个稳定的排序:直接插入排序、冒泡排序、归并排序

   public static void mergeSort(int[] array){
        mergeSortFun(array,0,array.length-1);
    }
    public static void mergeSortFun(int[] array,int start,int end){
        if(start >= end){
            return;
        }
        int mid = (start + end)/2;
        mergeSortFun(array,start,mid);
        mergeSortFun(array,mid+1,end);
        //左右两边数组合并
        merge(array,start,mid,end);
    }
    public static void merge(int[] array,int left,int mid, int right){
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        //两边的数组合并数组的长度
        int[] tmpArray = new int[right - left +1];
        int k = 0;
        while (s1 <= e1 && s2 <= e2){
            if(array[s1] < array[s2]){
                tmpArray[k++] = array[s1++];
            }else {
                tmpArray[k++] = array[s2++];
            }
        }
        while (s1 <= e1){
            tmpArray[k++] = array[s1++];
        }
        while (s2 <= e2){
            tmpArray[k++] = array[s2++];
        }
        for (int i = 0; i < tmpArray.length; i++) {
            array[left+i] = tmpArray[i];
        }
    }

 非递归

   public static void merge(int[] array,int left,int mid, int right){
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        //两边的数组合并数组的长度
        int[] tmpArray = new int[right - left +1];
        int k = 0;
        while (s1 <= e1 && s2 <= e2){
            if(array[s1] < array[s2]){
                tmpArray[k++] = array[s1++];
            }else {
                tmpArray[k++] = array[s2++];
            }
        }
        while (s1 <= e1){
            tmpArray[k++] = array[s1++];
        }
        while (s2 <= e2){
            tmpArray[k++] = array[s2++];
        }
        for (int i = 0; i < tmpArray.length; i++) {
            array[left+i] = tmpArray[i];
        }
    }
    public static void mergeSortNor(int[] array) {
      //每组几个数据
        int gap = 1;
        while(gap < array.length){
            for (int i = 0; i < array.length; i = i + gap*2) {
                int left = i;
                int mid = left + gap -1;
                int right = mid + gap;
                if(mid >= array.length){
                    mid = array.length - 1;
                }
                if(right >= array.length){
                    right = array.length - 1;
                }
                merge(array,left,mid,right);
            }
            gap = gap*2;
        }
    }

5.非比较排序

 使用场景是给定一个指定的待排序的序列

    public static void countSort(int[] array){
        int minVal = array[0];
        int maxVal = array[0];
        for (int i = 0; i < array.length; i++){
            if(array[i] > maxVal){
                maxVal = array[i];
            }
            if(array[i] < minVal){
                minVal = array[i];
            }

        }
        int len = maxVal - minVal + 1;
        int[] count = new int[len];
        for (int i = 0; i < array.length; i++) {
            count[array[i]-minVal]++;
        }
        int index = 0;
        for (int i = 0; i < array.length; i++) {
            while(count[0] > 0){
                array[index] = i + minVal;
                index++;
                count[i]--;
            }
        }
    }

 海量数据的排序问题


外部排序:排序过程需要在磁盘等外部存储进行的排序
前提:内存只有 1G,需要排序的数据有 100G
因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序
1. 先把文件切分成 200 份,每个 512 M
2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
3. 进行 2路归并,同时对 200 份有序文件做归并过程,最终结果就有序了

 记录当前电脑的时间

long startTime =System.currentTimeMillis();

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

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

相关文章

鸿蒙学习1概况

鸿蒙学习1相关概念 前言相关概念Stage 模型1. AbilityStage2. UIAbility组件和ExtensionAbility组3. WindowStage4. Context 事件传递UIAbility组件与UI的数据同步UIAbility组件间交互&#xff08;设备内&#xff09; 进程模型线程模型 前言 有时间多看官网&#xff0c;官网的…

Android项目中添加Dobby(inline hook)

2024技术交流群 ​ 课程地址 鸿蒙(HarmonyOS)APP开发实战课程(入门到精通) https://edu.csdn.net/course/detail/39448 1.Ubuntu编译Dobby 2.Dobby框架的介绍 Dobby是一个轻量级、多平台、多架构的inline hook框架&#xff0c;它使用起来轻快便捷&#xff0c;支持Windows/ma…

git如何将多个commit合并成一个?

我们使用git进行版本控制&#xff0c;在本地开发完某个功能时&#xff0c;需要提交commit&#xff0c;然后push至开发分支。简单的功能还好&#xff0c;几个commit可能就好了。但是如果功能比较复杂&#xff0c;commit多达十几甚至几十个时&#xff0c;commit管理就会很冗长。比…

selinux 基础知识

目录 概念 作用 SELinux与传统的权限区别 SELinux工作原理 名词解释 主体&#xff08;Subject&#xff09; 目标&#xff08;Object&#xff09; 策略&#xff08;Policy&#xff09; 安全上下文&#xff08;Security Context&#xff09; 文件安全上下文查看 先启用…

【数据结构】二叉树(带图详解)

文章目录 1.树的概念1.2 树的结构孩子表示法孩子兄弟表示法 1.3 相关概念 2.二叉树的概念及结构2.1 二叉树的概念2.2 数据结构中的二叉树-五种形态2.3 特殊的二叉树2.4 二叉树的存储结构顺序存储链式存储 2.5 二叉树的性质 3. 堆3.1 堆的定义3.2 堆的实现堆的结构堆的插入向上调…

Android binder死亡通知机制

在Andorid 的binder系统中&#xff0c;当Bn端由于种种原因死亡时&#xff0c;需要通知Bp端&#xff0c;Bp端感知Bn端死亡后&#xff0c;做相应的处理。 使用 Bp需要先注册一个死亡通知&#xff0c;当Bn端死亡时&#xff0c;回调到Bp端。 1&#xff0c;java代码注册死亡通知 …

Springboot+Vue+小程序+基于微信小程序护农远程看护系统

开发平台为idea&#xff0c;maven管理工具&#xff0c;Mybatis操作数据库&#xff0c;根据市场数字化需要为农户打造小程序可远程查看农场的种植情况。项目是调试&#xff0c;讲解服务均可有偿获取&#xff0c;需要可在最下方QQ二维码处联系我。 SpringbootVue小程序&#xff…

Android --- 消息机制与异步任务

在Android中&#xff0c;只有在UIThread(主线程)中才能直接更新界面&#xff0c; 在Android中&#xff0c;长时间的工作联网都需要在workThread(分线程)中执行 在分线程中获取服务器数据后&#xff0c;需要立即到主线程中去更新UI来显示数据&#xff0c; 所以&#xff0c;如…

50. 【Android教程】xml 数据解析

xml 是一种标记扩展语言&#xff08;Extension Mark-up Language&#xff09;&#xff0c;学到这里大家对 xml 语言一定不陌生&#xff0c;但是它在 Android 中的运用其实只是冰山一角。抛开 Android&#xff0c;XML 也被广泛运用于各种数据结构中。在运用 xml 编写 Android 布…

Docker创建镜像之--------------基于Dockerfile创建

目录 一、在编写 Dockerfile 时&#xff0c;有严格的格式需要遵循 二、Dockerfile 操作常用的指令 2.1ENTRYPOINT和CMD共存的情形 2.2ENTRYPOINT和CMD的区别 2.3ADD 与COPY的区别 三、Dockerfile案例 3.1构建apache镜像 3.1.1 创建镜像目录方便管理 3.1.2创建编写dock…

基于Springboot的音乐翻唱与分享平台

基于SpringbootVue的音乐翻唱与分享平台设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 音乐资讯 音乐翻唱 在线听歌 后台登录 后台首页 用户管理 音乐资讯管理…

基础安全:CSRF攻击原理与防范

CSRF的概念 CSRF(Cross-Site Request Forgery)中文名为“跨站请求伪造”。这是一种常见的网络攻击手段,攻击者通过构造恶意请求,诱骗已登录的合法用户在不知情的情况下执行非本意的操作。这种攻击方式利用了Web应用程序中用户身份验证的漏洞,即浏览器在用户完成登录后会自…

JavaEE 初阶篇-深入了解网络原理中传输层的端口号与 UDP 协议报文格式

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 端口号概述 1.1 端口号的作用 1.2 端口号不能重复被多个进程绑定 2.0 传输层协议 - UDP 2.1 UDP 的特性 2.2 UDP 的报文格式 1.0 端口号概述 端口号是计算机网络中…

进一步了解android studio 里 AGP,gradle等关系

目录 &#xff08;1&#xff09; gradle是什么 &#xff08;2&#xff09; 工程的jdk版本&#xff0c;及引用包的编译版本的关系 实践 问题与解决 编译成功与运行成功 编译成功 运行成功 &#xff08;1&#xff09; gradle是什么 Gradle是一个构建工具&#xff0c;它是…

1.6 Java全栈开发前端+后端(全栈工程师进阶之路)-前置课程Jdbc编程,使用Java通过Jdbc对数据库进行基础操作

原理图 用java代码实现连接数据库&#xff08;mysql&#xff09;的操作 因为数据库连接需要使用到API和URL&#xff0c;下面简单介绍下API和URL的概念&#xff0c; API&#xff1a; Application Programming Interface应用程序编程接口&#xff0c;就是一套类库 Java中的AP…

2024中国绿电制氢技术趋势分析报告

来源&#xff1a;ATC & 大东时代 国家级规划《氢能产业发展中长期规划&#xff08;2021-2035&#xff09;》出台 • 主要宗旨&#xff1a;明确“能源”的角色定位以及在绿色低碳转型中的作用&#xff0c;为产业发展构建清晰的蓝图。 • 阶段目标设立&#xff1a; • 2025/…

如何不使用代理服务从hugging face上下载大模型?

前言&#xff1a;中国大陆的朋友会发现hugging face经常无法访问了&#xff0c;特别是在服务器上下载大型模型/数据集&#xff0c;如果先在电脑上下载完再传输到服务器上&#xff0c;对于大模型来说会非常麻烦&#xff0c;这篇博客一共提供了三种有效的方法不使用代理服务从hug…

【Java】何为JShell?——有趣的Java学习小工具

前言&#xff1a;上一篇中我们已经看到了如何编译和运行一个Java程序。Java1.9&#xff08;即Java9&#xff09;中引入了另一种使用Java的方式。JShell(Java Shell)程序提供了一个“读取-计算-打印循环”&#xff08;Read-Evaluate-Print Loop,REPL&#xff09;。当你键入一个J…

【综述】多核处理器芯片

文章目录 前言 Infineon处理器 AURIX™系列 TC399XX-256F300S 典型应用 开发工具 参考资料 前言 见《【综述】DSP处理器芯片》 Infineon处理器 AURIX™系列&#xff0c;基于TriCore内核&#xff0c;用于汽车和工业领域。 XMC™系列&#xff0c;基于ARM Cortex-M内核&…

基于 Evan_song1234 开发,MoonSpaceCat 增补的2D 我的世界,增加双缓冲实现 cmd控制台窗口或 Powershell 流畅运行

游戏玩法&#xff1a; awsd移动 1234567890 各有功能 t 是命令行 q 是刷新 e 是重开 z 是挖 其他还没来及探索代码 代码来源 C我的世界2D控制台版_cminecraft-CSDN博客 其中解决颜色被双缓冲刷新没的方法 参考于自己的博客 用ReadConsoleOutput 解决双缓冲ReadConsol…