12.2排序

news2024/12/26 23:26:52

目录

0.做题的失误

1.引用传值和传址

1.斐波那契数列

一.快速排序

1.挖坑法

2.优化

2.1 随机取数法

2.2 三数取中法

2.3把基准值相同的值移到基准旁边

2.4引用直接插入排序

3.Hoare 法:

4.非递归法

5.总结

二,归并排序

1.原理

2.代码实现

3.分析

4.非递归

5.海量数据的排序问题

三.排序总结

四.非比较的排序

1.基数排序

2.桶排序

3.计数排序

1.原理

2.代码

3.分析


0.做题的失误

1.引用传值和传址

数组指向的对象是一个引用,函数结束的时候 就会消失

所以根本没有交换

要么我们的处理方式就是在函数内直接交换

或者写一个函数把数组也穿进去

1.斐波那契数列

这道题我们就需要找到给的这个数到离他最近的斐波那契左边的数和右边的数步数谁最小

还有一种情况就是相同的时候,那么右边边的就是相同的.左边的还是一样求,最小的还是右边边的

循环结束的时候,N一定大于f1

因为f1是由f2得来的,f1一定比f2小,一次循环下俩

当n跳出循环一定是小于等于f2的

上一次的f2就是这次的f1.上次没有跳出就说明满足循环条件

import java.util.*;
public class Main{
    public static void main(String[]args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int a=0;
        int b=1;
        while(b<n){
            int c=a+b;
            a=b;
            b=c;
        }
        //跳出循环的时候a就是N的左边的数,b就是n右边的数
        
        System.out.println(Math.min(n-a,b-n));
    }
}

一.快速排序

1.挖坑法

public static void quickSort(int[] array){
    quick(array,0,array.length);
}
public static void quick(int[] array,int left,int right){
    if(left>right) return;

    int pivot=partition(array,left,right);

    quick(array,left,pivot-1);//递归左区间
    quick(array,pivot+1,right);
}
public static int partition(int[]array,int start,int end){
    int tmp=array[start];
    while(start<end){
        while(start<end&&array[end]>tmp){
            end--;
        }//end<tmp
        array[start]=array[end];
        while(start<end&&array[start]<tmp){
            start++;
        }
        array[end]=array[start];
    }
    array[start]=tmp;
    return start;

}

2.优化

因为有可能这组数据是有序的,这种排序方法的最好的可能就是每组均匀分布,如果是有序的就成了一种单分支的二叉树

二叉树的高度就是n本身.所以最坏情况下的时间复杂度就是n*n

空间复杂度同理

所以我们尽量变成无序

2.1 随机取数法

随机除了第一个数以外的数与第一个数进行交换.

2.2 三数取中法

array[left], array[mid], array[right] 大小是中间的为基准值

找到中间数字,与left交换

代码实现

private static int findMidIndex(int[] array,int start,int end) {
    int mid = start + ((end-start) >>> 1);
    if(array[start] < array[end]) {
        if(array[mid] < array[start]) {
            return start;
        }else if(array[mid] > array[end]) {
            return end;
        }else {
            return mid;
        }
    }else {
        if(array[mid] > array[start]) {
            return start;
        }else if(array[mid] < array[end]) {
            return end;
        }else {
            return mid;
        }
    }
}

2.3把基准值相同的值移到基准旁边

这样减小下次的区间

2.4引用直接插入排序

public static void insertSort2(int[] array,int start,int end){
    for (int i = start+1; i <=end; i++) {
        int tmp=array[i];
        int j=i-1;
        for (;j>=start;j--){
            if(array[j]>tmp){
                array[j+1]=array[j];
            }else{
                break;
            }
        }
        array[j+1]=tmp;
    

但我们发现 取消优化三数取中法,发生了栈溢出,很有可能就是因为不均匀分布,一直在一边反复递归

虽然有序比无序的情况要快一点,但是还是在一个数量级,

因为有序情况下可能就是一直循环,减少了交换

3.Hoare 法:

原理类似,只是从挖坑变成交换.\

定义两个指针,一个从左走,一个从右z走.

j从右走.找到比tmp小的,停止

i从左走,找到从tmp大的,停止

交换i和j

直到i和j相遇

把这个位置和left所在的也就是tmp的值交换

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

}

经过测试,Hoare明显慢很多还容易栈溢出.可能会反复调用swap方法的原因把

4.非递归法

先找到基准,划分后分别把左右数对的下标开始结束放入栈里,

先出的就是右边的,

再从右边的开始找基准

找到后再把左边和右边的放入栈里

但是这个时候我们发现右边只有一个元素

就不需要放进栈里

所以我们可以判断好

我本来想可不可以用队列

发现不行因为你先放左右

然后左先出,再放进左的左和右,这个时候发现再第一段右的上面

还要等右判断完了再判断他的左和右

这块都乱了.

/**
 * 快速排序非递归
 * @param array
 */
public static void quickSort1(int[] array){
    //初始化
    int left=0;
    int right=array.length-1;
    Stack<Integer> stack=new Stack<>();
    //找基准
    int prvot=partition(array,left,right);
    //把左右区间放入栈
    if(prvot>left+1){
        stack.push(left);
        stack.push(prvot-1);
    }
    if(prvot<right-1){
        stack.push(prvot+1);
        stack.push(right);
    }

    while(!stack.isEmpty()){
         right=stack.pop();
         left=stack.pop();
         prvot=partition(array,left,right);
        //把左右区间放入栈
        if(prvot>left+1){
            stack.push(left);
            stack.push(prvot-1);
        }
        if(prvot<right-1){
            stack.push(prvot+1);
            stack.push(right);
        }
    }
}

前面的不能放到循环里,因为要找基准后吧`

5.总结

  1. 在待排序区间选择一个基准值
  2. 选择左边或者右边
  3. 随机选取
  4. 几数取中法
  5. 做 partition,使得小的数在左,大的数在右
  6. hoare
  1. 挖坑
  2. 前后遍历
  3. 将基准值相等的也选择出来(了解)
  4. 分治处理左右两个小区间,直到小区间数目小于一个阈值,使用插入排序

二,归并排序

1.原理

原理:把两个有序数组合并成一个有序数组\

代码实现

public static int[] mergeArray(int[]array1,int[] array2){
    int s1=0;
    int e1=array1.length-1;

    int s2=0;
    int e2=array2.length-1;

    int[] tmp=new int[e1+e2+2];
    int k=0;
    while(s1<=e1&&s2<=e2){
        if(array1[s1]<array2[s2]){
            tmp[k++]=array1[s1++];
        }else{
            tmp[k++]=array2[s2++];
        }
    }
    while(s1<=e1){
        tmp[k++]=array1[s1++];
    }
    while(s2<=e2){
        tmp[k++]=array2[s2++];
    }
    return tmp;
}

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

先一步一步递归直到l与h相遇,

也就是只剩下一个元素的情况

比如要合并1670 这两组,就要在4个一组的时候找到对应的下标

注意要对应上原数组的下标,而不是这次递归的开始

2.代码实现

public static void mergeSort(int[] array){
    mergeSortInternal(array,0,array.length-1);
}
public static void mergeSortInternal(int [] array,int low,int high){
   //递归终止条件
    if(low>=high) return;

    int mid=low+((high-low)>>>1);//加号 的优先级比较高

    //递归左边的
    mergeSortInternal(array,low,mid);
    //递归右边的
    mergeSortInternal(array,mid+1,high);

    //走到这就需要合并  所合并的参数应该是上次递归的
    merge(array,low,mid,high);
}
/**
 * g归并
 */
private static void merge(int[] array,int low,int mid,int high){
    int s1=low;
    int e1=mid;

    int s2=mid+1;
    int e2=high;
    int[] tmp=new int[high-low+1];
    int k=0;
    while(s1<=e1&&s2<=e2){
        if(array[s1]<=array[s2]){
            tmp[k++]=array[s1++];
        }else{
            tmp[k++]=array[s2++];
        }
    }
    while(s1<=e1){
        tmp[k++]=array[s1++];
    }
    while(s2<=e2){
        tmp[k++]=array[s2++];
    }
    //还要把tmp拷贝到原来的数组
    for (int i = 0; i < k; i++) {
        array[i+low]=tmp[i];
    }
}

3.分析

时间复杂度:一直递归每个数据都要递归到树的高度那么多,所以就是n*logn

空间复杂度就是额外开一个tmp数组所以就是o(n)

并且是一个稳定的排序

/**
 * 归并排序:
 * 时间复杂度:O(N*logN)
 * 空间复杂度:O(N)
 * 稳定性:稳定的排序
 * 如果 array[s1] <= array[s2] 不取等号  那么就是不稳定的排序
 *
 * 学过的排序 只有3个是稳定的:
 * 冒泡   插入   归并
 * @param array
 */

4.非递归

先定义一个gap每组从1个元素开始然后加倍

当每组一个时候.

找到相邻两个数据段的下标

进行归并

然后再往前走找下两个数据段

直到遍历完

再让gap加倍

继续进行循环

直到gap等于数组长度或者大于/

/**
 * 非递归实现归并排序
 */
public static void mergeSort1(int[] arr){
    int gap=1;//每组的数据个数
    while(gap<arr.length){//gap在数组一半长度时候已经完成了两个数据段的合并,所以到等于的时候早就合并完了
        //数组每次都要遍历,确定要归并的区间
        for (int i = 0; i < arr.length; i+=gap*2) {
            int left=i;
            int mid=i+gap-1;
            //防止越界
            if(mid>= arr.length){
                mid=arr.length-1;
            }
            int right=mid+gap;
            //防止越界
            if(right>=arr.length){
                right=arr.length-1;
            }
            //小标确立后,进行合并
            merge(arr,left,mid,right);
        }
        gap*=2;

    }
}

5.海量数据的排序问题

外部排序:排序过程需要在磁盘等外部存储进行的排序

前提:内存只有 1G,需要排序的数据有 100G

因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序

  1. 先把文件切分成 200 份,每个 512 M
  2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
  3. 进行 200 路归并,同时对 200 份有序文件做归并过程,最终结果就有序了

外部排序就是在磁盘上排序,

内部排序就是在内存上排序

三.排序总结

四.非比较的排序

1.基数排序

因为是十进制的,构成0-9的十个队列

把一组数据从个位数到最高位分别进行排序

先尾插进,头出

个位

然后在从0-9按照顺序头出来

可以发现个位已经有序

在来排序十位数

再分别拿出来

再排序百位数

1.10 基数排序 | 菜鸟教程 (runoob.com)

2.桶排序

桶排序(最快最简单的排序) - 知乎 (zhihu.com)

3.计数排序

1.原理

定义一个计数数组.找数组每个元素出现的次数,然后遍历计数数组.从头开始,

但是有疑问?

计数数组建立好后

把技术数组的数据覆盖到原数组

就先遍历计数数组

把不是0的数据进行循环

 

这里就需要定义一个index

 

因为很有可能一个数据出现好几次

循环一次,index就往后一位

直到计数数组对应的值为0

那我们如果放进去原数组的值呢

其实很简单就是计数数组的下标

但是如果是900-926各元素

我们防止内存冗余 就减去了900存放

那么我们遍历计数数组放元素的时候也需要加上900也就是minval.

2.代码

public static void countingSort(int[] array) {
    int maxVal = array[0];
    int minVal = array[0];
    for (int i = 1; i < array.length; i++) {
        if(array[i] < minVal) {
            minVal = array[i];
        }
        if(array[i] > maxVal) {
            maxVal = array[i];
        }
    }
    //说明,已经找到了最大值和最小值
    int[] count = new int[maxVal-minVal+1];//默认都是0
    //统计array数组当中,每个数据出现的次数
    for (int i = 0; i < array.length; i++) {
        int index = array[i];
        //为了空间的合理使用 这里需要index-minVal  防止923-900
        count[index-minVal]++;
    }
    //说明,在计数数组当中,已经把array数组当中,每个数据出现的次数已经统计好了
    //接下来,只需要,遍历计数数组,把数据写回array
    int indexArray = 0;
    for (int i = 0; i < count.length; i++) {
        while (count[i] > 0) {
            //这里一定要加minVal,因为不一定就是i出现了count[i]
            array[indexArray] = i+minVal;
            count[i]--;//拷贝一个之后,次数也就少一个
            indexArray++;//下标得向后移动
        }
    }
}

3.分析

/**
 * 计数排序
 */
/**
 * 计数排序:
 * 时间复杂度:O(N)
 * 空间复杂度:O(M) M:代表 当前数据的范围900 - 999
 * 稳定性:当前代码是不稳定的,但是本质是稳定的
 *
 * 一般适用于 有n个数,数据范围是0-n之间的
 * @param array
 */

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

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

相关文章

Git(第一篇)——Git的下载与安装(史上最全最详细)

Git&#xff08;第一篇&#xff09;——Git的下载与安装&#xff08;史上最全最详细&#xff09; 目录Git&#xff08;第一篇&#xff09;——Git的下载与安装&#xff08;史上最全最详细&#xff09;git的下载git的安装git的下载 如果你还没有下载Git&#xff0c;可直接到git…

什么是数据管理能力成熟度评估(DCMM)

GB/T 36073-2018 《数据管理能力成熟度评估模型》&#xff08;Data Management Capability Maturity Assessment Model&#xff0c;简称&#xff1a;DCMM&#xff09;是我国数据管理领域首个国家标准。该标准将组织对象的数据管理划分为八大能力域&#xff08;数据战略、数据治…

【Hbase】第一章——从原理剖析

文章目录1. HBase的实现原理1.1 HBase功能组件1.2 表和Region1.3 Region的定位2. HBase运行机制2.1 HBase系统架构2.2 Region服务器工作原理2.3 Store工作原理2.4 HLog工作原理3. HBase应用方案3.1 HBase实际应用中的性能优化方法3.2 HBase性能监视3.3 在HBase之上构建SQL引擎3…

【图像压缩】DCT图像无损压缩【含GUI Matlab源码 726期】

⛄一、DCT图像无损压缩简介 1 图像压缩 图像压缩按照压缩过程中是否有信息的损失以及解压后与原始图像是否有误差可以分为无损压缩和有损压缩两大类。无损压缩是指不损失图像质量的压缩&#xff0c;它是对文件的存储方式进行优化&#xff0c;采用某种算法表示重复的数据信息&a…

关于Jetpack Compose的初步使用、学习和总结

初步使用和学习ComposeJetpack Compose简要介绍创建一个Jetpack Compose项目自定义组合函数MessageCard通过修饰符&#xff0c;进一步改善布局为什么使用ComposeCompose 与 XML总结与期望Jetpack Compose 简要介绍 根据developers上的介绍&#xff0c;Jetpack Compose 是推荐…

【3D目标检测】Rethinking Pseudo-LiDAR Representation

目录概述细节证明基于伪点云的3D目标检测算法效果好的原因并不是伪点云这种数据表示基于深度图的图像表示的算法PatchNet证明基于伪点云的3D目标检测算法效果好的原因是从图像到点云坐标系转换的过程概述 本文是基于图像的3D目标检测算法。 贡献&#xff1a; 作者认为基于伪点…

开放式运动耳机排行榜,排行靠前的五款高性能耳机分享

智能产品的发展迅猛&#xff0c;作为生活必需品的耳机&#xff0c;更是在不断的更新&#xff0c;尤其是对于运动爱好者而言&#xff0c;以往的入耳式蓝牙耳机存在汗渍入耳等问题。而为了有效解决这一些列问题&#xff0c;新型的骨传导耳机随之诞生了&#xff0c;相比入耳式的蓝…

一定要用Photoshop?no!动手用Python做一个颜色提取器! ⛵

&#x1f4a1; 作者&#xff1a;韩信子ShowMeAI &#x1f4d8; Python3◉技能提升系列&#xff1a;https://www.showmeai.tech/tutorials/56 &#x1f4d8; 计算机视觉实战系列&#xff1a;https://www.showmeai.tech/tutorials/46 &#x1f4d8; 本文地址&#xff1a;https://…

直播 | 数据仓库?数据湖?停止纠结,流批融合的极速 Lakehouse来了!

万物皆数据的时代&#xff0c;各行各业对数据分析架构的要求日益拔高&#xff0c;打破传统的数据湖应需而生。企业得以用更低廉的成本、更完善的 ACID 支持、更实时的方式&#xff0c;导入并存储所有结构化、半结构化和非结构化数据。得益于数据湖良好的伸缩性和灵活性&#xf…

jQuery 安装

网页中添加 jQuery 可以通过多种方法在网页中添加 jQuery。 您可以使用以下方法&#xff1a; 从 jquery.com 下载 jQuery 库从 CDN 中载入 jQuery, 如从 Google 中加载 jQuery下载 jQuery 有两个版本的 jQuery 可供下载&#xff1a; Production version - 用于实际的网站中…

渲染时间过长?这些参数设置学起来

渲染时间 为了契合创作者的需求&#xff0c;V-Ray渲染器近年来迭代迅速&#xff0c;新版本的上线&#xff0c;便利了更多用户。但也有小伙伴在使用后反馈&#xff1a; 我的渲染器明明已经升级到最高版本了&#xff0c;为什么渲染时间还这么慢&#xff1f; 实际上&#xff0c;出…

如何通过一个项目征服Java

Java早已经不是高大山的稀世珍品了&#xff0c;程序员也不再是高科技工作者&#xff0c;而被称为码农 &#xff0c;为什么呢&#xff1f;因为Java后台的很多基础技术都已经固定了&#xff0c;也就是说主要你从头到尾学一遍就能会 &#xff0c;淘宝双十一搞不定&#xff0c;但是…

2022年12月深圳/珠海/佛山/东莞数据分析CPDA认证报名

2022年12月深圳/珠海/佛山/东莞数据分析CPDA认证报名 CPDA数据分析师认证是中国大数据领域有一定权威度的中高端人才认证&#xff0c;它不仅是中国较早大数据专业技术人才认证、更是中国大数据时代先行者&#xff0c;具有广泛的社会认知度和权威性。 无论是地方政府引进人才、…

HAL库(STM32CubeMX)之看门狗学习及实操(STM32F767IGTX)

系列文章目录 HAL库&#xff08;STM32CubeMX&#xff09;——ADC学习总结&#xff08;包含单次/连续模式下的轮询/中断/DMA&#xff09;&#xff08;蓝桥杯STM32G431RBT6&#xff09; HAL库(STM32CubeMX)——DAC学习&#xff08;STM32G431RBT6&#xff09; HAL库(STM32CubeM…

Innodb如何实现表--上篇

Innodb如何实现表--上篇数据是如何被管理起来的表空间段区页行行记录格式Compact记录行格式Redundant行记录格式行溢出数据Compressed和Dynamic行记录格式Char的行存储结构小结数据是如何被管理起来的 从InnoDB存储引擎的逻辑存储结构看&#xff0c;所有数据都被逻辑地存放在一…

[附源码]计算机毕业设计JAVA宿舍管理系统

[附源码]计算机毕业设计JAVA宿舍管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis M…

十万部冷知识:奥运会冠城市名,世界杯为什么冠国名?

不知道大家发现没有&#xff0c;凡是给奥运会、亚运会等很多比赛取名的时候&#xff0c;往往都是给它冠以城市的名字。比如&#xff0c;北京冬奥会、广州亚运会、北京奥运会等等&#xff0c;而称呼世界杯的时候&#xff0c;我们往往是冠以国家的名字称呼的&#xff0c;诸如&…

Day17-购物车页面-商品列表-实现滑动删除功能

提纲挈领&#xff1a; 官方文档&#xff1a; 博主文档&#xff1a; 我的操作&#xff1a; 1》改造 cart.vue 页面的 UI 结构&#xff0c;将商品列表区域的结构修改如下&#xff08;可以使用 uSwipeAction 代码块快速生成基本的 UI 结构&#xff09;&#xff1a; 2》在 data 节…

学到生无可恋之 Redis

一把年纪了还是这么菜 1 Redis 是啥 Redis 是一个高性能的 Key-Value 数据库&#xff0c;key 的类型是字符串&#xff0c;value 的类型有&#xff1a;string 字符串类型、list 列表类型、set 集合类型、sortedset(zset) 有序集合类型、hash 类 型、bitmap 位图类型等。 上图…

Mybatis:Mybatis的各种查询功能(5)

Mybaits笔记框架&#xff1a;https://blog.csdn.net/qq_43751200/article/details/128154837 Mybatis的各种查询功能1. 查询一个实体类对象2. 查询一个List集合3. 查询单个数据4. 查询一条数据为map集合5. 查询多条数据为map集合方法一方法二1. 查询一个实体类对象 SelectMapp…