当前位置:

首页 > 编程开发 > Java十大排序算法怎么实现

Java十大排序算法怎么实现

排序算法的稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,如果排序以后,保证这些记录的相对次序保持不变,即在原序列中,a[i]=a[j],且a[i]在a[j]之前,排序后保证a[i]仍在a[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。一.选择排序每次从待排序的元素中选择最小的元素,依次和第1、2、3...位置的元素进行交换。这样在数组前面的部分形成有序区域。每进行一次交换,有序区域长度加一。publicstaticvoidselectionSort(int[]arr){//细节

本文目录

    Java十大排序算法怎么实现

    排序算法的稳定性:

            假定在待排序的记录序列中,存在多个具有相同的关键字的记录,如果排序以后,保证这些记录的相对次序保持不变,即在原序列中,a[i]=a[j],且 a[i] 在 a[j] 之前,排序后保证 a[i] 仍在 a[j] 之前,则称这种排序算法是稳定的;否则称为不稳定的。

    Java十大排序算法怎么实现

    一.选择排序

    每次从待排序的元素中选择最小的元素,依次和第1、2、3...位置的元素进行交换。这样在数组前面的部分形成有序区域。每进行一次交换,有序区域长度加一。

    Java十大排序算法怎么实现

    public static void selectionSort(int[] arr){
        //细节一:这里可以是arr.length也可以是arr.length-1
        for (int i = 0; i < arr.length-1 ; i++) {
            int mini = i;
            for (int j = i+1; j < arr.length; j++) {
                //切换条件,决定升序还是降序
                if(arr[mini]>arr[j]) mini =j;
            }
            swap(arr,mini,i);
        }
    }

    二.冒泡排序

            依次比较相邻的两个数,如果顺序错误就把他们交换过来,这样的话,每一轮比较下来都可以把最大的数放到它应该在的位置。(就像是把最大的气泡冒到最上层一样)

             这里解释一下顺序错误的含义。我们按照按升序排序,后面的值应该大于等于前面的值,如果不满足的话,就交换。

    Java十大排序算法怎么实现

    public static void bubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            //记录本次有没有进行交换的操作
            boolean flag = false;
            //保存在头就动头,保存在尾就动尾
            for(int j =0 ; j < arr.length-1-i ; j++){
                //升序降序选择地
                if(arr[j] > arr[j+1])
                {
                    swap(arr,j,j+1);
                    flag = true;
                }
            }
            //如果本次没有进行交换操作,表示数据已经有序
            if(!flag){break;} //程序结束
        }
    }

    三.插入排序

            插入排序其实可以理解为我们玩扑克时摸牌的过程,我们在摸牌的时候手里的牌总是有序的,每摸一张牌,就把这张牌插到它应该在的位置。等所有的牌都摸完了以后,全部的牌就都有序了。

    Java十大排序算法怎么实现

     思考:数组前面形成了有序区域,那我查找当前数字应该插入位置的时候,用二分进行,是不是就可以把插入排序的复杂度优化到O(nlogn)了呀?

            二分倒是可以log的复杂度找到位置。 关键是如果用数组存储的话,插入的时候数据后移还是O(n)的复杂度。如果用链表的话,找到位置插入是O(1)的了,但是链表也没办法二分呀。

    public static void insertSort(int[] arr){
            //从第二个数开始,把每个数依次插入到指定的位置
            for(int i = 1 ; i < arr.length ; i++)
            {
                int key = arr[i];
                int j = i-1;
                //大的后移操作
                while(j >= 0 && arr[j] > key)
                {
                    arr[j+1] = arr[j];
                    j--;
                }
                arr[j+1] = key;
            }
        }

    四.希尔排序

            希尔排序是Donald Shell于1959年提出的一种排序算法,是对直接插入排序的改进之后的高效版本。 希尔排序需要准备一组数据作为增量序列。

    这组数据需要满足以下三个条件:

    1. 数据递减排列

    2. 数据中的最大值小于待排序数组的长度

    3. 数据中的最小值是1。

            只要满足上述要求的数组都可以作为增量序列,但是不同的增量序列会影响到排序的效率。这里我们用{5,3,1}作为增量序列来进行讲解

    Java十大排序算法怎么实现

     实现优化的原因:减少数据量,使O(n)和O(n^2)的差距并不大

    public static void shellSort(int[] arr){
            //分块处理
            int gap = arr.length/2; //增量
            while(1<=gap)
            {
                //插入排序:只不过是与增量位交换
                for(int i = gap ; i < arr.length ; i++)
                {
                    int key = arr[i];
                    int j = i-gap;
                    while(j >= 0 && arr[j] > key)
                    {
                        arr[j+gap] = arr[j];
                        j-=gap;
                    }
                    arr[j+gap] = key;
                }
                gap = gap/2;
            }
        }

    五.堆排序

    是一棵完全二叉树,分为大根堆、小根堆两种

    可以O(1)取最大/小值,可以O(logn)删除最大/小值,可以O(logn)插入元素

    MIN-HEAPIFY(i)操作:

    我们假设完全二叉树中某节点 i 的左子树和右子树都满足小根堆的性质,假设 i 节点的左孩子是 left_i,i 节点的右孩子是 rigℎt_i。那如果 a[i] 大于 a[left_i] 或 a[rigℎt_i] 的话,那以 i 节点为根节点的整棵子树就不满足小根堆的性质了,我们现在要进行一个操作:把以 i 为根节点的这棵子树调整成小根堆。

    Java十大排序算法怎么实现

    //堆排序
        public static void heapSort(int[] arr){
            //开始调整的位置为最后一个叶子节点
            int start = (arr.length - 1)/2;
            //从最后一个叶子节点开始遍历,调整二叉树
            for (int i = start; i >= 0 ; i--){
                maxHeap(arr, arr.length, i);
            }
     
            for (int i = arr.length - 1; i > 0; i--){
                int temp = arr[0];
                arr[0] = arr[i];
                arr[i] = temp;
                maxHeap(arr, i, 0);
            }
        }
     
        //将二叉树调整为大顶堆
        public static void maxHeap(int[] arr, int size, int index){
            //建立左子节点
            int leftNode = 2 * index + 1;
            //建立右子节点
            int rightNode = 2 * index + 2;
     
            int maxNode = index;
            //左子节点的值大于根节点时调整
            if (leftNode < size && arr[leftNode] > arr[maxNode]){
                maxNode = leftNode;
            }
            //右子节点的值大于根节点时调整
            if (rightNode < size && arr[rightNode] > arr[maxNode]){
                maxNode = rightNode;
            }
            if (maxNode != index){
                int temp = arr[maxNode];
                arr[maxNode] = arr[index];
                arr[index] = temp;
                //交换之后可能会破坏原来的结构,需要再次调整
                //递归调用进行调整
                maxHeap(arr, size, maxNode);
            }
        }

    我使用的是大根堆,排序的过程归根下来就是:先左底根后右底根(看自己怎么写)->每个根向上在向下。(左右上下)

    六.归并排序

            归并排序是分治法的典型应用,先来介绍一下分治法,分治法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题规模很小可以直接求解,再将子问题的解进行合并来得到原问题的解。

    Java十大排序算法怎么实现

            归并排序分解子问题的过程就是每一次把数组分成2份,直到数组的长度为1(因为只有一个数字的数组是有序的)。然后再将相邻的有序数组合并成一个有序数组。直到全部合到一起,整个数组就排序完毕了。 现在要解决的问题就是如何把两个有序的数组合并成一个有序的数组。其实就是每次比较两个数组当前最小的两个元素,哪个小就选哪个

    数组a

    数组b

    说明

    答案数组

    2,5,7

    1,3,4

    1<2,取1,数组b的指针后移

    1

    2,5,7

    1,3,4

    2<3,取2,数组a的指针后移

    1,2

    2,5,7

    1,3,4

    3<5,取3,数组b的指针后移

    1,2,3

    2,5,7

    1,3,4

    4<5,取4,数组b的指针后移

    1,2,3,4

    2,5,7

    1,3,4

    数组b中没有元素了,取5

    1,2,3,4,5

    2,5,7

    1,3,4

    数组b中没有元素了,取7

    1,2,3,4,5,7

    public static void mergeSort(int[] arr, int low, int high){
            int middle = (high + low)/2;
            if (low < high){
                //递归排序左边
                mergeSort(arr, low, middle);
                //递归排序右边
                mergeSort(arr, middle +1, high);
                //将递归排序好的左右两边合并
                merge(arr, low, middle, high);
            }
     
        }
     
        public static void merge(int[] arr, int low, int middle, int high){
            //存储归并后的临时数组
            int[] temp = new int[high - low + 1];
            int i = low;
            int j = middle + 1;
            //记录临时数组中存放数字的下标
            int index = 0;
            while (i <= middle && j <= high){
                if (arr[i] < arr[j]){
                    temp[index] = arr[i];
                    i++;
                } else {
                    temp[index] = arr[j];
                    j++;
                }
                index++;
            }
            //处理剩下的数据
            while (j <= high){
                temp[index] = arr[j];
                j++;
                index++;
            }
            while (i <= middle){
                temp[index] = arr[i];
                i++;
                index++;
            }
            //将临时数组中的数据放回原来的数组
            for (int k = 0; k < temp.length; ++k){
                arr[k + low] = temp[k];
            }
        }

    七.快速排序

            快速排序的工作原理是:从待排序数组中随便挑选一个数字作为基准数,把所有比它小的数字放在它的左边,所有比它大的数字放在它的右边。然后再对它左边的数组和右边的数组递归进行这样的操作。

            全部操作完以后整个数组就是有序的了。 把所有比基准数小的数字放在它的左边,所有比基准数大的数字放在它的右边。这个操作,我们称为“划分”(Partition)。

    Java十大排序算法怎么实现

    	//快速排序
    	public static void QuickSort1(int[] arr, int start, int end){
    		int low = start, high = end;
    		int temp;
    		if(start < end){
    		    int guard = arr[start];
    			while(low != high){
    				while(high > low && arr[high] >= guard) high--;
    				while(low < high && arr[low] <= guard) low++;
    				if(low < high){
    					temp = arr[low];
    					arr[low] = arr[high];
    					arr[high] = temp;
    				}
    			}
    			arr[start] = arr[low];
    			arr[low] = guard;
    			QuickSort1(arr, start, low-1);
    			QuickSort1(arr, low+1, end);
    		}
    	}
    	
    	//快速排序改进版(填坑法)
    	public static void QuickSort2(int[] arr, int start, int end){
    		int low = start, high = end;
    		if(start < end){
    		while(low != high){
    	    	int guard = arr[start];//哨兵元素
    			while(high > low && arr[high] >= guard) high--;
    			arr[low] = arr[high];
    			while(low < high && arr[low] <= guard) low++;
    			arr[high] = arr[low];
    		}
    		arr[low] = guard;
    		QuickSort2(arr, start, low-1);
    		QuickSort2(arr, low+1, end);
    	}
    }

    八.鸽巢排序

            计算一下每一个数出现了多少次。举一个例子,比如待排序的数据中1出现了2次,2出现了0次,3出现了3次,4出现了1次,那么排好序的结果就是{1.1.3.3.3.4}。

    Java十大排序算法怎么实现

    //鸽巢排序
        public static void PigeonholeSort(int[] arr){
            //获取最大值
            int k = 0;
            for (int i = 0; i < arr.length; i++) {
                k = Math.max(k,arr[i]);
            }
            //创建计数数组并且初始化为0
            int[] cnt = new int[k+10];
            for(int i = 0 ; i <= k ; i++) { cnt[i]=0; }
            for(int i = 0 ; i < arr.length ;i++) { cnt[arr[i]]++; }
            int j = 0;
            for(int i = 0 ; i <=k ; i++)
            {
                while(cnt[i]!=0)
                {
                    arr[j]=i;
                    j++;
                    cnt[i]--;
                }
            }
        }

            鸽巢排序其实算不上是真正意义上的排序算法,它的局限性很大。只能对纯整数数组进行排序,举个例子,如果我们需要按学生的成绩进行排序。是一个学生+分数的结构那就不能排序了。

    九.计数排序

            先考虑这样一个事情:如果对于待排序数据中的任意一个元素 a[i],我们知道有 m 个元素比它小,那么我们是不是就可以知道排好序以后这个元素应该在哪个位置了呢?(这里先假设数据中没有相等的元素)。计数排序主要就是依赖这个原理来实现的。

    比如待排序数据是{2,4,0,2,4} 先和鸽巢一样做一个cnt数组{1,0,2,0,2}                                                                                                                                    0,1,2,3,4

    此时cnt[i]表示数据i出现了多少次,

    然后对cnt数组做一个前缀和{1,1,3,3,5}    :0,1,2,3,4

    此时cnt[i]表示数据中小于等于i的数字有多少个

    待排序数组

    计数数组

    说明

    答案数组ans

    2,4,0,2,4

    1,1,3,3,5

    初始状态

    null,null,null,null,null,

    2,4,0,2,4

    1,1,3,3,5

    cnt[4]=5,ans第5位赋值,cnt[4]-=1

    null,null,null,null,4

    2,4,0,2,4

    1,1,3,3,4

    cnt[2]=3,ans第3位赋值,cnt[2]-=1

    null,null,2 null,4

    2,4,0,2,4

    1,1,2,3,4

    cnt[0]=1,ans第1位赋值,cnt[0]-=1

    0,null,2,null,4

    2,4,0,2,4

    0,1,2,3,4

    cnt[4]=4,ans第4位赋值,cnt[4]-=1

    0,null,2,4,4

    2,4,0,2,4

    0,1,2,3,3

    cnt[2]=2,ans第2位赋值,cnt[2]-=1

    0,2,2,4,4

    十.基数排序

    基数排序是通过不停的收集和分配来对数据进行排序的。

    Java十大排序算法怎么实现

    • 因为是10进制数,所以我们准备十个桶来存分配的数。

    • 最大的数据是3位数,所以我们只需要进行3次收集和分配。

    • 需要先从低位开始收集和分配(不可从高位开始排,如果从高位开始排的话,高位排好的顺序会在排低位的时候被打乱,有兴趣的话自己手写模拟一下试试就可以了)

    • 在收集和分配的过程中,不要打乱已经排好的相对位置

            比如按十位分配的时候,152和155这两个数的10位都是5,并且分配之前152在155的前面,那么收集的时候152还是要放在155之前的。

    //基数排序
        public static void radixSort(int[] array) {
            //基数排序
            //首先确定排序的趟数;
            int max = array[0];
            for (int i = 1; i < array.length; i++) {
                if (array[i] > max) {
                    max = array[i];
                }
            }
            int time = 0;
            //判断位数;
            while (max > 0) {
                max /= 10;
                time++;
            }
            //建立10个队列;
            List queue = new ArrayList();
            for (int i = 0; i < 10; i++) {
                ArrayList queue1 = new ArrayList();
                queue.add(queue1);
            }
            //进行time次分配和收集;
            for (int i = 0; i < time; i++) {
                //分配数组元素;
                for (int j = 0; j < array.length; j++) {
                    //得到数字的第time+1位数;
                    int x = array[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
                    ArrayList queue2 = queue.get(x);
                    queue2.add(array[j]);
                    queue.set(x, queue2);
                }
                int count = 0;//元素计数器;
                //收集队列元素;
                for (int k = 0; k < 10; k++) {
                    while (queue.get(k).size() > 0) {
                        ArrayList queue3 = queue.get(k);
                        array[count] = queue3.get(0);
                        queue3.remove(0);
                        count++;
                    }
                }
     
            }
     
     
        }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。