桶排序算法及优化(java)

news2024/9/21 14:46:03

目录

1.1 引言

1.2 桶排序的历史

1.3 桶排序的基本原理

1.3.1 工作流程

1.3.2 关键步骤

1.4 桶排序的Java实现

1.4.1 简单实现

1.4.2 优化实现

1.4.3 代码解释

1.5 桶排序的时间复杂度

1.5.1 分析

1.5.2 证明

1.6 桶排序的稳定性

1.7 著名案例

1.7.1 应用场景

1.7.2 具体案例

1.8 桶排序的优化方案

1.8.1 选择合适的桶数量

1.8.2 桶内排序算法的选择

1.8.3 处理数据分布不均的情况

1.8.4 Java示例代码

1.8.5 代码解释

1.9 总结

1.1 引言

桶排序是一种非比较型整数排序算法,它通过将元素分布到有限数量的“桶”中,然后对每个桶内的元素进行排序(通常使用其他排序算法),最后按顺序合并各个桶来完成排序。本文将详细介绍桶排序的历史背景、工作原理,并通过具体案例来阐述其应用。此外,还将探讨桶排序的不同优化方案,并给出相应的Java代码示例。

1.2 桶排序的历史

桶排序的思想可以追溯到20世纪初期,它最初是为了处理大规模数据集而提出的。随着计算机科学的发展,桶排序逐渐成为一种常用的排序算法,尤其是在需要快速处理大量相似范围内的数据时。

桶排序之所以重要,是因为它可以在特定条件下达到线性时间复杂度 O(n),这对于某些特定的数据分布非常有效。特别是当输入数据分布在一定范围内时,桶排序可以提供非常高的排序效率。

1.3 桶排序的基本原理

先来看个示例,老师安排同学们考试结束后,接到教学主任的通知需要马上把同学们的分数统计并做好排序,但是他来到教室,发现教室后面只有5个垃圾桶,老师冥思苦想,要用这几个垃圾桶怎么把同学们的分数给排名出来呢?

  • 首先还是给垃圾桶标号,这个还是不能少的。
  • 约定,1号垃圾桶放分数是1-20的同学的成绩单,2号垃圾桶放分数是20-40的同学的成绩单,3号垃圾桶放分数是40-60的同学的成绩单,4号垃圾桶放分数是60-80的同学的成绩单,5号垃圾桶放分数是80-100的同学的成绩单。
  • 当向同一个垃圾桶放入新数据的时候,先判断桶中最高分成绩和新放入成绩的大小,如果比原来最高分还高,则把新插入成绩放在原来成绩的后面。
  • 否则,把放入的新的成绩单与原来的成绩单从后往前依次比较,如果存在的成绩大于新放入的成绩,则存在的成绩往后挪一个位置,循环比较已存放的所有成绩单,如第一个桶已经有了63,再插入51,67后,桶中的排序为(51,63,67)一般通过链表来存放桶中数据。
  • 阿布老师依次从1~5号桶捡起自己仍进来的成绩单,(然后依次输出所有(非空)桶里面的数据)最后完成排序。

1.3.1 工作流程

桶排序的基本步骤如下:

  1. 初始化:根据输入数据的范围和特性,创建适当数量的空桶。
  2. 分配:遍历输入数组,将每个元素放入对应的桶中。
  3. 排序:对每个桶内的元素进行排序(可以使用任何排序算法,如插入排序)。
  4. 合并:按顺序合并各个桶中的元素,得到最终排序结果。

1.3.2 关键步骤

  • 桶的选择:根据数据的分布选择合适的桶数量。
  • 桶内排序:选择适当的排序算法对每个桶内的数据进行排序。
  • 合并桶:按顺序合并各个桶中的数据。

1.4 桶排序的Java实现

1.4.1 简单实现

下面是一个简单的桶排序Java代码示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BucketSortSimple {

    public static void bucketSort(int[] array) {
        if (array == null || array.length == 0) {
            return;
        }

        int max = getMax(array);
        List<List<Integer>> buckets = createBuckets(max, array.length);
        distributeElements(array, buckets);
        sortAndMerge(buckets, array);
    }

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

    private static List<List<Integer>> createBuckets(int max, int bucketCount) {
        List<List<Integer>> buckets = new ArrayList<>(bucketCount);
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<>());
        }
        return buckets;
    }

    private static void distributeElements(int[] array, List<List<Integer>> buckets) {
        for (int element : array) {
            int index = element / (buckets.size() - 1);
            buckets.get(index).add(element);
        }
    }

    private static void sortAndMerge(List<List<Integer>> buckets, int[] array) {
        int index = 0;
        for (List<Integer> bucket : buckets) {
            Integer[] bucketArray = bucket.toArray(new Integer[0]);
            Arrays.sort(bucketArray);
            for (Integer value : bucketArray) {
                array[index++] = value;
            }
        }
    }

    public static void main(String[] args) {
        int[] array = {4, 2, 2, 8, 3, 3, 1};
        System.out.println("原始数组:");
        printArray(array);

        bucketSort(array);

        System.out.println("排序后的数组:");
        printArray(array);
    }

    private static void printArray(int[] array) {
        for (int value : array) {
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

1.4.2 优化实现

接下来是一个优化后的桶排序Java代码示例,其中考虑了更多的细节,如桶的数量选择、桶内排序算法的选择等:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BucketSortOptimized {

    public static void bucketSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }

        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int value : array) {
            if (value < min) min = value;
            if (value > max) max = value;
        }

        int range = max - min + 1;
        int bucketCount = (int) Math.sqrt(array.length); // 选择桶的数量
        List<List<Integer>> buckets = createBuckets(bucketCount);

        // 分配元素到桶中
        for (int value : array) {
            int index = (value - min) * bucketCount / range;
            buckets.get(index).add(value);
        }

        // 排序并合并桶
        sortAndMerge(buckets, array, min);

    }

    private static List<List<Integer>> createBuckets(int bucketCount) {
        List<List<Integer>> buckets = new ArrayList<>(bucketCount);
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<>());
        }
        return buckets;
    }

    private static void sortAndMerge(List<List<Integer>> buckets, int[] array, int min) {
        int index = 0;
        for (List<Integer> bucket : buckets) {
            Integer[] bucketArray = bucket.toArray(new Integer[0]);
            Arrays.sort(bucketArray);
            for (Integer value : bucketArray) {
                array[index++] = value;
            }
        }
    }

    public static void main(String[] args) {
        int[] array = {4, 2, 2, 8, 3, 3, 1};
        System.out.println("原始数组:");
        printArray(array);

        bucketSort(array);

        System.out.println("排序后的数组:");
        printArray(array);
    }

    private static void printArray(int[] array) {
        for (int value : array) {
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

1.4.3 代码解释

  • 初始化:找到数组中的最小值和最大值,以确定数据的范围。
  • 桶的选择:根据数组的大小选择合适的桶数量。
  • 分配:将每个元素分配到对应的桶中。
  • 排序:使用内置的 Arrays.sort() 方法对每个桶内的元素进行排序。
  • 合并:按顺序合并各个桶中的元素。

1.5 桶排序的时间复杂度

桶排序的时间复杂度取决于桶的数量、桶内排序算法的时间复杂度以及输入数据的分布情况。

平均时间复杂度:O(n + k)
最佳时间复杂度:O(n + k)
最差时间复杂度:O(n ^ 2)
空间复杂度:O(n * k)
稳定性:稳定

桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。 

1.6 桶排序的稳定性

桶排序是稳定的排序算法,只要桶内排序也是稳定的,桶排序就能保持输入数据的相对顺序不变。

1.7 著名案例

1.7.1 应用场景

桶排序在处理大规模数据集时特别有用,尤其是当数据分布较为均匀时。下面通过一个具体的案例来说明桶排序的应用。

1.7.2 具体案例

案例描述:假设我们有一个包含100000个整数的数组,这些整数的范围在1到1000之间。我们需要快速地对这些整数进行排序。

解决方案:使用桶排序可以有效地解决这个问题。

  1. 初始化:创建1000个空桶。
  2. 分配:遍历数组,将每个整数分配到对应的桶中。
  3. 排序:对每个桶内的元素使用计数排序。
  4. 合并:按顺序合并各个桶中的元素。

具体步骤

  1. 初始化:创建1000个空桶。
  2. 分配:遍历数组,将每个整数分配到对应的桶中。
  3. 排序:对每个桶内的元素使用计数排序。
  4. 合并:按顺序合并各个桶中的元素。

效果:由于数据分布较为均匀,桶排序可以快速完成排序任务,且时间复杂度接近 O(n)。

1.8 桶排序的优化方案

1.8.1 选择合适的桶数量

选择合适的桶数量对于桶排序的性能至关重要。一个常见的做法是使用根号n作为桶的数量,其中 n 是数组的长度。

1.8.2 桶内排序算法的选择

对于桶内的排序,可以选择更高效的排序算法,如计数排序或基数排序,以减少排序的时间复杂度。

1.8.3 处理数据分布不均的情况

当数据分布不均时,可以通过预处理步骤来改善数据分布,如对数据进行归一化处理。

1.8.4 Java示例代码

下面是一个考虑了更多优化因素的桶排序Java代码示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BucketSortAdvanced {

    public static void bucketSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }

        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int value : array) {
            if (value < min) min = value;
            if (value > max) max = value;
        }

        int range = max - min + 1;
        int bucketCount = (int) Math.sqrt(array.length); // 选择桶的数量
        List<List<Integer>> buckets = createBuckets(bucketCount);

        // 分配元素到桶中
        for (int value : array) {
            int index = (value - min) * bucketCount / range;
            buckets.get(index).add(value);
        }

        // 排序并合并桶
        sortAndMerge(buckets, array, min);

    }

    private static List<List<Integer>> createBuckets(int bucketCount) {
        List<List<Integer>> buckets = new ArrayList<>(bucketCount);
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<>());
        }
        return buckets;
    }

    private static void sortAndMerge(List<List<Integer>> buckets, int[] array, int min) {
        int index = 0;
        for (List<Integer> bucket : buckets) {
            Integer[] bucketArray = bucket.toArray(new Integer[0]);
            countSort(bucketArray); // 使用计数排序
            for (Integer value : bucketArray) {
                array[index++] = value;
            }
        }
    }

    private static void countSort(Integer[] array) {
        int minVal = Integer.MAX_VALUE;
        int maxVal = Integer.MIN_VALUE;
        for (int value : array) {
            if (value < minVal) minVal = value;
            if (value > maxVal) maxVal = value;
        }

        int range = maxVal - minVal + 1;
        int[] count = new int[range];

        for (int value : array) {
            count[value - minVal]++;
        }

        int index = 0;
        for (int i = 0; i < range; i++) {
            while (count[i] > 0) {
                array[index++] = i + minVal;
                count[i]--;
            }
        }
    }

    public static void main(String[] args) {
        int[] array = {4, 2, 2, 8, 3, 3, 1};
        System.out.println("原始数组:");
        printArray(array);

        bucketSort(array);

        System.out.println("排序后的数组:");
        printArray(array);
    }

    private static void printArray(int[] array) {
        for (int value : array) {
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

1.8.5 代码解释

  • 初始化:找到数组中的最小值和最大值,以确定数据的范围。
  • 桶的选择:根据数组的大小选择合适的桶数量。
  • 分配:将每个元素分配到对应的桶中。
  • 排序:使用计数排序对每个桶内的元素进行排序。
  • 合并:按顺序合并各个桶中的元素。

1.9 总结

桶排序是计数排序的变种,它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。把计数排序中相邻的m个”小桶”放到一个”大桶”中,在分完桶后,对每个桶进行排序(一般用快排),然后合并成最后的结果。

算法思想和散列中的开散列法差不多,当冲突时放入同一个桶中;可应用于数据量分布比较均匀,或比较侧重于区间数量时。

桶排序最关键的建桶,如果桶设计得不好的话桶排序是几乎没有作用的。通常情况下,上下界有两种取法,第一种是取一个10^n或者是2^n的数,方便实现。另一种是取数列的最大值和最小值然后均分作桶。

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

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

相关文章

基于GPT-SoVITS的API实现批量克隆声音

目标是将每一段声音通过GPT-SoVITS的API的API进行克隆,因为拼在一起的整个片段处理会造成内存或者缓存溢出。 将目录下的音频文件生成到指定目录下,然后再进行拼接。 通过AI工具箱生成的数据文件是这样的结构,temp目录下是没个片段生成的部分,connect_是正常拼接的音频文件…

笨鸟先飞(疯狂的小鸟)小游戏自制分享

《Flappy Bird》是一款由越南独立游戏开发者阮哈东&#xff08;Dong Nguyen&#xff09;制作并发布的移动端小游戏。该游戏最初于2013年上线&#xff0c;在2014年初迅速走红&#xff0c;成为全球范围内的热门现象。 游戏的玩法非常简单&#xff0c;玩家只需通过点击屏幕来控制…

Python | Leetcode Python题解之第355题设计推特

题目&#xff1a; 题解&#xff1a; class Twitter:class Node:def __init__(self):self.followee set()self.tweet list()def __init__(self):self.time 0self.recentMax 10self.tweetTime dict()self.user dict()def postTweet(self, userId: int, tweetId: int) ->…

基于人工智能、三维视觉、混合现实等技术的智慧能源开源了

一、简介 AI视频监控平台, 是一款功能强大且简单易用的实时算法视频监控系统。愿景在最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;减少企业级应用约 95%的开发成本&#xff0c;在强大视频算…

AI学习记录 - LSTM详细拆解

拒绝熬夜&#xff0c;一点点写&#xff0c;拆解LSTM计算过程和最后的总结 遗忘门的计算流程 拼接词向量&#xff0c;前面来的&#xff0c;现在输入的 然后进行计算&#xff1a;

浅谈移动端车牌识别技术的实现过程及应用场景

随着移动互联技术的飞速发展和智能设备的普及&#xff0c;Android、iOS平台上的车牌识别技术逐渐成熟并广泛应用于各个领域。该技术通过智能手机的摄像头捕捉车牌图像&#xff0c;利用先进的图像处理与机器学习算法&#xff0c;实现车牌号码的自动识别。相比传统的人工录入或固…

opencv中Core中的Norm函数解释

1. Norm的类型 NORM_L1&#xff1a; L1 范数&#xff08;曼哈顿范数&#xff09;。数组中所有元素绝对值之和。 NORM_L2&#xff1a; L2 范数&#xff08;欧几里得范数&#xff09;。数组中所有元素平方和的平方根。 NORM_INF&#xff1a;无穷范数&#xff08;最大绝对值范数&…

Nginx的7大调度算法详解

Nginx的7大调度算法详解 一、Sticky二、Round-Robin&#xff08;RR&#xff09;三、Weight四、Least_conn五、IP_hash六、Fair七、URL_hash总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Nginx作为一款高性能的HTTP和反向代理服务器&a…

Linux虚拟机磁盘管理-添加磁盘

添加磁盘--添加前请选关闭虚拟机 添加步骤&#xff1a; 1.编辑虚拟机设置 2.选择硬盘 3.选择SCSI 4.创建新虚拟磁盘 5.设置磁盘大小 6.点击完成 开机的时候会去读取有几块硬盘&#xff0c;总共我们是有4块硬盘&#xff0c;sda\sdb\sdc\sdd 注意&#xff1a;新加的硬盘实际我们…

VScode相关使用、配置

VScode 拉取新分支 点击左下角分支会出现这个 选择创建新分支依据… 选择一个分支为从这个分支拉新分支 输入新分支的名称即可 VScode 合并分支 切到最终要合并到的分支&#xff0c;通过快捷键 shiftctrlp 出现框中 &#xff0c;选择 git 合并分支 选择要合并过来的分…

【Docker】Docker Consul

docker consul Docker Consul 是一个用于服务发现和配置的开源工具&#xff0c;它是 HashiCorp 公司推出的一个项目。Consul 提供了一个中心化的服务注册和发现系统&#xff0c;可以帮助开发人员轻松地在 Docker 容器和集群之间进行服务发现和配置管理。 Consul 使用基于 HTT…

位运算使用

在写代码过程中&#xff0c;适当的位运算是一种提高代码质量的有效手段。 0 位运算 常用的运算符共 6 种&#xff0c;分别为按位与&、按位或|、按位异或^、按位取反~、左移位<<、右移位>>。 0.1 按位与&、按位或|、按位异或^ 按位与&、按位或|、按…

MySQL中处理JSON数据:大数据分析的新方向,MYSQL如何处理JSON数据,参数讲解+实战案例+全网最全

1-3章理论为主&#xff0c;如果想直接看实战和MySQL如何操作JSON可以直接看第4章。 感谢您的观看&#xff0c;如果您喜欢这篇文章或者对您有所帮助的话&#xff0c;动动发财的小手点点关注&#xff0c;一起学习一起进步 第一章 引言 1.1 研究背景与意义 随着大数据技术的迅猛…

回归预测|基于北方苍鹰优化支持向量机的数据回归预测Matlab程序NGO-SVM 多特征输入单输出 高引用先用先创新

回归预测|基于北方苍鹰优化支持向量机的数据回归预测Matlab程序NGO-SVM 多特征输入单输出 高引用先用先创新 文章目录 前言回归预测|基于北方苍鹰优化支持向量机的数据回归预测Matlab程序NGO-SVM 多特征输入单输出 高引用先用先创新 一、NGO-SVM 模型1. 北方苍鹰优化算法&#…

vue3+ts封装axios以及解决跨域问题

目录 一、前言二、封装axios三、 解决跨域四、调用接口五、运行结果 一、前言 前端请求后端数据时&#xff0c;会用到axios&#xff0c;但是如果不将axios封装好&#xff0c;会导致代码冗余 二次封装的好处如下&#xff1a; 求头能统一处理便于接口的统一管理解决回调地狱配置…

rust api接口开发(以登陆和中间件鉴权为例)

rust rest api接口开发 所需依赖 axumtokioredis cargo add axum redis cargo add tokio --featuresfull路由服务创建和运行 //子路由 let v1router axum::Router::new(); //主路由,并将子路由绑定到主路由 let routeraxum::Router::new().nest("/v1",v1router)…

Zabbix6.4监控Windows上的GPU使用率

背景&#xff1a;一台Windows物理机上装了英伟达的GPU显卡&#xff0c;业务需要实时监控它的使用率。 1、确认nvidia-smi命令可用 2、命令查询相关使用情况 3、服务器上部署zabbix-agent 提前下载好包上传&#xff0c;路径自行修改 C:\Users\Administrator>C:\zabbix_age…

集团数字化转型方案(三)

集团数字化转型方案通过系统整合人工智能&#xff08;AI&#xff09;、大数据、云计算和物联网&#xff08;IoT&#xff09;技术&#xff0c;建立了一个全面智能化的业务管理平台&#xff0c;涵盖从业务流程自动化、数据驱动决策支持&#xff0c;到客户体验优化和供应链管理的各…

Redis基础到高级狂神笔记一篇总结完

学习视频&#xff1a;【狂神说Java】Redis最新超详细版教程通俗易懂_哔哩哔哩_bilibili 目录 1.为什么用NoSQL 1.1单机MySQL的美好年代 1.2 Memcached&#xff08;缓存&#xff09; MySQL 垂直拆分(读写分离) 1.3分表分库 水平拆分 Mysql 集群 1.4现今 1.5为什么用NoSQL&…

『深度长文』4种有效提高LLM输出质量的方法!

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,专注于分享AI全维度知识,包括但不限于AI科普,AI工具测评,AI效率提升,AI行业洞察。关注我,AI之路不迷路,2024我们一起变强。 LLM,全…