java排序算法

news2024/11/24 18:51:59

目录

一 冒泡排序

二 选择排序

三 插入排序

四 希尔排序

五 快速排序

5.1 单边循环快速排序

5.2 双边循环快速排序

六 二分查找

七 总结


一 冒泡排序

  1. 依次比较数组中相邻的两个元素,若 arr[i] > arr[i+1],则交换两个元素,两两都比较一遍称为一轮冒泡,结果是最大的元素排在最后。
  2. 重复以上操作,直至整个数组有序。
  3. 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,如果这个值为0,表示整个数组有序,直接退出外层循环。
public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {5,9,7,4,1,2,8,3,6};
        bubble(arr);
    }

    public static void bubble(int[] arr) {
        int n = arr.length - 1;
        while(true) {
            int last = 0; // 最后一次交换索引位置
            for(int i=0;i<n;i++) {
                if(arr[i] > arr[i+1]) {
                    swap(arr, i, i+1);
                    last = i;
                } 
            }
            n = last;
            if(n == 0) {
                break;
            }
            System.out.println(Arrays.toString(arr));
        }  
    }

    public static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

二 选择排序

  1. 将数组分为两个子集,排序的和未排序的,每一轮从未排序的子集中选出最小的元素,放入排序子集。
  2. 重复以上操作,直至整个数组有序。
  3. 每轮可以先找到最小的索引,在每轮最后在交换元素。
public class SelectionSort {
    public static void main(String[] args) {
        int[] arr = {5,9,7,4,1,2,8,3,6};
        selection(arr);
    }

    public static void selection(int[] arr) {
        for(int i=0;i<arr.length-1;i++) {
            int s = i; // 记录最小元素索引
            for(int j=s+1;j<arr.length;j++) {
            	if(arr[s] > arr[j]) {
            		s=j;
            	}
            }
            if(s != i) {
                swap(arr, s, i);
            }
            System.out.println(Arrays.toString(arr));
        }
    }

    public static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

三 插入排序

  1. 将数组分为两个区域,排序区和未排序区,每一轮从未排序区域选取第一个元素,插入到排序区域(需要保证顺序)。
  2. 重复以上操作,直至整个数组有序。
  3. 待插入元素进行比较时,遇到比自己小的元素,就代表找到了插入位置,无需进行后续比较。
public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {5,9,7,4,1,2,8,3,6};
        insert(arr);
    }

    public static void insert(int[] arr) {
    	// i 代表待插入元素的索引
        for(int i=1;i<arr.length;i++) {
            int t = arr[i]; // 待插入元素的值
            int j = i-1; // 已排序元素的索引
            while(j >= 0) {
                if(t < arr[j]) {
                    arr[j+1] = arr[j];
                } else {
                    break; // 退出循环,减少比较次数
                }
                j--;
            }
            arr[j+1] = t;
            System.out.println(Arrays.toString(arr));
        }
    }
}

四 希尔排序

  1. 设置间隙序列。
  2. 将间隙相同元素划为一组,对每组使用插入排序。
  3. 重复以上操作,直至数组有序。
public class ShellSort {
	
	public static void main(String[] args) {
		int[] arr = {5,9,7,4,1,2,8,3,6};
		shell(arr);
	}
	
	public static void shell(int[] arr) {
		// 分而治之,循环为每次总数除二
		for (int gap = arr.length/2; gap > 0; gap /= 2) {
			// 循环分治的每一个分组使用插入排序
	        for (int i = gap; i < arr.length; i++) {
	            int t = arr[i];
	            int j = i-gap;
	            while (j >= 0) {
	            	if (t < arr[j]) {
	            		arr[j + gap] = arr[j];
	            	} else {
	            		break;
	            	}
	            	j -= gap;
	            }
	            arr[j+gap] = t;
	            System.out.println(Arrays.toString(arr));
	        }
	        System.out.println("gap="+gap+":"+Arrays.toString(arr));
		}
	}
	
}

五 快速排序

5.1 单边循环快速排序

  1. 选择最右边元素作为基准点元素。
  2. j 指针负责找到基准点小的元素,一旦找到则与 i 进行交换。
  3. i 指针维护小于基准点元素边界,也是每次交换的目标索引。
  4. 最后基准点与 i 交换,i 即为分区位置。
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {5,9,7,4,1,2,8,3,6};
        quick(arr, 0, arr.length-1);
    }

    public static void quick(int[] arr, int l, int h) {
        if(l >= h) {
            return;
        }
        int pv = partition(arr, l, h);
        quick(arr, l, pv-1); // 左边分区范围确定
        quick(arr, pv+1, h); // 右边分区范围确定
    }

    public static int partition(int[] arr, int l, int h) {
        int pv = arr[h];
        int i = l;
        for(int j=l;j<h;j++) {
            if(arr[j] < pv) {
                if(i != j) {
                    swap(arr, i, j);
                }
                i++;
            }
        }
        if(i != h) {
            swap(arr, h, i);
        }
        System.out.println(Arrays.toString(arr));
        return i;
    }

    public static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

5.2 双边循环快速排序

  1. 选择最左边元素作为基准点元素。
  2. j 指针负责从右向左找比基准点小的元素,i 指针负责从左向右找比基准点大的元素,一旦找到二者交换,直至 i、j 相交。
  3. 最后基准点与 i(此时 i 与 j 相等)交换,i 即为分区位置。
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {5,9,7,4,1,2,8,3,6};
        quick(arr, 0, arr.length-1);
    }

    public static void quick(int[] arr, int l, int h) {
        if(l >= h) {
            return;
        }
        int pv = partition(arr, l, h);
        quick(arr, l, pv-1); // 左边分区范围确定
        quick(arr, pv+1, h); // 右边分区范围确定
    }

    public static int partition(int[] arr, int l, int h) {
        int pv = arr[l];
        int i = l;
        int j = h;
        while(i < j) {
            // j 从右找小的
            while(i < j && arr[j] > pv) {
                j--;
            }
            // i 从左找大的
            while(i < j && arr[i] <= pv) {
                i++;
            }
            swap(arr, i, j);
        }
        swap(arr, l, j);
        System.out.println(Arrays.toString(arr));
        return j;
    }

    public static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

六 二分查找

1、前提:有已排序的数组 arr。

2、定义左边界 l,右边界 r,确定搜索范围,循环执行二分查找(3、4步)。

3、获取中间索引 m = Floor((l+r)/2)。

4、中间索引的值 arr[m] 与待搜索的值 t 进行比较。

  • arr[m] == t 表示找到,返回中间索引。
  • arr[m] > t,中间值右侧的其它元素都大于 t,无需比较,中间索引左边去找,m-1 设置为右边界,重新查找。
  • arr[m] < t,中间值左侧的其它元素都大于 t,无需比较,中间索引右边去找,m+1 设置为左边界,重新查找。

5、当 l > r,表示没有找到,结束循环。

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 5, 8, 11, 19, 22, 31, 35, 40, 45, 48, 49, 50};
        int t = 48;
        int index = binarySearch(arr, t);
            
        System.out.println(index);
    }

    public static int binarySearch(int[] arr, int t) {
        int l = 0, r = arr.length - 1, m;
        while(l <= r) {
            //m = l+(r-l)/2; // 解决整数溢出
            m = (l+r) >>> 1;
            if(arr[m] == t) {
                return m;
            } else if(arr[m] > t) {
                r = m-1;
            } else {
                l = m+1;
            }
        }

        return -1;
    }
}

6、面试题

  • 奇数二分取中间
  • 偶数二分取中间靠左

1、有一个有序表为[1,5,8,11,19,22,31,35,40,48,49,50],当二分查找值为48的节点时,需经过几次比较?

2、有一个有序表为[1,4,6,7,15,33,50,64,75,78,81,89,96],当二分查找值为81的节点时,需经过几次比较?

3、在拥有128个元素的数组中二分查找一个数,需要比较的次数最多不超过几次?

  •     \log_{10}128 / \log_{10}2
  •     整数,则该整数即为最终结果
  •     小数,舍去小数部分,整数+1即为最终结果

七 总结

  • int[] arr = {5,9,7,4,1,2,8,3,6} 
时间复杂度实现优化排序过程
冒泡排序O(n^{2})
  1. 依次比较数组中相邻的两个元素,若 arr[i] > arr[i+1],则交换两个元素,两两都比较一遍称为一轮冒泡,结果是最大的元素排在最后。
  2. 重复以上操作,直至整个数组有序。
  • 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,如果这个值为0,表示整个数组有序,直接退出外层循环。
[5, 7, 4, 1, 2, 8, 3, 6, 9]
[5, 4, 1, 2, 7, 3, 6, 8, 9]
[4, 1, 2, 5, 3, 6, 7, 8, 9]
[1, 2, 4, 3, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
选择排序O(n^{2})
  1. 将数组分为两个子集,排序的和未排序的,每一轮从未排序的子集中选出最小的元素,放入排序子集。
  2. 重复以上操作,直至整个数组有序。
  • 每轮可以先找到最小的索引,在每轮最后在交换元素。
[1, 9, 7, 4, 5, 2, 8, 3, 6]
[1, 2, 7, 4, 5, 9, 8, 3, 6]
[1, 2, 3, 4, 5, 9, 8, 7, 6]
[1, 2, 3, 4, 5, 9, 8, 7, 6]
[1, 2, 3, 4, 5, 9, 8, 7, 6]
[1, 2, 3, 4, 5, 6, 8, 7, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
插入排序

O(n^{2})

  1. 将数组分为两个区域,排序区和未排序区,每一轮从未排序区域选取第一个元素,插入到排序区域(需要保证顺序)。
  2. 重复以上操作,直至整个数组有序。
  • 待插入元素进行比较时,遇到比自己小的元素,就代表找到了插入位置,无需进行后续比较。
  • 插入时可以直接移动元素,而不是交换元素。
[3, 5, 1, 7, 2, 9, 8, 4, 6]
[1, 3, 5, 7, 2, 9, 8, 4, 6]
[1, 3, 5, 7, 2, 9, 8, 4, 6]
[1, 2, 3, 5, 7, 9, 8, 4, 6]
[1, 2, 3, 5, 7, 9, 8, 4, 6]
[1, 2, 3, 5, 7, 8, 9, 4, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
希尔排序
  1. 设置间隙序列
  2. 将间隙相同元素划为一组,对每组使用插入排序。
  3. 重复以上操作,直至数组有序。
[1, 9, 7, 4, 5, 2, 8, 3, 6]
[1, 2, 7, 4, 5, 9, 8, 3, 6]
[1, 2, 7, 4, 5, 9, 8, 3, 6]
[1, 2, 7, 3, 5, 9, 8, 4, 6]
[1, 2, 7, 3, 5, 9, 8, 4, 6]
gap=4:[1, 2, 7, 3, 5, 9, 8, 4, 6]
[1, 2, 7, 3, 5, 9, 8, 4, 6]
[1, 2, 7, 3, 5, 9, 8, 4, 6]
[1, 2, 5, 3, 7, 9, 8, 4, 6]
[1, 2, 5, 3, 7, 9, 8, 4, 6]
[1, 2, 5, 3, 7, 9, 8, 4, 6]
[1, 2, 5, 3, 7, 4, 8, 9, 6]
[1, 2, 5, 3, 6, 4, 7, 9, 8]
gap=2:[1, 2, 5, 3, 6, 4, 7, 9, 8]
[1, 2, 5, 3, 6, 4, 7, 9, 8]
[1, 2, 5, 3, 6, 4, 7, 9, 8]
[1, 2, 3, 5, 6, 4, 7, 9, 8]
[1, 2, 3, 5, 6, 4, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
gap=1:[1, 2, 3, 4, 5, 6, 7, 8, 9]
 
快速排序-单边循环

O(n^{2})

  1. 选择最右边元素作为基准点元素。
  2. j 指针负责找到基准点小的元素,一旦找到则与 i 进行交换。
  3. i 指针维护小于基准点元素边界,也是每次交换的目标索引。
  4. 最后基准点与 i 交换,i 即为分区位置。
[5, 4, 1, 2, 3, 6, 8, 7, 9]
[1, 2, 3, 4, 5, 6, 8, 7, 9]
[1, 2, 3, 4, 5, 6, 8, 7, 9]
[1, 2, 3, 4, 5, 6, 8, 7, 9]
[1, 2, 3, 4, 5, 6, 8, 7, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
快速排序-双边循环

平均:O(n\log_{2}n)

最坏:O(n^{2})

  1. 选择最左边元素作为基准点元素。
  2. j 指针负责从右向左找比基准点小的元素,i 指针负责从左向右找比基准点大的元素,一旦找到二者交换,直至 i、j 相交。
  3. 最后基准点与 i(此时 i 与 j 相等)交换,i 即为分区位置。
[1, 3, 2, 4, 5, 7, 8, 9, 6]
[1, 3, 2, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 6, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

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

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

相关文章

RabbitMQ原理剖析

常见的消息队列很多&#xff0c;主要包括 RabbitMQ、Kafka、RocketMQ 和 ActiveMQ&#xff0c;本篇文章只讲 RabbitMQ&#xff0c;先讲原理&#xff0c;后搞实战。 直接上思维导图&#xff1a; 1. 消息队列 1.1 消息队列模式 消息队列目前主要 2 种模式&#xff0c;分别为“…

【AI with ML】第 6 章 :使用嵌入使情绪可编程

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Web安全研究(二)

TChecker: Precise Static Inter-Procedural Analysis for Detecting Taint-Style Vulnerabilities in PHP Applications 香港中文大学&#xff0c;CCS2022 Abstract 由于php语言的高度复杂性&#xff0c;现有的污点分析解决方案由于其不全面的程序间分析和各种实现问题&#…

DIV简单个人静态HTML网页设计作品 WEB静态个人介绍网页模板代码 DW个人网站制作成品 期末网页制作与实现

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

jmeter压测线程5000后内存溢出问题解决

一.报错内容&#xff1a; ava.lang.OutOfMemoryError: Java heap space&#xff1a;意思就是堆内存溢出&#xff0c;不够用了 版本&#xff1a;jmeter5 内存溢出&#xff1a;应用的内存已经不能满足正常使用了&#xff0c;堆栈已经达到系统设置的最大值&#xff0c;进而导致崩…

【图像融合】高斯金字塔+拉普拉斯金字塔彩色水下图像融合【含Matlab源码 1629期】

⛄一、区域分割图像融合简介 图像的分解 对源图像进行融合时,首先对图像进行分解,利用拉普拉斯金字塔分解,先对图像进行高斯金字塔分解,然后再进行拉普拉斯金字塔分解。 1 高斯金字塔分解 记源图像为G0,G0即为高斯金字塔最底层,将其进行高斯低通滤波,之后对其进行隔行隔列的下…

mysqldump实战-问题1

使用mysqldump导出数据时&#xff0c;遇到了一个权限问题(之前没报过这个提示) mysqldump: Error: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation when trying to dump tablespaces 查看当前用户的权限&#xff1a; 解决方法&…

ARM 指令流水线

CPU要执行某一个指令&#xff0c;第一步&#xff0c;PC给内存发送地址&#xff0c;IR接收内存返回的指令&#xff1b;第二步&#xff0c;指令译码器解析IR中的指令&#xff1b;第三步&#xff0c;寄存器执行译码结果对应的运算单元。 实际上&#xff0c;译码器在译码的时候&am…

flutter 基于百度地图的地图选址,包括移动选址,地区搜索 ,仿微信地图选址

flutter 最近有在地图上选择地址的需求&#xff0c;要求如下 1.移动地图获取根据地图中心点获取周边的poi信息 2.搜索&#xff0c;根据搜索内容提示相关地点信息&#xff0c;点击移动到相关位置&#xff0c;显示出该位置周边的poi信息 废话少说&#xff0c;先上视频 flutter…

菜鸟Linux(2):进程优先级与进程状态

"才一年,看着世界变迁,有种沧海桑田" 一、进程调度 与 进程优先级 (1)何为优先级 双击.exe(可执行程序)文件 会发生什么&#xff1f; 但是,当我们使用电脑的时候,不仅仅只会 启动一个程序&#xff01; 系统中一定会有多个 进程同时存在&#xff01; 然而,需求是无…

什么是云手机?云手机的原理是什么?

什么是云手机? 云手机(Cloud Phone)是在云上运行APP的仿真手机。云手机服务根据不同场景提供多种规格的云手机&#xff0c;稳定24小时不间断&#xff0c;全面兼容Android原生APP&#xff0c;流畅运行大型手游&#xff0c;是移动办公好助手。云手机服务为您提供高性能、安全、…

微服务Spring Boot 整合 Redis 实现好友关注 – Feed流实现推送到粉丝收件箱

文章目录⛄引言一、Redis 实现好友关注 -- Feed流实现推送到粉丝收件箱⛅Feed 流实现方案⚡推送到粉丝收件箱三、Redis 实现好友关注 -- 实现分页滚动查询 实时获取信息⛵小结⛄引言 本博文参考 黑马 程序员B站 Redis课程系列 在点评项目中&#xff0c;有这样的需求&#xff…

【正点原子I.MX6U-MINI】删除开机内核Logo和进度条界面Logo

一、编译内核 内核源码1、例程源码-》3、正点原子 Uboot 和 Linux 出厂源码-》linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2。 在 Ubuntu 中新建名为“alientek_linux”的文件夹&#xff0c;然后将 linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2 这个压缩包拷贝到前面新建的 aliente…

Revit中用楼板编辑创建坡道的两种方法

在绘制坡道的时候&#xff0c;有一种两侧带坡度的坡道&#xff0c;一般我们采用楼板编辑的方式来创建。 方法有两种&#xff1a; 第一种是听过添加子图元的点来创建&#xff0c;方法如下&#xff0c; 首先绘制设计所需的楼板尺寸&#xff0c;完成之后点击楼板&#xff0c;形状编…

【Flutter 组件】004-基础组件:图片及 ICON

【Flutter 组件】004-基础组件&#xff1a;图片及 ICON 文章目录【Flutter 组件】004-基础组件&#xff1a;图片及 ICON一、图片1、Image概述Image 的几个构造方法常用属性ImageProvider2、从 asset 中加载图片第一步&#xff1a;准备图片第二步&#xff1a;使用图片第三步&…

9.高性能计算 期末复习

文章目录1.提纲2.第二章 并行硬件&程序设计2.1 SIMD&MIMD2.2 可扩展性2.7 串行程序并行化&#xff08;poster四步&#xff1a;划分、通信、聚合、分配&#xff09;3.mpi2.1 点对点gemm2.2集合通信gemmsend/recv实现reducesend/recv 实现ring AllReduce2.3 加速比2.4 奇…

数据预处理的方法有哪些?

数据处理的工作时间占据了整个数据分析项目的70%以上。因此&#xff0c;数据的质量直接决定了分析模型的准确性。那么&#xff0c;数据预处理的方法有哪些呢&#xff1f;比如数据清洗、数据集成、数据规约、数据变换等&#xff0c;其中最常用到的是数据清洗与数据集成&#xff…

医学影像篇

影像组学研究的基本流程知识点 01 准备工作 研究前我们先要做好准备工作&#xff1a;&#xff08;这个准备工作呢就好像小白做菜&#xff09; 最开始&#xff0c;我们往往主动提出或者被提出了一个临床问题&#xff08;临床问题可能是老板直接安排的&#xff0c;也可能是在临…

【网管日记】Nginx基本介绍、安装与使用

Nginx基本使用 基本介绍 Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是 占用内存少&#xff0c;并发能力强 &#xff0c;事实上nginx的并发能力在同类型的网页服务器中表现较好&#xff0c;中国大陆使用ngin…

AntV-G6:图表自动居中显示/画布自适应/fitView

需求描述 图表节点较多时&#xff0c;可能分布到屏幕可视范围之外&#xff0c;期望图表自动居中显示 调研分析 阅读官网文档&#xff1a;G6.Graph配置项&#xff0c;一下就看到了这个配置项&#xff1a; 看起来只要在初始化图表的配置里加上“fitView: true”就能万事大吉了…