Java八大常用排序算法

1冒泡排序

对于冒泡排序相信我们都比较熟悉了,其核心思想就是相邻元素两两比较,把较大的元素放到后面,在一轮比较完成之后,最大的元素就位于最后一个位置了,就好像是气泡,慢慢的浮出了水面一样

图片

Jave 实现

public class BubbleSort1 {
    public static void BubbleSort(int[] arr) {
        for(int i=0;i<arr.length-1;i++){//冒泡趟数,n-1趟
                for(int j=0;j<arr.length-i-1;j++){
                    int temp;//定义一个临时变量
                    if(arr[j+1]<arr[j]){
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
    }
    public static void main(String[] args) {
        int arr[] = new int[]{1,6,2,2,5};
        BubbleSort.BubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

冒泡排序算法还是比较好理解的,只需要进行两次循环,最外层的循环代表排序元素的个数,内部循环则进行两两比较,时间复杂度为 O(n^2) 

2快速排序

快排的思想为首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序,之后再递归排序两边的数据

图片

Jave 实现

public class QuickSort {
    public static void quickSort(int[] arr,int low,int high){
        int i,j,temp,t;
        if(low>high){
            return;
        }
        i=low;
        j=high;
        //temp就是基准位
        temp = arr[low];
 
        while (i<j) {
            //先看右边,依次往左递减
            while (temp<=arr[j]&&i<j) {
                j--;
            }
            //再看左边,依次往右递增
            while (temp>=arr[i]&&i<j) {
                i++;
            }
            //如果满足条件则交换
            if (i<j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }
 
        }
        //最后将基准为与i和j相等位置的数字交换
         arr[low] = arr[i];
         arr[i] = temp;
        //递归调用左半数组
        quickSort(arr, low, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, high);
    }
 
 
    public static void main(String[] args){
        int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
        quickSort(arr, 0, arr.length-1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

相比冒泡排序,快速排序每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了,时间复杂度为 O(N*logN) 

3直接插入排序

插入排序的思想是把一个数据插入到一个有序序列中,从而得到一个新的序列加一的有序序列,可以通过下图来进一步加深理解

图片

Java 实现

public static void InsertSort(int[] arr)
{
    int i, j;
    int n = arr.Length;
    int target;
 
    //假定第一个元素被放到了正确的位置上
    //这样,仅需遍历1 - n-1
    for (i = 1; i < n; i++)
    {
        j = i;
        target = arr[i];
 
        while (j > 0 && target < arr[j - 1])
        {
            arr[j] = arr[j - 1];
            j--;
        }
 
        arr[j] = target;
    }
}

由于每次遍历有序序列时,都会有序列中所有的数据做对比,故而时间复杂度为O(n^2) 

4选择排序

选择排序,是逐个确定元素位置的思想。同样是 n 遍循环,第一轮时,每一个元素都与第一个元素比较,如果比第一个元素大,则与之交换,这样一轮过后,第一个元素就是最小的了,第二轮开始每个元素与第二个位置的元素比较,如果大,则与第二位置的元素交换,以此类推,达到排序的目的

图片

Java 实现

public static int[] selectionSort(int[] array) {
    int len = array.length;
    // 如果数组长度为0或者1,都是不用排序直接返回
    if(len == 0 || len == 1) {
        return array;
    }
    for(int i = 0; i < len - 1; i++) {
        int minIdx = i;
        for(int j = i + 1; j < len; j++) {
            // 找到最小的数
            if(array[minIdx] > array[j]) {
                // 保存最小数的索引
                minIdx = j;
            }
        }
        // 如果一轮比较下来都没有变更最小值的索引则无需调换顺序
        if(minIdx != i) {
            int tmp = array[i];
            array[i] = array[minIdx];
            array[minIdx] = tmp;
        }
    }
    return array;
}

选择排序和冒泡排序还是很相似的,但是选择排序会比冒泡排序少一次交换的过程,但是同样是两层循环,所有时间复杂度也是 O(n^2) 

5并归排序

可以把一个数组分成两半,对于每一个数组当他们是有序的就可以进行一次合并操作。对于他们的两个区间进行递归,一直递归下去划分区间,当区间只有一个值的时候我们就可以进行合并返回上一层,让上一层合并再返回

图片

Java 实现

public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if(low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            //左右归并
            merge(a,low,mid,high);
        }
        return a;
    }
     
    public static void merge(int[] a, int low, int mid, int high) {
        int[] temp = new int[high-low+1];
        int i= low;
        int j = mid+1;
        int k=0;
        // 把较小的数先移到新数组中
        while(i<=mid && j<=high){
            if(a[i]<a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组 
        while(i<=mid){
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while(j<=high){
            temp[k++] = a[j++];
        }
        // 把新数组中的数覆盖nums数组
        for(int x=0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }

 归并排序采用分而治之的原理:首先将一个序列从中间位置分成两个序列,然后再将这两个子序列按照第一步继续二分下去,最后直到所有子序列的长度都为1,也就是不可以再二分截止。这时候再两两合并成一个有序序列即可。时间复杂度 O(NlogN)

6随机快速排序

随机快速排序与快速排序的思路一样,差异就是取主元之前,随机快速排序多了一个步骤:随机快速排序是随机取得一个元素,并且会与最后一个元素交换位置。取得主元的下标位置实际上还是最后一个下标,快速排序是习惯取得最后一个元素作为主元

图片

Java 实现

package quicksort;

import java.util.Random;

public class RandomQuickSort {

    public void Sort(int[] a, int p, int r) {
        if (p < r) {
            int q = Partition(a, p, r);
            Sort(a, p, q-1);
            Sort(a,q+1, r);
        }
    }

    private int Partition(int[] A, int p, int r) {
        /*随机选取主元元素*/
        Random random = new Random();
        int random_index = random.nextInt(r-p+1)+p;
        System.out.println("random_index="+random_index);
        int temp = A[random_index];
        A[random_index] = A[r];
        A[r] = temp;

        int x = A[r];  //pivot = A[p]
        int i = p-1;
        for (int j = p; j < r; j++) {
            if (A[j] <= x) {  //与pivot作比较
                i++;
                int tmp = A[j];
                A[j] = A[i];
                A[i] = tmp;
            }
        }

        int tmp = A[r];
        A[r] = A[i+1];
        A[i+1] = tmp;

        return i+1;

    }

}

7计数排序

首先统计原数组中每个值出现的次数

然后进行排序:遍历Count数组,对应位置的值出现多少次就往原数组写几个这个值

当然,在对于数据比较大的时候我们可以通过相对映射,让(该值-min)后的数组加一,最后还原回去即可

图片

Java 实现

public static int[] CountingSort(int[] a) {
    int b[] = new int[a.length];
    int max = a[0], min = a[0];
    for (int i=1;i<a.length;i++) {
        if (a[i] > max) {
            max = a[i];
        }
        if (a[i] < min) {
        min = a[i];
        }
    } 
    // k的大小是要排序的数组中,元素大小的极值差+1
    int k = max - min + 1;
    int c[] = new int[k];
    //统计A数组元素出现次数
    for (int i = 0; i < a.length; ++i) {
        c[a[i] - min] += 1;
    }
    //更新计算C数组
    for (int i = 1; i < c.length; ++i) {
        c[i] = c[i] + c[i - 1];
    }
    //填充B数组
    for (int i = a.length - 1; i >= 0; --i) {
        b[--c[a[i] - min]] = a[i];
    }
    return b;
}

8基数排序

基数排序核心思想是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前

图片

Java 版实现

public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {63, 157, 189, 51, 101, 47, 141, 121, 157, 156,
                194, 117, 98, 139, 67, 133, 181, 12, 28, 0, 109};

        radixSort(arr);

        System.out.println(Arrays.toString(arr));
    }

    /**
     * 高位优先法
     *
     * @param arr 待排序列,必须为自然数
     */
    private static void radixSort(int[] arr) {
        //待排序列最大值
        int max = arr[0];
        int exp;//指数

        //计算最大值
        for (int anArr : arr) {
            if (anArr > max) {
                max = anArr;
            }
        }

        //从个位开始,对数组进行排序
        for (exp = 1; max / exp > 0; exp *= 10) {
            //存储待排元素的临时数组
            int[] temp = new int[arr.length];
            //分桶个数
            int[] buckets = new int[10];

            //将数据出现的次数存储在buckets中
            for (int value : arr) {
                //(value / exp) % 10 :value的最底位(个位)
                buckets[(value / exp) % 10]++;
            }

            //更改buckets[i],
            for (int i = 1; i < 10; i++) {
                buckets[i] += buckets[i - 1];
            }

            //将数据存储到临时数组temp中
            for (int i = arr.length - 1; i >= 0; i--) {
                temp[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
                buckets[(arr[i] / exp) % 10]--;
            }

            //将有序元素temp赋给arr
            System.arraycopy(temp, 0, arr, 0, arr.length);
        }

    }
}

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

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

相关文章

RabbitMQ_00000

MQ的相关概念 RabbitMQ官网地址&#xff1a;https://www.rabbitmq.com RabbitMQ API地址&#xff1a;https://rabbitmq.github.io/rabbitmq-java-client/api/current/ 什么是MQ&#xff1f; MQ(message queue)本质是个队列&#xff0c;FIFO先入先出&#xff0c;只不过队列中…

Jmeter 基于Docker 实现分布式测试

基于Docker 实现分布式测试 制作Jmeter基础镜像制作工作节点镜像启动工作节点启动控制节点遇到的问题 使用Docker 部署Jmeter非常方便&#xff0c;可以省略软件的安装以及配置&#xff0c;比如jdk、jmeter。需要部署多个工作节点可以节省时间。 制作Jmeter基础镜像 下载jmeter…

Kubernetes集群搭建

一、概述 Kubernetes是一个Google开源的全新的分布式容器集群管理系统&#xff0c;由于从第一个字母到字母s中间有8个字母&#xff0c;所以简称K8s。 二、准备 ip角色内存192.168.187.130master4G192.168.187.131node2G192.168.187.132node2G 小提示&#xff1a; 设置静态i…

【课程作业_01】国科大2023模式识别与机器学习实践作业

国科大2023模式识别与机器学习实践作业 作业内容 从四类方法中选三类方法&#xff0c;从选定的每类方法中 &#xff0c;各选一种具体的方法&#xff0c;从给定的数据集中选一 个数据集&#xff08;MNIST&#xff0c;CIFAR-10&#xff0c;电信用户流失数据集 &#xff09;对这…

TCP TIME_WAIT 过多怎么处理

文章目录 1.什么是 TCP TIME_WAIT&#xff1f;2.为什么要 TIME_WAIT?3.TIME_WAIT 过多的影响4.解决办法4.1 调整短连接为长连接4.2 调整系统内核参数 5.小结参考文献 1.什么是 TCP TIME_WAIT&#xff1f; TCP 断开连接四次挥手过程中&#xff0c;主动断开连接的一方&#xff…

ctfshow——文件包含

文章目录 web 78——php伪协议第一种方法——php://input第二种方法——data://text/plain第三种方法——远程包含&#xff08;http://协议&#xff09; web 78——str_replace过滤字符php第一种方法——远程包含&#xff08;http://协议&#xff09;第二种方法——data://&…

游戏被DDOS攻击无法访问时该如何处理

游戏行业随着时代的发展有着突飞猛进的变化&#xff0c;尤其是互联网时代智能手机的普及&#xff0c;让游戏行业发展上了一个新的台阶。因为游戏带来的巨大利润&#xff0c;游戏行业一直是DDoS攻击的首选目标。 DDoS是Distributed Denial of Service的缩写&#xff0c;即分布式…

学习Android的第二天

目录 Android User Interface 用户界面 UI Android View与ViewGroup的概念 Android View android.view.View android.view.View XML 属性 android:id 属性 Android ViewGroup android.view.ViewGroup ViewGroup.LayoutParams ViewGroup.MarginLayoutParams ViewGr…

Redis核心技术与实战【学习笔记】 - 19.Pika:基于SSD实现大容量“Redis”

前言 随着业务数据的增加&#xff08;比如电商业务中&#xff0c;随着用户规模和商品数量的增加&#xff09;&#xff0c;就需要 Redis 能保存更多的数据。你可能会想到使用 Redis 切片集群&#xff0c;把数据分散保存到不同的实例上。但是这样做的话&#xff0c;如果要保存的…

java社区养老年人服务系统springboot+vue

为了帮助用户更好的了解和理解程序的开发流程与相关内容&#xff0c;本文将通过六个章节进行内容阐述。 第一章&#xff1a;描述了程序的开发背景&#xff0c;程序运用于现实生活的目的与意义&#xff0c;以及程序文档的结构安排信息&#xff1b; 第二章&#xff1a;描述了程序…

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key   登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…

Leetcode 85. 最大矩形

题目信息 LeetoCode地址: 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目理解 该题是84题的升级版。84题给出了一个一维数组&#xff0c;即一行数据&#xff0c;每个元素是高度。而该题则是给出了二维数组&#xff0c;只需我们将每一行的高度…

太强了,AI数字人从制作到变现一次搞定

AI数字人从制作到变现 如果说GPT类大模型是我们人类的第二大脑&#xff0c;数字人就是我们人类在互联网上的第二个身体。随着 AI 的迅速发展&#xff0c;2024 年 AI 模型开始从大型语言模型向大型视觉模型转变。数字人技术作为其分支之一&#xff0c;正日益成为科技、娱乐、教…

【GAMES101】Lecture 14 15 辐射度量学

目录 辐射度量学 Radiant flux&#xff08;光通量&#xff09; intensity&#xff08;发光强度&#xff09; irradiance radiance 辐射度量学 主要讲述了物理学中的Basic radiometry (辐射度量学)&#xff0c;就是我们在之前的计算光照中没有用具体的物理单位去衡量和描述…

C++新特性 协程

本篇文章我们来讲述一下C协程 协程&#xff08;Coroutine&#xff09;是一种能够挂起个恢复的函数过程 是一种轻量级的并发编程方式&#xff0c;也称为用户级线程。它与传统的线程&#xff08;Thread&#xff09;相比&#xff0c;具有更低的开销和更高的执行效率。 协程通常运…

爬虫学习笔记-scrapy爬取汽车之家

1.终端运行scrapy startproject scrapy_carhome,创建项目 2.接口查找 3.终端cd到spiders,cd scrapy_carhome/scrapy_carhome/spiders,运行 scrapy genspider audi https://car.autohome.com.cn/price/brand-33.html 4.打开audi,编写代码,xpath获取页面车型价格列表 5.运行项目…

深度学习技巧应用35-L1正则化和L2正则在神经网络模型训练中的应用

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用35-L1 正则化和L2正则在神经网络模型训练中的应用。L1正则化和L2正则化是机器学习中常用的两种正则化方法,用于防止模型过拟合并提高模型的泛化能力。这两种正则化方法通过在损失函数中添加惩罚项来控制模型的复杂性。…

面试八股文(4)

文章目录 1.sleep和wait区别2.为什么调用start()方法会执行run()方法&#xff0c;为什么不能直接调用run()方法3.synchronized关键字4.并发编程的三个重要特性5.synchronized和volatile关键字区别6.ThreadLocal7.为什么要用线程池&#xff1f;8.实现Runnable接口和Callable接口…

课时13:变量基础_变量场景

2.1.1 变量场景 学习目标 这一节&#xff0c; 我们从 数据存储、变量场景、小结 三个方面来学习。 数据存储 数据存储 所谓的数据存储&#xff0c;我们从三方面来理解这句话&#xff1a;1、数据保存到哪里 -- 各种媒介&#xff0c;CPU、内存、磁盘、磁带、网盘...2、数据保…

react+ts+antd-mobile 动态tabs➕下拉加载

1.初始化项目 //搭建项目 npm create vitelatest react-jike-mobile -- --template react-ts//安装依赖 npm i //运行 npm run dev清理项目目录结构 安装ant design mobile ant design mobile是ant design家族里专门针对于移动端的组件库 npm install --save antd-mobile测试…