排序算法及java实现

news2025/7/14 19:42:10

简介

排序算是非常基础的算法,为什么我们需要排序算法呢?假设我们只有10个数,或者100个数,其实根本不需要研究这么多的排序算法,正常我们会使用的插入排序或者选择排序足够了,没必要发明快排,基数排序这些。
只有将需要排序的量非常大,我们才开始需要一些效率更高,更合适的排序算法。看一下常见的几种排序算法的效率:
在这里插入图片描述
来解释一下稳定性的意思,稳定性的意思是说,相等的数在排序后仍然保持排序前的相对顺序。

贴一个百科的解释:
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
然后我们来看具体的算法

注意:排序算法的速度是有极限的,基于比较的排序算法的最优下界是 O ( n l o g n ) % O(nlogn) O(nlogn),至于为什么,我还没搞明白,可以看看这个:CBA理论, 为什么基于比较的排序方法的性能极限是O(nlogn)

冒泡排序

一般我们提起冒泡排序,都说它是最简单的排序,但是对我来说,实际生活中,我感觉使用插入排序或者选择排序其实更多,很少会直接想到冒泡排序,冒泡排序的操作过程就是,从第一个起,和后面的两两对比,然后如果后面的小于前面的,就进行交换,如此这般,循环直到所有数字顺序都正确。

/**
 * 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
 * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
 * 针对所有的元素重复以上的步骤,除了最后一个。
 * 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
 */
public class BubbleSort {

    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        bubbleSort(list,count);
        System.out.println("排序后: "+ Arrays.toString(list));
    }

    private static void bubbleSort(int[] list, int count) {
        for (int i = list.length-1; i >0 ; i--) {
            boolean flag=true;

            for (int j = 0; j < i; j++) {
                if (list[j]>list[j+1]){
                    flag=false;
                    int temp=list[j];
                    list[j]=list[j+1];
                    list[j+1]=temp;
                }
            }

            if (flag){
                return;
            }
        }

    }
}

插入排序

插入排序就是,从第一个开始就当它有序,开始和后面的进行对比,当发现大小小于前面的时候,就一直找到对的位置放下这个数字。

/**
 *插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
 *插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。
 */
public class InsertionSort {

    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
//        int[] result=insertionSort(list,count);
        insertionSort(list);
//        System.out.println("排序后: "+ Arrays.toString(result));
        System.out.println("排序后: "+ Arrays.toString(list));
    }

    private static int[] insertionSort(int[] list, int count) {
        int[] result= Arrays.copyOf(list, list.length);

        for (int i = 1; i < list.length; i++) {

            int j=i;
            while (j > 0 && list[i]<result[j-1]) {
                result[j]=result[j-1];
                j--;
            }
            result[j]=list[i];
        }

        return  result;
    }


    public static void insertionSort(int[] arr){
        for(int i=1;i<arr.length;i++){
            int j=i;
            while(j>0 && arr[j] < arr[j - 1]){
                arr[j] = arr[j]+arr[j-1];
                arr[j-1] = arr[j]-arr[j-1];
                arr[j] = arr[j]-arr[j-1];
                j--;
            }
        }
    }

}

选择排序

我觉得选择排序最符合人的排序习惯,就是一轮一轮的找最小的,拿出来排队。


/**
 * 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
 */
public class SelectionSort {

    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        selectSort(list);
        System.out.println("排序后: "+ Arrays.toString(list));
    }

    private static void selectioonSort(int[] list, int count) {
        for (int i = 0; i < list.length-1; i++) {
            int min=i;
            for (int j = i + 1; j < list.length; j++) {
                if(list[min]>list[j]){
                    min=j;
                }
            }

            if (min!=i){
                int temp=list[i];
                list[i]=list[min];
                list[min]=temp;
            }

        }
    }

    public static void selectSort(int[] arr) {
        for (int i = 0; i < arr.length-1; i++) {
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[min]) {
                    min = j;
                }
            }

            if (min != i) {
                arr[min]=arr[min]+arr[i];
                arr[i]=arr[min]-arr[i];
                arr[min]=arr[min]-arr[i];
            }
        }
    }


}

希尔排序

希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。一些老版本教科书和参考手册把该算法命名为Shell-Metzner,即包含Marlene Metzner Norton的名字,但是根据Metzner本人的说法,“我没有为这种算法做任何事,我的名字不应该出现在算法的名字中。

希尔排序可以理解为在插入排序外面套了一层,每次不是相近的数字在比,而是间隔着比,主要是为了提高消灭逆序对的效率

/**
 * 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
 * 希尔排序是基于插入排序的以下两点性质而提出改进方法的:
 * 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
 * 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
 * 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
 */
public class ShellSort {

    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        shellSort2(list,count);
        System.out.println("排序后: "+ Arrays.toString(list));
    }


    private static void shellSort(int[] list, int count) {
        for (int D = count/2; D >0 ; D/=2) {
            for (int P = D; P < count; P++) {
                int temp=list[P];
                int i;
                for (i = P; i >= D && list[i-D] > temp; i-=D) {
                    list[i]=list[i-D];
                }
                list[i]=temp;

            }
        }
    }

    private static void shellSort2(int[] arr, int count) {
        for (int D = count/2; D >0 ; D/=2) {
            for(int i=D;i<arr.length;i++){
                int j=i;
                while(j>=D && arr[j] < arr[j - D]){
                    arr[j] = arr[j]+arr[j-D];
                    arr[j-D] = arr[j]-arr[j-D];
                    arr[j] = arr[j]-arr[j-D];
                    j-=D;
                }
            }
        }
    }

归并排序

归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为
O ( n l o g n ) % O(nlogn) O(nlogn)(大O符号)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

我觉得靠我的脑子想不出来归并排序这种东西,就是拆分到最小单位,1个或者两个,然后排好序返回来,有序的列表继续参与合并排序。

/**
 * 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
 * 作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
 * 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
 * 自下而上的迭代;
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        int[] result=sort(list);
        System.out.println("排序后: "+ Arrays.toString(result));
    }


    private static int[] sort(int[] list){
        int middle = (int) Math.floor(list.length / 2);

        if(list.length<2){
            return list;
        }
        int[] left=Arrays.copyOfRange(list,0,middle);
        int[] right=Arrays.copyOfRange(list,middle,list.length);

        return merge(sort(left),sort(right));
    }

    private static int[] merge(int[] left, int[] right) {
        int[] result=new int[left.length+right.length];
        int i=0;
        while (left.length>0 && right.length>0){
            if (left[0]> right[0]){
                result[i]=right[0];
                right=Arrays.copyOfRange(right,1,right.length);
            }else {
                result[i]=left[0];
                left=Arrays.copyOfRange(left,1,left.length);
            }
            i++;
        }

        while (left.length>0){
            result[i++]=left[0];
            left=Arrays.copyOfRange(left,1,left.length);
        }

        while (right.length>0){
            result[i++]=right[0];
            right=Arrays.copyOfRange(right,1,right.length);
        }
        return result;
    }

快速排序

由英国计算机科学家托尼·霍尔(Tony Hoare)于1959年想到的,1961年发表的,这个算法也成了今天世界计算机产业中使用最多的排序算法,霍尔因此获得了爵士头衔,也成为第一个获得这种头衔的科学家。


/**
 * 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用
 * 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
 * 该方法的基本思想是:
 * 1.先从数列中取出一个数作为基准数。
 * 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
 * 3.再对左右区间重复第二步,直到各区间只有一个数。
 */
public class QuickSort {

    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        quickSort(list,0,count-1);
        System.out.println("排序后: "+ Arrays.toString(list));
    }

    private static void quickSort(int[] list, int low,int high) {

        if(low>=high){
            return;
        }
        int piovt=list[low];

        int left=low;
        int right=high;
        while (left<right){
            while (left<right&&list[right]>=piovt){
                right--;
            }
            if (left<right){
                list[left]=list[right];
            }
            while (left<right&&list[left]<piovt){
                left++;
            }
            if (left<right){
                list[right]=list[left];
            }
            if (left>=right){
                list[left]=piovt;
            }
        }

        quickSort(list,low,right-1);
        quickSort(list,right+1,high);
    }

堆排序

计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同发明了堆排序算法。

堆排序Heapsort 是J. W. J. Williams在1964年发明的。这也是堆诞生的时候,Williams 将其本身作为一个有用的数据结构提出。同年,R. W. Floyd发表了一个改进的版本,可以对数组进行就地排序,继续他早期对treesort 算法的研究。

/**
 * 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
 * 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
 * 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
 * 堆排序的平均时间复杂度为 Ο(nlogn)。
 */
public class Heapsort {

    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        heapSort(list,count);
        System.out.println("排序后: "+ Arrays.toString(list));
    }

    private static void heapSort(int[] list, int count) {

        for (int k = count-1; k > 1; k--) {
            for (int i = 0; i <=k; i++) {
                int left=2*i+1;
                int right=2*i+2;
                if(left<k && list[left]<list[i]){
                    int temp=list[i];
                    list[i]=list[left];
                    list[left]=temp;
                }
                if(right<k && list[right]<list[i]){
                    int temp=list[i];
                    list[i]=list[right];
                    list[right]=temp;
                }

                if (right<k && list[right]<list[left]){
                    int temp=list[left];
                    list[left]=list[right];
                    list[right]=temp;
                }

            }
            int min=list[0];
            list[0]=list[k];
            list[k]=min;
        }

    }

基数排序

基数排序(英语:Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序的发明可以追溯到1887年赫尔曼·何乐礼在列表机(Tabulation Machine)上的贡献。

这个真的写起来好麻烦,照着菜鸟教程写的,改了六七遍才跑通。


/**
 * 基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
 */
public class RadixSort {
    public static void main(String[] args) {
        int[] list= {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        radixSort(list,count);
        System.out.println("排序后: "+ Arrays.toString(list));
    }

    private static void radixSort(int[] list, int count) {
//        int[] result=Arrays.copyOf(list,list.length);

        LinkedList<Integer>[] linkedLists = new LinkedList[10];
        for (int i = 0; i < linkedLists.length; i++) {
            linkedLists[i] = new LinkedList<>();
        }
        int max=getMax(list);
        for (int i = 1; i <=max; i++) {
            for (int j = 0; j < list.length; j++) {
                linkedLists[getIndex(list[j],i)].offer(list[j]);
            }

            int index=0;

            for (int j = 0; j < linkedLists.length; j++) {
                while (!linkedLists[j].isEmpty()){
                    list[index++]=linkedLists[j].poll();

                }
            }
        }

//        return result;
    }

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

        }
        return (max + "").length();
    }


    private static int getIndex(int num, int r) {
        int ret = 0;
        for (int i = 1; i <= r; i++) {
            ret = num % 10;
            num /= 10;
        }
        return ret;
    }

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

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

相关文章

第九章 哈希表 AcWing 2 1549. 集合相似度

第九章 哈希表 AcWing 2 1549. 集合相似度 原题链接 AcWing 1549. 集合相似度 算法标签 哈希表 位运算 思路 使用unordered_set数据结构将数据插入指定集合 如何计算Nc&#xff08;两集合交集&#xff09; 如何计算Nt&#xff08;两集合并集&#xff09; 输出问题 WA 精…

干掉 “重复代码”,这三种方式绝了!

软件工程师和码农最大的区别就是平时写代码时习惯问题&#xff0c;码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。 业务同学抱怨业务开发没有技术含量&#xff0c;用不到设计模式、Java 高级特性、OOP&#xff0c;平时写代码都在堆 CRUD&#xff0c;个…

BCD编码和ASCII码

计算机里&#xff0c;字母&#xff0c;各种字符以及指挥计算机执行操作的指令&#xff0c;均用二进制数的组合表示&#xff0c;称为二进制编码 目录 ASCII码&#xff08;汇编语言程序设计的时候会常用&#xff09; BCD码&#xff08;了解&#xff09; ASCII码&#xff08;汇…

等数值计算方法学习笔记第4章第三部分【数值积分(数值微分)】

高等数值计算方法学习笔记第4章第三部分【数值积分&#xff08;数值微分&#xff09;】六、数值微分&#xff08;第四次课&#xff09;1、中点方法与误差分析2、插值型的求导公式3、习题和表格4、知识结构图六、数值微分&#xff08;第四次课&#xff09; 1、中点方法与误差分析…

【图像处理】小波编码图像中伪影和纹理的检测(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

一年一度的科技狂欢盛会——2022亚马逊云科技re:Invent全球大会

一年一度的科技狂欢盛会&#xff0c;2022年亚马逊云科技re:Invent全球大会即将于北京时间2022年11月29日盛大开启&#xff01;届时全球各领域关注“云计算圈”发展的人都将齐聚一堂&#xff0c;共同聆听5大重磅嘉宾的主题演讲&#xff0c;700前沿技术话题…… 携全球合作伙伴&…

《计算机工程》投稿经验分享

历经两个月终于录用了 投稿过程真的太心酸了 第一次投计算机工程与应用&#xff1a;历时两周&#xff0c;拒稿 第二次投计算机科学&#xff1a;加急15天&#xff0c;增刊录用&#xff0c;撤稿 第三次投计算机应用与软件&#xff1a;说文件太大&#xff0c;修改文件大小重投&…

选择合作伙伴是最大关键:网宿科技的云业务拓展之路

关注IT圈子的小伙伴们&#xff0c;对网宿科技这个名字想必都是耳熟能详。在众多发力云计算业务的科技企业当中&#xff0c;近年来业绩表现出众的网宿科技&#xff0c;无疑是相当引人瞩目的一家。那么问题就来了&#xff1a;网宿科技当初是怎样走上了这条云业务拓展之路&#xf…

【知识网络分析】二模网络(two node)、多模网络(multi node)与多级别网络(multi level)

二模网络(two node)、多模网络(multi node)与多级别网络(multi level) 1 二模网络(two node)1.1 读取本地文献并构建二模网络数据集1.2 网络数据集精简1.3 网络图绘制及美化2 多模网络(multi node)3 多级别网络(multi level)1 二模网络(two node) 1.1 读取本地文…

web期末网站设计大作业 奶茶店网站美食餐饮网站设计与实现(HTML+CSS+JavaScript)

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

【网页设计】HTML做一个属于我的音乐页面(纯html代码)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

JAVA学习笔记- - - day 2

&#x1f495;前言&#xff1a;作者是一名正在学习JAVA的初学者&#xff0c;每天分享自己的学习笔记&#xff0c;希望能和大家一起进步成长&#x1f495; 目录 &#x1f495;前言&#xff1a;作者是一名正在学习JAVA的初学者&#xff0c;每天分享自己的学习笔记&#xff0c;希望…

15.变量的存储类别

变量的存储类别 内存的分区 1.内存&#xff1a;物理内存&#xff0c;虚拟内存。 虚拟内存&#xff1a;操作系统虚拟出来的的内存。 操作系统会再物理内存和虚拟内存之间做映射。 在32位系统下&#xff0c;每个进程的寻址范围是4G&#xff1a;0x00 00 00 00 ~ 0xff ff ff ff …

XSStrike工具使用说明

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是XSStrike工具使用说明。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权…

详解设计模式:工厂方法模式

工厂方法模式&#xff0c;又称工厂模式、多态工厂模式和虚拟构造器模式&#xff0c;通过工厂父类定义负责创建产品的公共接口&#xff0c;子类负责生产具体对象。可以理解为简单工程模式的升级&#xff0c;解决简单工厂模式的弊端。 &#xff5e; 本篇内容包括&#xff1a;关于…

CANdelaStudio-从入门到深入到实践目录

前文介绍诊断协议那些事儿专栏&#xff0c;为大家深入介绍了ISO 14229各个服务的基础知识、请求与响应的报文格式&#xff0c;详情可查看&#xff1a;诊断协议那些事儿&#xff0c;从本专题开始&#xff0c;将由浅入深的展开诊断实际开发与测试的数据库编辑&#xff0c;包含大量…

强化学习调度环境:析取图和离散事件仿真

获取更多资讯&#xff0c;赶快关注上面的公众号吧&#xff01; 文章目录何为析取图和离散事件仿真模型析取图模型离散事件仿真模型强化学习环境调度环境基于析取图的调度环境基于离散事件仿真的调度环境总结近日有小伙伴在复现强化学习求解作业车间调度的文章代码问题时遇到一些…

Python01(安装环境以及开发工具PyCharm)

目录 一、环境下载&安装 二、开发工具下载&安装 一、环境下载&安装 1、Python环境安装包下载 官方网址&#xff1a;https://www.python.org/downloads/windows/ 选择一个安装包进行下载&#xff0c;建议不要下载最新的。 2、环境安装 双击下载好的环境安装包进…

Rational rose 2007 下载和安装教程

文章目录Rational rose 简介一&#xff0c;下载Rational rose 2007二&#xff0c;安装Rational rose 2007三&#xff0c;激活Rational Rose 2007四&#xff0c;启动Rational Rose 2007Rational rose 简介 Rational Rose是Rational公司出品的一种面向对象的统一建模语言的可视化…

云原生系列 【基于CCE Kubernetes编排实战】

✅作者简介&#xff1a; CSDN内容合伙人&#xff0c;全栈领域新星创作者&#xff0c;阿里云专家博主&#xff0c;华为云享专家博主&#xff0c;掘金后端评审团成员 &#x1f495;前言&#xff1a; 最近云原生领域热火朝天&#xff0c;那么云原生是什么&#xff1f;何为云原生&a…