排序-八大排序FollowUp

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();

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

早期明牌空投Sanctum【大羊毛必薅】

Season 1 第一季 早期 Sanctum指南&#xff1a;https://sanc.tm/w?refH0IEGW邀请&#xff1a;H0IEGW 感觉和kmno一个实时积分系统的&#xff01; 直接用SOL换成Infinity&#xff0c; 然后过一会就会实时更新积分&#xff01;很简单&#xff01; 投资方Dragonfly比较牛逼。

linux dma的使用

设备树配置 驱动代码 static void bcm2835_dma_init(struct spi_master *master, struct device *dev) { struct dma_slave_config slave_config; const __be32 *addr; dma_addr_t dma_reg_base; int ret; /* base address in dma-space */ addr of_get_address(master->de…

MySQL —— 库的基本操作

一、数据库的增删查改 &#xff08;1&#xff09;创建 语句&#xff1a;create database db_name;&#xff08;db_name是自定义的数据库名字&#xff09; &#xff08;2&#xff09;删除 语句&#xff1a;drop database dp_name;&#xff08;dp_name是要被删除的数据库的名字…

谷粒商城实战(021 业务-订单模块-页面设计)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第262p-第p266的内容 介绍 所需的页面 设计页面 新增域名 路径带/static的都到/usr/share/nginx/html文件夹下去找 其他动态请求的都负载…

第12章 软件测试基础(第三部分)测试类型

七、测试类型&#xff08;按工程阶段划分&#xff09; 单集系确收 &#xff08;一&#xff09;单元测试 1、单元测试/模块测试 单元就是软件中最小单位&#xff08;或模块&#xff09;。可以是一个函数、一个过程、一个类。主要依据是模块的详细设计文档。价值在于尽早发现…

Nginx负载均衡主备模式

1. 背景 使用Nginx代理后端服务&#xff0c;有时候某些服务是不能使用多台负载均衡&#xff0c;但又想保障高可用&#xff0c;所以采用主备模式&#xff0c;记录如下&#xff1a; 2. 参考 nginx 负载均衡Nginx-负载均衡-后端状态max_conns、down、backup、max_fails、fail_t…

文心一言 VS 讯飞星火 VS chatgpt (249)-- 算法导论18.2 2题

二、请解释在什么情况下&#xff08;如果有的话&#xff09;&#xff0c;在调用 B-TREE-INSERT 的过程中&#xff0c;会执行冗余的 DISK-READ 或 DISK-WRITE 操作。&#xff08;所谓冗余的 DISK-READ &#xff0c;是指对已经在主存中的某页做 DISK-READ 。冗余的 DISK-WRITE 是…

无脑入单向无头链表的实现| ArrayList和LinkedList的区别

1. ArrayList的缺陷 上节课已经熟悉了ArrayList的使用&#xff0c;并且进行了简单模拟实现。通过源码知道&#xff0c;ArrayList底层使用数组来存储元素。 由于其底层是一段连续空间&#xff0c;当 在 ArrayList 任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往…

踏上R语言之旅:解锁数据世界的神秘密码(三)

多元相关与回归分析及R使用 文章目录 多元相关与回归分析及R使用一.变量间的关系分析1.两变量线性相关系数的计算2.相关系数的假设检验 二.一元线性回归分析的R计算三、回归系数的假设检验总结 一.变量间的关系分析 变量间的关系及分析方法如下&#xff1a; 1.两变量线性相关…

延时任务通知服务的设计及实现(二)-- redisson的延迟队列RDelayedQueue

一、接着上文 RDelayedQueue作为redisson封装的一个分布式延迟队列&#xff0c;直接拿来使用还是比较简单的。 本文主要包括以下几部分&#xff1a; 保存至延迟队列&#xff08;生产者&#xff09;读取延迟队列&#xff08;消费者&#xff09;从延迟队列移除任务 二、rediss…

NCC导入导出开发

&#x1f4e3;NCC导入导出开发 ✨1. 导入流程图 ✨2. 实现步骤 &#x1f434;1. 前端代码实现。 &#x1f434;2. 配置文件创建与设置。 &#x1f434;3. 后端代码实现。 &#x1f434;4. 注册后端代码类。

通过Servlet和JSP,结合session和application实现简单网络聊天室(文末附源码)

目录 一.成品效果 二.代码部分 chat.jsp ChatServlet 一.成品效果 在启动成功后&#xff0c;我们就可以在任意俩个浏览器页面中相互发消息&#xff0c;如图所示左边屏幕使用的是Edge浏览器&#xff0c;右图使用的是火狐浏览器。当然笔者这里只是简单实现最基本的一些功能&…

【IC设计】CRC(循环冗余校验)

目录 理论解读CRC应用CRC算法参数解读常见CRC参数模型 设计实战校招编程题分类串行输入、并行计算、串行输出**串行计算、串行输出&#xff08;线性移位寄存器&#xff09;LSFR线性移位寄存器&#xff08;并转串&#xff09;(并行计算)模二除 总结——串行、并行计算的本质参考…

Vitis HLS 学习笔记--S_AXILITE 寄存器及驱动

目录 1. 简介 2. S_AXILITE Registers 寄存器详解 2.1 “隐式”优势 2.2 驱动程序文件 2.3 硬件头文件 2.4 硬件头文件中 SC/COR/TOW/COH 的解释 2.5 驱动控制过程 3. 总结 1. 简介 回顾此博文《Vitis HLS 学习笔记--Syn Report解读&#xff08;1&#xff09;-CSDN博…

可视化大屏也在卷组件化,组件绝对是效率利器呀。

组件化设计在B端上应用十分普遍&#xff0c;其实可视化大屏组件更为规范&#xff0c;本期分享组件化设计的好处&#xff0c;至于组件源文件如何获取&#xff0c;大家都懂的。 组件化设计对可视化大屏设计有以下几个方面的帮助&#xff1a; 提高可重用性&#xff1a; 组件化设…

【从0开始搭建内网穿透】开源内网穿透神器-中微子代理

1. 背景 概念&#xff1a;内网穿透&#xff0c;就是让处在外网的设备能够访问内网设备的服务。典型的应用场景就是人在外面访问家中的NAS、人在出差调试内网中的web服务、开Minecraft服务器等。 起因&#xff1a;实验室项目有搭建内网穿透服务的需求&#xff08;项目前端需要部…

【网络】UDP协议

文章目录 一. 初识UDP1. UDP简介2. UDP协议的特点特点一&#xff1a;无连接特点二&#xff1a;不可靠特点三&#xff1a;面向数据报 3. UDP报文的格式4. UDP的缓冲区5. 基于UDP实现的用户层协议 二. UDP报文中各个字段1. 原端口号与目的端口号&#xff08;16位&#xff09;1.1 …

《Redis使用手册之Lua脚本》

《Redis使用手册之Lua脚本》 EVAL&#xff1a;执行脚本 127.0.0.1:6379> eval “return ‘hello world’” 0 “hello world” 127.0.0.1:6379> eval “return redis.call(‘set’,KEYS[1],ARGV[1])” 1 “message” “hello world” OK 127.0.0.1:6379> get message…

网络安全知识点

网络安全 1&#xff0e; 网络安全的定义&#xff0c;网络安全的属性。 定义&#xff1a;针对各种网络安全威胁研究其安全策略和机制&#xff0c;通过防护、检测和响应&#xff0c;确保网络系统及数据的安全性。 属性&#xff1a;机密性 认证&#xff08;可鉴别性&#xff09…

ASP.NET淘宝店主交易管理系统的设计与实现

摘 要 淘宝店主交易管理系统主要采用了ASPACCESS的B/S设计模式&#xff0c;通过网络之间的数据交换来实现客户、商品、交易的管理和对客户、商品、交易统计工作&#xff0c;从而提高淘宝店主在管理网店过程中的工作效率和质量。 系统分为基本资料模块&#xff0c;统计资料模…