Java数据结构之排序(头歌平台,详细注释)

目录

第1关:选择排序

任务描述

相关知识

代码:  

 第2关:插入排序

任务描述

相关知识

插入排序

代码:  

第3关:归并排序

任务描述

相关知识

归并排序

原理

代码:  

 第4关:快速排序

任务描述

相关知识

快速排序

代码:  

 第5关:堆排序

任务描述

相关知识

堆的性质

堆排序

用大根堆排序的基本思想

大根堆排序算法的基本操作

代码:  


第1关:选择排序

任务描述

给定一组无序的数据,如果要把它们从小到大重新排序,我们要如何实现这个排序功能呢?

本关任务:实现选择排序。

相关知识

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

上图是一个从小到大排序的选择排序过程。第一次,我们从初始序列中找出了最小的元素11,把它放到第一位;第二次我们从剩下的元素中找出最小的元素13,把它放到第二位,以此类推,直到所有元素从小到大排好序。

代码:  
package step1;

/**
 * Created by sykus on 2018/3/20.
 */
public class SelectionSort {

    /**
     * 选择排序
     *
     * @param arr
     */
    public static void sort(int arr[]) {
        /********** Begin *********/
        int n=arr.length;//数组长度
        for(int i=0;i<n-1;i++){//从第一个数开始比较,第一位存放最小的,第二位存放第二小的,以此推类
            for(int j=i+1;j<n;j++){//查找i下标以及之后的最小值,放在i的位置
                if(arr[i]>arr[j]){//如果小就交换
                    int t=arr[i];//t存储arr[i]的值
                    arr[i]=arr[j];//arr[i]赋arr[j]的值
                    arr[j]=t;//arr[j]赋值t,即为arr[i]的值
                }
            }
            print(arr);//一个输出的方法,在下面可以看到
        }
        /********** End *********/
    }

    private static void print(int arr[]) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

}

以下是测试样例:

测试输入:2 8 7 1 3 5 6 4 预期输出:

 第2关:插入排序

任务描述

上一关我们实现了选择排序,本关我们实现另外一种排序方法:插入排序。

本关任务:实现插入排序。

相关知识
插入排序

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据。

假设我们输入的是5,1,4,2,3,我们从第二个数字开始,这个数字是1,我们的任务只要看看1有没有正确的位置,我们的做法是和这个数字左边的数字来比,因此我们比较1515小,所以我们就交换15,原来的排列就变成了1,5,4,2,3

接下来我们看第三个数字有没有在正确的位置。这个数字是4,它的左边数字是545小,所以我们将45交换,排列变成了1,4,5,2,3我们必须继续看4有没有在正确的位置,4的左边是114小,4就维持不动了。

再来看第四个数字,这个数字是2,我们将2和它左边的数字相比,都比2大,所以就将2一路往左移动,一直移到2的左边是1,这时候排序变成了1,2,4,5,3

最后,我们检查第五个数字,这个数字是33必须往左移,一直移到3的左边是2为止,所以我们的排列就变成了1,2,3,4,5,排序完成。

插入排序示例

 如果难以理解,可以看作,第一次对前两个数排序,第二次对前三个数排序,第n次对第n+1个数排序,即可得插入排序的排序顺序

代码:  
package step2;

/**
 * Created by sykus on 2018/3/20.
 */
public class InsertionSort {

    public static void sort(int arr[]) {
        /********** Begin *********/
        int n=arr.length;//存储数组长度
        for(int i=1;i<n;i++){//从第二位数开始插入
            int j=i;//存储需要插入数的下标
            int t=arr[j];//存储需要插入数的值
            while(j>0 && t<arr[j-1]){//从后往前开始找比需要插入值大的值
                arr[j]=arr[j-1];//如果大就后移一位
                j--;//继续往前找
            }
            arr[j]=t;//最后将需要插入数插入j下标的位置
            print(arr);//一个输出的方法,在下面可以看到
        }
        /********** End *********/
    }

    private static void print(int arr[]) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

以下是测试样例:

测试输入:

  1. 6
  2. 1 5 4 3 2 6

预期输出:

第3关:归并排序

任务描述

本关任务:实现归并排序。

相关知识
归并排序

归并排序(Merge Sort)是建立在归并操作上的一种有效的排序算法。归并是指将若干个已排序的子序列合并成一个有序的序列。若将两个有序序列合并成一个有序序列,称为二路归并。

原理

假设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1。然后两两归并,得到n/2个长度为21的有序子序列;再两两归并,如此重复,直到得到一个长度为n的有序序列为止。

上图是一个二路归并排序过程示例,经过三次归并操作后完成了排序。

代码:  
package step3;

/**
 * Created by sykus on 2018/3/20.
 */
public class MergeSort {

    /**
     * lo, hi都是指下标
     */
    public static void sort(int arr[], int lo, int hi) {
        if (lo < hi) {
            int mid = (lo + hi) / 2;
            sort(arr, lo, mid);
            sort(arr, mid + 1, hi);
            merge(arr, lo, mid, hi);
            print(arr);
        }
    }

    private static void merge(int arr[], int p, int q, int r) {
        /********** Begin *********/
        //归并排序将两部分合并
        int n=arr.length;//存储数组长度
        int[] t=new int[n];//定义一个数组用于存储排序后的数组
        int i=p,j=q+1,k=i;;//第一部分的左边界,第二部分的左边界,t的初始下标为第一部分的左边界
        while(i<=q&&j<=r){//如果两部分都不超过他们的右边界则继续合并
            if(arr[i]<arr[j]){//比大小,小的先放入排序数组里
                t[k++]=arr[i++];//继续往后比较
            }else{//比大小,小的先放入排序数组里
                t[k++]=arr[j++];//继续往后比较
            }
        }
        //当有一个部分的越界后,另一个部分可能还没找完
        while(i<=q){//再找一遍,确保找完
            t[k++]=arr[i++];
        }
        while(j<=r){//再找一遍,确保找完
            t[k++]=arr[j++];
        }
        for(int l=p;l<=r;l++){//将排序数组的顺序返回arr数组
            arr[l]=t[l];
        }
        /********** End *********/
    }

    private static void print(int arr[]) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

以下是测试样例:

测试输入:

  1. 6
  2. 1 5 4 3 2 6

预期输出:

 第4关:快速排序

任务描述

本关任务:实现快速排序。

相关知识

快速排序由C. A. R. Hoare1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

快速排序

快速排序的基本思想是: 1.先从数列中取出一个数作为基准数。 2.将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。 3.再对左右区间重复第二步,直到各区间只有一个数。

现在假设我们对6 1 2 7 9 3 4 5 10 810个数进行排序。首先在这个序列中找一个数作为基准数。为了方便,取第一个数6作为基准数。接下来,需要将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放在6的左边,类似下面这种排列: 3 1 2 5 4 6 9 7 10 8 具体过程是:从右往左找比6小的数,从左往右找6大的数,然后把这两个数交换,如下图所示,

最后得到3 1 2 5 4 6 9 7 10 8

我们接着在对6的左右区间分别进行同样的操作。会得到类似1 2 3 5 48 7 9 10的排列。直到区间只有一个数,处理结束。

代码:  
package step4;

/**
 * Created by sykus on 2018/3/20.
 */
public class QuickSort {

    public void sort(int arr[], int low, int high) {
        /********** Begin *********/
        int i=low;//左边界,为默认主元,所以从low+1开始找,所以下面循环++i,i先加1
        int j=high+1;//右边界,high+1,所以下面循环--j,j先减1
        //主元默认为左边第一个数,arr[low]
        while(i<j){//i大于j则跳出
            while(j>low && arr[--j]>=arr[low]);//从右往左找一个比主元小的数
            while(i<high && arr[++i]<=arr[low]);//从左往右找一个比主元大的数
            if(i<j)//如果i小于j就交换
            {
            int t=arr[j];
            arr[j]=arr[i];
            arr[i]=t;
            print(arr);//每次交换都要输出
            }
            else break;//i大于j则跳出
        }
        int t=arr[j];//交换下标j与主元的位置
        arr[j]=arr[low];
        arr[low]=t;
        print(arr);//一个输出方法
        if(i>low) sort(arr,low,j-1);//如果i没越界,将右边界左移,左边界默认为主元从
        if(j<high)sort(arr,j+1,high);//如果j没越界,将左边界右移
        /********** End *********/
    }


    private static void print(int arr[]) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

以下是测试样例:

测试输入:

  1. 10
  2. 6 1 2 7 9 3 4 5 10 8

预期输出:

 第5关:堆排序

任务描述

本关任务:在本关,我们将实现另一种排序算法——堆排序(heapsort)。

相关知识

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。 当一个含有n个元素的数组{k1​, k2​... ki​...kn​},当且仅当满足下列关系时称之为堆: (ki​ <= k2i​, ki​ <= k2i​+1)或者(ki​ >= k2i​, ki​ >= k2i​+1), (i = 1, 2, 3, 4... n/2)

即,如果用堆中的元素依次从上至下,从左至右构建一棵完全二叉树,那么这棵二叉树的任意节点的值都大于其子节点的值(或都小于其子结点的值),将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质

通常堆是通过一维数组来实现的。在索引起始位置为1的情形中: 父节点i的左子节点在位置 (2i); 父节点i的右子节点在位置 (2i+1);

大根堆堆顶元素最大

堆排序

堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得选取最大(或最小)关键字变得简单。

用大根堆排序的基本思想
  1. 先将初始数组R[1..n]构造成一个大根堆,此堆为初始的无序区。
  2. 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
  3. 由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
  4. 直到无序区只有一个元素为止。
大根堆排序算法的基本操作
  1. 建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。
  2. 调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交换节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。
  3. 堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。
代码:  
package step5;

/**
 * Created by sykus on 2018/3/20.
 */
public class HeapSort {

    public static void sort(int arr[]) {
        /********** Begin *********/
        int n=arr.length;//存储数组长度
        //先将初始数组数据从上到下从左到右摆成一个完全二叉树
        for(int i=n/2-1;i>=0;i--){//从n/2-1的下标开始
            BuildPile(arr,i,n);//导入数组以及当前需要调整的数的下标,数组长度
        }
        for(int i=n-1;i>0;i--){
            int t=arr[0];//将第一个数即最大值与最后一个没被排好的数交换
            arr[0]=arr[i];
            arr[i]=t;
            BuildPile(arr,0,i);//从0~i重新建堆
            print(arr);//一个输出方法,下面可以看见
        }
    }
    //需要自己写一个递归方法
public static void BuildPile(int[] arr,int f,int n){
        int max=f;//存储最大值的下标
        int lc=2*f+1;//左子树下标
        int rc=2*f+2;//右子树下标
        if(lc<n && arr[lc]>arr[max]){//如果下标没有超过数组表示存在,比较大小
            max=lc;//如果大就存储
        }
        if(rc<n && arr[rc]>arr[max]){//如果下标没有超过数组表示存在,比较大小
            max=rc;//如果大就存储
        }
        if(f==max)//如果最大值是本身则返回
        {
            return;
        }
        //否则交换,他们的值
            int t=arr[f];
            arr[f]=arr[max];
            arr[max]=t;
            f=max;//查找max值的左右子树
            BuildPile(arr,f,n);
    }
        /********** End *********/
    private static void print(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

}

以下是测试样例:

测试输入:

  1. 8
  2. 2 8 7 1 3 5 6 4

预期输出:

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

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

相关文章

Prometheus配置Grafana监控大屏(Docker)

拉取镜像 docker pull grafana/grafana挂载目录 mkdir /data/prometheus/grafana -p chmod 777 /data/prometheus/grafana临时启动 docker run -d -p 3000:3000 --name grafana grafana/grafana从容器拷贝配置文件至对应目录 docker exec -it grafana cat /etc/grafana/gra…

[C++]:12:模拟实现list

[C]:12:模拟实现list 一.看一看SGI的stl_list的源码&#xff1a;1.基础结构构造函数1.节点结构&#xff1a;2.节点构造函数&#xff1a;3.链表结构&#xff1a;4.链表的构造函数&#xff1a; 2.析构1.节点析构&#xff1a;2.链表的析构&#xff1a; 3.迭代器 二.模拟实现list1.…

PyTorch深度学习实战(31)——生成对抗网络(Generative Adversarial Network, GAN)

PyTorch深度学习实战&#xff08;31&#xff09;——生成对抗网络 0. 前言1. GAN2. GAN 模型分析3. 利用 GAN 模型生成手写数字小结系列链接 0. 前言 生成对抗网络 (Generative Adversarial Networks, GAN) 是一种由两个相互竞争的神经网络组成的深度学习模型&#xff0c;它由…

EOCR电机保护器带煤电厂的具体应用

EOCR系列电动机智能保护器在煤电厂中有广泛的应用。这些保护器具有齐全的保护功能、直观的测量参数、快速的反应灵敏度、可靠的行动以及与上位机通讯构成远程监控的能力&#xff0c;使其成为理想的低压电动机保护及远程监控产品。 在煤电厂中&#xff0c;电动机保护器需要具备过…

SpringCloud Aliba-Sentinel【上篇】-从入门到学废【4】

&#x1f3b5;诗词分享&#x1f3b5; 大江东去&#xff0c;浪淘尽&#xff0c;千古风流人物。 ——苏轼《念奴娇赤壁怀古》 目录 &#x1f37f;1.Sentinel是什么 &#x1f9c2;2.特点 &#x1f9c8;3.下载 &#x1f32d;4.sentinel启动 &#x1f953;5.实例演示 1.Senti…

IOT pwn

已经过了填坑的黄金时期 环境搭建 交叉编译工具链 很多开源项目需要交叉编译到特定架构上&#xff0c;因此需要安装对应的交叉编译工具链。 sudo apt install gcc-arm-linux-gnueabi g-arm-linux-gnueabi -y sudo apt install gcc-aarch64-linux-gnu g-aarch64-linux-gnu -…

RK3568笔记十:Zlmediakit交叉编译

若该文为原创文章&#xff0c;转载请注明原文出处。 编译Zlmediakit的主要目的是想实现在RK3568拉取多路RTPS流&#xff0c;并通过MPP硬解码&#xff0c;DRM显示出来。为了实现拉取多路流选择了Zlmediakit,使用FFMEPG也可以&#xff0c;在RV1126上已经验证了可行性。 一、环境…

对MODNet 主干网络 MobileNetV2的剪枝探索

目录 1 引言 1.1 MODNet 原理 1.2 MODNet 模型分析 2 MobileNetV2 剪枝 2.1 剪枝过程 2.2 剪枝结果 2.2.1 网络结构 2.2.2 推理时延 2.3 实验结论 3 模型嵌入 3.1 模型保存与加载 法一&#xff1a;保存整个模型 法二&#xff1a;仅保存模型的参数 小试牛刀 小结…

服务端实现微信小游戏登录

1 微信小程序用户登录及其流程 小程序可以通过微信官方提供的登录能力,便能方便的获取微信提供的用户身份标识,达到建立用户体系的作用。 官方文档提供了登录流程时序图,如下: 从上述的登录流程时序图中我们发现,这里总共涉及到三个概念。 第一个是小程序,小程序即我们…

C#,入门教程(30)——扎好程序的笼子,错误处理 try catch

上一篇&#xff1a; C#&#xff0c;入门教程(29)——修饰词静态&#xff08;static&#xff09;的用法详解https://blog.csdn.net/beijinghorn/article/details/124683349 程序员语录&#xff1a;凡程序必有错&#xff0c;凡有错未必改&#xff01; 程序出错的原因千千万&…

Rockchip linux USB 驱动开发

Linux USB 驱动架构 Linux USB 协议栈是一个分层的架构&#xff0c;如下图 5-1 所示&#xff0c;左边是 USB Device 驱动&#xff0c;右边是 USB Host 驱动&#xff0c;最底层是 Rockchip 系列芯片不同 USB 控制器和 PHY 的驱动。 Linux USB 驱动架构 USB PHY 驱动开发 USB 2…

LeetCode 77. 组合

77. 组合 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示例 2&#xff1a; 输入&#xff1a;…

Kafka(八)使用Kafka构建数据管道

目录 1 使用场景2 构建数据管道时需要考虑的问题2.1 及时性2.2 可靠性高可用可靠性数据传递 2.3 高吞吐量2.4 数据格式2.5 转换ETLELT 2.6 安全性2.7 故障处理2.8 耦合性和灵活性临时数据管道元数据丢失末端处理 3 使用Connect API3.1 Connect的数据处理流程sourcesinkconnecto…

csrf漏洞之DedeCMS靶场漏洞(超详细)

1.Csrf漏洞&#xff1a; 第一步&#xff0c;查找插入点&#xff0c;我选择了网站栏目管理的先秦两汉作为插入点 第二步修改栏目名称 第三步用burp拦截包 第四步生成php脚本代码 第五步点击submit 第六步提交显示修改成功 第二个csrf 步骤与上述类似 红色边框里面的数字会随着…

第91讲:MySQL主从复制集群主库与从库状态信息的含义

文章目录 1.主从复制集群正常状态信息2.从库状态信息中重要参数的含义 1.主从复制集群正常状态信息 通过以下命令查看主库的状态信息。 mysql> show processlist;在主库中查询当前数据库中的进程&#xff0c;看到Master has sent all binlog to slave; waiting for more u…

Rocky Linux 8.9 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

2023 IoTDB Summit:北京城建智控科技股份有限公司高级研发主管刘喆《IoTDB在城市轨道交通综合监控系统中的应用》...

12 月 3 日&#xff0c;2023 IoTDB 用户大会在北京成功举行&#xff0c;收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题&#xff0c;多位学术泰斗、企业代表、开发者&#xff0c;深度分享了工业物联网时序数据库 IoTDB 的技术创新…

Laykefu客服系统 任意文件上传漏洞复现

0x01 产品简介 Laykefu 是一款基于workerman+gatawayworker+thinkphp5搭建的全功能webim客服系统,旨在帮助企业有效管理和提供优质的客户服务。 0x02 漏洞概述 Laykefu客服系统/admin/users/upavatar.html接口处存在文件上传漏洞,而且当请求中Cookie中的”user_name“不为…

SpringBoot+Email发送邮件

引言 邮件通知是现代应用中常见的一种通信方式&#xff0c;特别是在需要及时反馈、告警或重要事件通知的场景下。Spring Boot提供了简单而强大的邮件发送功能&#xff0c;使得实现邮件通知变得轻而易举。本文将研究如何在Spring Boot中使用JavaMailSender实现邮件发送&#xf…

geemap学习笔记052:影像多项式增强

前言 下面介绍的主要内容是应用Image.polynomial() 对图像进行多项式增强。 1 导入库并显示地图 import ee import geemap ee.Initialize() Map geemap.Map(center[40, -100], zoom4)2 多项式增强 # 使用函数 -0.2 2.4x - 1.2x^2 对 MODIS 影像进行非线性对比度增强。# L…