数据结构与算法:排序算法(2)

news2024/11/28 6:44:05

目录

堆排序

使用步骤

代码实现

计数排序

适用范围

过程

代码实现

排序优化

桶排序

工作原理

代码实现


堆排序

二叉堆的特性:

        1. 最大堆的堆顶是整个堆中的最大元素

        2. 最小堆的堆顶是整个堆中的最小元素

        以最大堆为例,如果删除一个最大堆的堆顶(并不是完全删除,而是跟末尾的节点交换位置),经过自我调整,第2大的元素就会被交换上来,成为最大堆的新堆顶

        在删除值为10的堆顶节点后,经过调整,值为9的新节点就会顶替上来;由于二叉堆的这个特性,每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么只要反复删除堆顶,反复调整二叉堆,所得到的集合就会成为一个有序集合。

使用步骤

1. 把无序数组构建成二叉堆。需要从小到大排序,则构建成最大堆;需要从大到小排序,则构建成最小堆

2. 循环删除堆顶元素,替换到二叉堆的末尾,调整堆产生新的堆顶

代码实现

public static void main(String[] args){
        int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};
        heapSort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void downAdjust(int[] array, int parentIndex, int length) {
        int temp = array[parentIndex];
        int childIndex = 2 * parentIndex + 1;

        while (childIndex < length){
            if (childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) {
                childIndex++;
            }

            if (temp >= array[childIndex]){
                break;
            }

            array[parentIndex] = array[childIndex];
            parentIndex = childIndex;
            childIndex = 2 * childIndex + 1;
        }
        array[parentIndex] = temp;
    }

    public static void heapSort(int[] array) {
        //1.无序数组构建成最大堆
        for (int i = (array.length-2)/2; i >= 0; i--) {
            downAdjust(array, i, array.length);
        }

        System.out.println(Arrays.toString(array));

        //2.环删除堆顶元素,移到集合尾部,调整堆产生新的堆顶
        for (int i = array.length - 1; i > 0; i--) {
            int temp = array[i];
            array[i] = array[0];
            array[0] = temp;

            downAdjust(array, 0, i);
        }
    }

计数排序

有一些特殊的排序并不基于元素比较,而是利用数组下标来确定元素的正确位置的。

适用范围

它适用于一定范围内的整数排序。在取值范围不是很大的情况下,它的性能甚至快过那些时间复杂度为O(nlogn)的排序

过程

假设数组中有20个随机整数,取值范围为0~10,要求用最快的速度把这20个整数从小到大进行排序,可以根据这有限的范围,建立一个长度为11的数组。数组下标从0到10,元素初始值全为0

随机值:9,3,5,4,9,1,2,7,8,1,3,6,5,3,4,0,10,9 ,7,9

这个无序的随机数列,每一个整数按照其值对号入座,同时,对应数组下标的元素进行加1操作

该数组中每一个下标位置的值代表数列中对应整数出现的次数;直接遍历数组,输出数组元素的下标值,元素的值是几,就输出几次,输出的数列已经是有序的了

代码实现

public static void main(String[] args){
        int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};
        int[] sortedArray = countSort(array);
        System.out.println(Arrays.toString(sortedArray));
    }

    public static int[] countSort(int[] array) {
        //1.得到数列的最大值
        int max = array[0];

        for(int i=1; i<array.length; i++){
            if(array[i] > max){
                max = array[i];
            }
        }

        //2.根据数列最大值确定统计数组的长度
        int[] countArray = new int[max+1];

        //3.遍历数列,填充统计数组
        for(int i=0; i<array.length; i++){
            countArray[array[i]]++;
        }

        //4.遍历统计数组,输出结果
        int index = 0;
        int[] sortedArray = new int[array.length];

        for(int i=0; i<countArray.length; i++){
            for(int j=0; j<countArray[i]; j++){
                sortedArray[index++] = i;
            }
        }
        return sortedArray;
    }

排序优化

只以数列的最大值来决定统计数组的长度,其实并不严谨;如:数列的最大值是99,但最小的整数是90。如果创建长度为100的数组,那么前面从0到89的空间位置就都浪费了

解决:

        以数列最大值-最小值+1作为统计数组的长度

同时,数列的最小值作为一个偏移量,用于计算整数在统计数组中的下标

public static void main(String[] args){
        int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};
        int[] sortedArray = countSort(array);
        System.out.println(Arrays.toString(sortedArray));
    }

    public static int[] countSort(int[] array) {
        //1.得到数列的最大值和最小值,并算出差值d
        int max = array[0];
        int min = array[0];

        for(int i=1; i<array.length; i++){
            if(array[i] > max){
                max = array[i];
            }
            if(array[i] < min){
                min = array[i];
            }
        }

        int d = max - min;

        //2.创建统计数组并统计对应元素的个数
        int[] countArray = new int[d+1];

        for(int i=0; i<array.length; i++){
            countArray[array[i]-min]++;
        }

        //3.统计数组做变形,后面的元素等于前面的元素之和
        for(int i=1;i<countArray.length;i++) {
            countArray[i] += countArray[i-1];
        }

        //4.遍历统计数组,输出结果
        int[] sortedArray = new int[array.length];

        for(int i=array.length-1;i>=0;i--) {
            sortedArray[countArray[array[i]-min]-1]=array[i];
            countArray[array[i]-min]--;
        }
        return sortedArray;
    }

桶排序

桶排序是一种线性时间的排序算法。类似于计数排序所创建的统计数组,桶排序需要创建若干个桶来协助排序。

桶:每一个桶(bucket)代表一个区间范围,里面可以承载一个或多个元素。

工作原理

1.创建桶,并确定每一个桶的区间范围

        创建的桶数量等于原始数列的元素数量

        区间跨度 = (最大值-最小值)/ (桶的数量 - 1)

2.遍历原始数列,把元素对号入座放入各个桶中

3.对每个桶内部的元素分别进行排序

4.遍历所有的桶,输出所有元素

代码实现

public static void main(String[] args){
        double[] array = new double[]{4.12,6.421,0.0023,3.0,2.123,8.122,4.12, 10.09};
        double[] sortedArray = bucketSort(array);
        System.out.println(Arrays.toString(sortedArray));
    }

    public static double[] bucketSort(double[] array){

        //1.得到数列的最大值和最小值,并算出差值d
        double max = array[0];
        double min = array[0];

        for(int i=1; i<array.length; i++) {
            if(array[i] > max){
                max = array[i];
            }

            if(array[i] < min){
                min = array[i];
            }
        }

        double d = max - min;

        //2.初始化桶
        int bucketNum = array.length;

        ArrayList<LinkedList<Double>> bucketList = new ArrayList<LinkedList<Double>>(bucketNum);

        for(int i=0;i<bucketNum;i++){
            bucketList.add(new LinkedList<Double>());
        }

        //3.遍历原始数组,将每个元素放入桶中
        for(int i = 0; i < array.length; i++){
            int num = (int)((array[i] - min) * (bucketNum-1) / d);
            bucketList.get(num).add(array[i]);
        }

        //4.对每个桶内部进行排序
        for(int i = 0; i < bucketList.size(); i++){
            Collections.sort(bucketList.get(i));
        }

        //5.输出全部元素
        double[] sortedArray = new double[array.length];
        int index = 0;

        for(LinkedList<Double> list : bucketList){
            for(double element : list){
                sortedArray[index] = element;
                index++;
            }
        }
        return sortedArray;
    }

        所有的桶都保存在ArrayList集合中,每一个桶都被定义成一个链表(LinkedList<Double>),这样便于在尾部插入元素

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

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

相关文章

基于Java开发的数字化询价招标采购系统(SRM系统源码)

在如今商业环境中&#xff0c;企业的采购流程变得越来越重要。传统的采购方式可能存在诸多弊端&#xff0c;例如效率低下、信息不透明、易滋生腐败等。为了解决这些问题&#xff0c;许多企业开始转向SRM&#xff08;供应商关系管理&#xff09;系统。本文将详细介绍SRM数字询价…

js表单autocomplete=‘off‘失效问题

众所周知。。。。autocomplete是Html5中的新属性&#xff0c;有‘off’,on’两个属性。作用是点击输入框时&#xff0c;会打开或者关闭提示信息。 部分浏览器也会出现失效的情况&#xff08;emmmm…&#xff0c;毕竟是html5新增的&#xff0c;有点bug也正常哈&#xff09;。 …

初识Java 10-1 集合

目录 泛型和类型安全的集合 基本概念 添加一组元素 打印集合 List Iterator&#xff08;迭代器&#xff09; 本笔记参考自&#xff1a; 《On Java 中文版》 在进行程序设计时我们会发现&#xff0c;程序总是会根据某些在运行时才能知道的条件来创建新的对象。这意味着&am…

Vue3 - 实现动态获取菜单路由和按钮权限控制指令

GitHub Demo 地址 在线预览 前言 关于动态获取路由已在这里给出方案 Vue - vue-admin-template模板项目改造&#xff1a;动态获取菜单路由 这里是在此基础上升级成vue3和ts&#xff0c;数据和网络请求是通过mock实现的 具体代码请看demo!!! 本地权限控制&#xff0c;具体是通过…

关于若依(ruoyi)前端,f12跟踪失效的问题处理

1、根据作者反馈&#xff0c;使用了vite-plugin-vue-setup-extend该插件&#xff1b; 2、参考作者指导&#xff0c;我采用了去掉这个插件的方法&#xff1b; 具体操作&#xff1a; &#xff08;1&#xff09;找到package.json,去掉该插件&#xff1b; &#xff08;2&#xff…

新的小伙伴加入,开始系统更新分享了

近几个月一直有一个好消息未跟大家分享&#xff0c;就是我们有新的小伙伴加入了&#xff0c;帅就不必说了&#xff0c;关键是对电控的理解那可不是一般的强&#xff0c;工程经验丰富&#xff0c;学术能力也是一等一的。我们有幸在一个公司工作&#xff0c;跟着一个企业导师学习…

10个值得关注的学习网站,知乎超30万人收藏,什么资源都可找到!

hi&#xff0c;大家好我是技术苟&#xff0c;每周准时上线为你带来实用黑科技&#xff01;由于公众号改版&#xff0c;现在的公众号消息已经不再按照时间顺序排送了。因此小伙伴们就很容易错过精彩内容。喜欢黑科技的小伙伴&#xff0c;可以将黑科技百科公众号设为标星&#xf…

Webstorm怎么导入插件

Webstorm怎么导入插件&#xff1a; 1.点击“File”&#xff0c;选择“Settings” 2.选择“Plugins” 3.如下图所示继续操作 4.选择想要导入的插件

【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

自动化测试:yaml结合ddt实现数据驱动!

在pythonunittestseleniumddt的框架中&#xff0c;数据驱动常见有以下几种方式实现&#xff1a; Csv/txtExcelYAML 本文主要给大家介绍测试数据存储在YAML文件中的使用场景。首先先来简单介绍一下YAML。 1. 什么是YAML 一种标记语言类似YAML&#xff0c;它实质上是一种通用…

方案:浅析AI视频分析与视频监控技术的工厂车间智能化监管方案

一、方案背景 工厂生产车间一般是从原材料到成品的流水作业&#xff0c;有大量器械和物料。为保障车间财产安全并提高生产效率&#xff0c;需要进行全面的监管。在生产制造流水线的关键工序中&#xff0c;不仅有作业过程监管需求&#xff0c;同时&#xff0c;也存在生产发生异…

全网最全知识图谱讲解!

什么是知识图谱 知识图谱标准化白皮书定义&#xff1a;知识图谱&#xff08;Knowledge Graph&#xff09;以结构化的形式描述客观世界中概念、实体及其关系&#xff0c;将互联网的信息表达成更接近人类认知世界的形式&#xff0c;提供了一种更好地组织、管理和理解互联网海量信…

Jmeter怎么实现接口关联?

用于接口测试时&#xff0c;后一个接口经常需要用到前一次接口返回的结果&#xff0c;应该如何获取前一次请求的结果值&#xff0c;应用于后一个接口呢&#xff0c;拿一个登录的例子来说明如何获取。 1、打开jmeter&#xff0c;新建一个测试计划&#xff0c;在测试计划里新建一…

分享基于SringBoot足球训练俱乐部系统Python训练打卡系统(源码+调试+lw)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

SMS--短信服务

1 短信服务介绍 短信服务&#xff08;Short Message Service&#xff09;是阿里云为用户提供的一种通信服务的能力。 2 短信服务使用 接下来,我们使用短信验证码功能来演示短信服务的使用。流程如下: 2.1 准备工作 2.1.1 实名认证 https://help.aliyun.com/document_detail…

智能箱式浪涌保护器综合行业解决方案

智能箱式浪涌保护器是一种集成了多种功能的浪涌保护装置&#xff0c;它可以对电力系统、通信系统、计算机系统、工业控制系统等设备提供有效的防雷和过电压保护。本文将详细介绍智能箱式浪涌保护器的作用和原理&#xff0c;以及在不同行业中的应用方案&#xff0c;并参考相关的…

【Hash表】两数之和-力扣 1 题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

【国产32位mcu】电动车控制芯片CS32F031C8T6的应用

近年来&#xff0c;随着“新国标”的落地&#xff0c;双轮电动车在智能化、强性能、安全性等方面不断演进&#xff0c;带动了新一轮的换车高峰。电动车控制器作为双轮电动车的核心部件&#xff0c;迎来新的增长。 芯海科技32位MCU CS32F031C8T6&#xff0c;作为电动车控制器的…

多因素身份验证MFA功能

随着信息技术的不断进步&#xff0c;网络威胁也随之不断升级和演化。为了保护敏感数据和网络资源&#xff0c;企业和组织需要采取更多的安全措施强化信息安全。多因素身份验证&#xff08;MFA&#xff09;已经成为了现代安全战略的核心组成部分之一。 在这篇文章中&#xff0…

软件工程第一次作业参考答案

题目 名词解释&#xff1a;软件危机、软件、软件工程、软件生命周期、瀑布模型、原型模型、增量模型、喷泉模型、敏捷过程模型。 答案 软件危机&#xff1a;软件危机是指在软件开发过程中所面临的一系列问题和挑战&#xff0c;包括成本超支、进度延误、质量不达标等。 软件…