26从零开始学Java之如何对数组进行排序与二分查找?

news2024/11/28 12:39:10

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦

千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

在上一篇文章中,壹哥给大家讲解了数组的扩容、缩容及拷贝方式。接下来在今天的文章中,壹哥会给大家讲解更重要的数组排序及查找方法。今天的内容会有点难,希望你不要因此而退缩,挺过这一关,你会向上突破的!

------------------------------------------------前戏已做完,精彩即开始----------------------------------------------

全文大约【3500】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

配套开源项目资料

Github:

GitHub - SunLtd/LearnJavaContribute to SunLtd/LearnJava development by creating an account on GitHub.https://github.com/SunLtd/LearnJava

Gitee:

Gitee - 从零开始学Javahttps://gitee.com/sunyiyi/LearnJava

一. 数组排序

1. 简介

Java中的数组是一种数据集合,里面可以存储若干数据元素。有时我们需要对这些数据元素进行排序,找出数组中的最大值、最小值,或者是按降序或升序对数组进行排列,这些需求都需要我们能够对数组进行排序。但我们要注意,对数组排序会修改数组本身,即数组里元素的内存指向会发生改变。

对数组进行排序是程序中很常见的需求。如果我们想要实现数组排序,可以利用数据结构中的某些排序算法来进行实现,比如著名的冒泡排序、选择排序等,当然也可以利用Java自带的Arrays.sort()方法来实现。接下来壹哥就针对这几种实现方案,给大家设计几个实现案例。

2. 冒泡排序(重点)

2.1 简介

冒泡排序的核心实现思路,就是把数据元素按照从下到上,两两进行比较。所以冒泡排序的特点是,每一轮循环后,最大的一个数被交换到末尾。因此,下一轮循环可以“刨除”最后的数,每一轮循环都比上一轮循环的结束位置靠前一位。冒泡排序整体可以分为两种情况,即升序排列和降序排列。

升序排列的实现思想:

  1. 将数组中相邻的两个数据元素进行比较,如果前面一个元素比后面的大,就把两者交换位置(一轮比较);
  2. 然后将上面的操作进行循环(比较n-1轮)。

排列过程如下图所示:

降序排列的实现思想:

  1. 将数组中相邻的两个数据元素进行比较,如果前面一个元素比后面的小,就把两者交换位置(一轮比较);
  2. 然后将上面的操作进行循环(比较n-1轮)。

2.2 基本实现

大家要注意,面试时经常会让我们手写冒泡排序和选择排序等算法,你必须牢牢地记住相关的代码实现哦。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo09 {
	public static void main(String[] args) {
		// 冒泡排序--基本实现
		//待排序的数组
		int[] arr = { 1, 3, 46, 22, 11 };

		//控制需要比较几轮
		for (int i = 0; i < arr.length; i++) {
			//控制每一轮的比较次数
			for (int j = 0; j < arr.length - 1; j++) {
				//如果前面的比后面的数字大,则两者就进行交换
				if (arr[j] > arr[j + 1]) {
					//两数交换,需要一个“第三方”,好比两杯水互换,需要第三个杯子。

                    //交换两个变量的值,必须借助一个临时变量。
					//定义一个新的临时变量,将数组中的前面的元素先赋值给临时变量
					int temp = arr[j];
					//后面的值赋值到前面的位置上
					arr[j] = arr[j + 1];
					//再将临时变量的值赋值到后面的位置上
					arr[j + 1] = temp;
				}
			}
		}
		
		//遍历排序后的数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"\t");
		}
	}
}

这种实现方式比较容易理解,但并不是最优的实现方案,因为这种方案需要比较的次数较多。我们可以进一步对该方案进行优化,将比较的次数降下来,请继续往下看。

2.3 优化次数

在本案例中,壹哥会对比较次数进行优化。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo10 {
	public static void main(String[] args) {
		// 冒泡排序--优化比较次数
		// 待排序数组
		int[] arr = { 1, 3, 46, 22, 11 };

		for (int j = 0; j < arr.length; j++) {   //控制轮数
	        for (int i = 0; i < arr.length - 1 - j; i++) {//控制每一轮的次数
	            if(arr[i] > arr[i+1]) {
	                int temp = arr[i];
	                arr[i] = arr[i+1];
	                arr[i+1] = temp;
	            }
	        }
	    }
		
		//遍历排序后的数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"\t");
		}
	}
}

本案例同样也不是最优的实现方案,我们也可以对该实现方案进行优化。

2.4 优化轮数

在本案例中,壹哥会对比较的轮数进行优化。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo11 {
	public static void main(String[] args) {
		// 冒泡排序--优化比较轮数
		// 待排序数组
		int[] arr = { 1, 3, 46, 22, 11 };

		for (int j = 0; j < arr.length - 1; j++) { //轮数
	        //假设这一轮已经拍好序,设置一个标签进行记录
	        boolean flag = true;
	        
	        for (int i = 0; i < arr.length - 1 - j; i++) {//每一轮比较的次数
	            if(arr[i] > arr[i+1]) {
	            	//更改是否比较过的标签
	                flag = false;
	                int temp = arr[i];
	                arr[i] = arr[i+1];
	                arr[i+1] = temp;
	            }
	        }
	        
	        //如果本轮已排序好,则直接跳过,避免没必要的比较。
	        if(flag) {
	            break;
	        }
	    }
		
		//遍历排序后的数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"\t");
		}
	}
}

这种实现方案,可以说是三种方案中最优的一种,但对初学者来说,理解起来确实不容易。当然,在我们的线下课程中,我们的讲师会对实现的每一个步骤详细讲解,不用怕自己理解不了。

2.5 配套视频

为了方便大家更好地理解冒泡排序,壹哥这里有对应的视频哦,链接如下:

bilibili html5 player

3. 选择排序(重点)

3.1 简介

选择排序的核心实现思路,是随机确定一个标志位(一般为第一个数字)作为最小数,然后向后遍历,找到比标志位更小的数字后,便与标志位互换位置,并更新最小数。选择排序同样可以进行升序或降序排列。

选择排序升序思路:

  1. 将当前位置上的数,与它后面的每个数进行比较,选择出最小的那个数,交换到当前位置;
  2. 循环选择当前位置上的数。

选择排序降序思路:

  1. 将当前位置上的数,与它后面的每个数进行比较,选择出最大的那个数,交换到当前位置;
  2. 循环选择当前位置上的数。

3.2 实现案例

以下是以升序的方式实现的选择排序代码,供大家参考。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦 
 * 千锋教育
 */
public class Demo12 {
	public static void main(String[] args) {
		// 选择排序
		// 待排序的数组
		int[] arr = { 1, 3, 46, 22, 11 };

		for (int j = 0; j < arr.length-1; j++) {
	        //选择下标为0的位置
	        int min = j;
	        
	        //将当前这个数与后面的每个数进行比较
	        for (int i = j+1; i < arr.length; i++) {
	        	//如果当前数字小于标记的最小值,则将当前数字标记为最小值
	            if(arr[min] > arr[i]) {
	                min = i;
	            }
	        }
	        
	        //如果当前数字不是最小的,则进行交换
	        if(min != j) {
	            int temp = arr[j];
	            arr[j] = arr[min];
	            arr[min] = temp;
	        }
	    }
		
		//遍历排序后的数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"\t");
		}
	}
}

3.3 配套视频

为了方便大家更好地理解选择排序,壹哥这里有对应的视频哦,链接如下:

bilibili html5 player

4. Arrays.sort方法

以上两种排序算法,实现起来是比较复杂的,但在面试时,基本上都要求我们能够手写出冒泡排序和选择排序,大家一定要把代码看懂哦。但如果我们想快速实现排序,其实可以使用Java自带的API方法进行实现,这个会更简单。

4.1 简介

Arrays工具类主要用于对数组进行排序、查找、填充、比较等的操作,该类存在于java.util包下,所以我们使用的第一步就是要先进行导包: import java.util.Arrays;

其中Arrays.sort()是Arrays类中的一个静态方法,用于对数组进行排序,我们可以直接调用。该方法有如下几种重载形式:

  • sort(T[] a):对指定T型数组按数字升序排序;
  • sort(T[] a, int formIndex, int toIndex):对指定T型数组中[formIndex,toIndex)数据按数字升序排序;
  • sort(T[] a, Comparator<? supre T> c): 依据比较器对T型数组进行排序;
  • sort(T[] a, int formIndex, int toIndex, Comparator<? supre T> c): 依据比较器产生的顺序对T型数组中的[formIndex,toIndex)进行排序。

4.2 实现案例

接下来壹哥再给大家设计一个利用Arrays.sort方法实现的排序案例。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo13 {
	public static void main(String[] args) {
		// 选择排序
		//遍历排序后的数组
		String[] names = { "cxk", "rose", "lihua", "lilei", "zhaosi" };
		
		//直接利用Arrays类提供的数组排序的方法,内部是基于“快速排序”实现的。
		Arrays.sort(names);

		for (int i = 0; i < names.length; i++) {
			System.out.print(names[i] + "\t");
		}
	}
}

二. 二分查找法(重点)

1. 简介

我们对数组除了可以进行排序之外,还能对数组中的元素进行查找,其中一个比较经典的方案是利用二分查找法,也叫做折半查找法进行实现,可以缩小查找范围,提高查找效率。

二分查找是一种效率较高的查找方法,要求数据表须采用顺序存储结构,且数组是有序(升序或者降序)的。核心思路就是将待查找的元素与中间下标对应的元素进行比较,如果大于中间下标对应的元素,则去右半部分查找,否则就去左半部分进行查找。基本实现流程如下:

  • 首先,我们假设数组中的元素是按升序排列的;
  • 然后将数组中间位置记录的关键字与查找关键字进行比较,如果两者相等,则查找成功;
  • 否则就利用中间的位置记录,将数组分成前、后两个子部分。如果中间位置记录的关键字大于查找关键字,则进一步查找前一子部分,否则进一步查找后一子部分;
  • 重复以上过程,直到找到满足条件的记录为止。或直到子部分不存在为止,此时查找不成功。

2. 实现案例

然后壹哥就按照上述思路,给大家设计了如下案例,大家可以对照练习,好好琢磨该案例。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo14 {
	public static void main(String[] args) {
		// 二分查找法--折半查找法

		// 遍历排序后的数组
		int[] arr = { 1, 3, 46, 22, 11 };

		int index = search(arr,46);
		System.out.println("46所在的索引位置="+index);
	}
	
	//定义一个方法,实现二分查找
	public static int search(int[] arr,int num) {
	    //1. 获取最小、大值的下标
	    int min = 0;
	    int max = arr.length -1;

	    while(min <= max) {
	        //2. 获取中间值的下标
	        int middle = (min + max) / 2;

	        //3. 将要查找的数字与中间值做比较
	        if(num > arr[middle]) {
	            min = middle +1;
	        }else if(num < arr[middle]) {
	            max = middle -1;
	        }else {
	            return middle;
	        }
	    }
	    return -1;
	}
}

3. 配套视频

为了方便大家更好地理解二分查找法,壹哥这里有对应的视频哦,链接如下:

bilibili html5 player

------------------------------正片已结束,来根事后烟----------------------------

三. 结语

至此,壹哥就把一维数组的内容给大家介绍完毕了,现在你知道数组有什么作用了吗?今日重点:

  • 常用的排序算法有冒泡排序、插入排序和快速排序等;
  • 冒泡排序使用两层for循环实现排序;
  • 交换两个变量的值需要借助一个临时变量。
  • 可以直接使用Java标准库提供的Arrays.sort()进行排序;
  • 对数组排序会直接修改数组本身。

对于数组,我们要掌握其基本用法,明白数组的扩容原理,并掌握数组的排序算法。如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

四. 今日作业

1. 第一题

录入班级学员的人数,然后循环给学员的名字赋值。之后输入一个名字,查找该学员是否在此班级中。

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

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

相关文章

深眸科技|深度学习、3D视觉融入机器视觉系统,实现生产数智化

随着“中国制造2025”战略加速落实&#xff0c;制造业生产线正在加紧向智能化、自动化和数字化转型之路迈进。而人工智能技术的兴起以及边缘算力持续提升的同时&#xff0c;机器视觉及其相关技术也在飞速发展&#xff0c;并不断渗透进工业领域&#xff0c;拓展应用场景的同时&a…

Apache Druid中Kafka配置远程代码执行漏洞(MPS-2023-6623)

漏洞描述 Apache Druid 是一个高性能的数据分析引擎。 Kafka Connect模块曾出现JNDI注入漏洞(CVE-2023-25194)&#xff0c;近期安全研究人员发现Apache Druid由于支持从 Kafka 加载数据的实现满足其利用条件&#xff0c;攻击者可通过修改 Kafka 连接配置属性进行 JNDI 注入攻…

软件架构中间件技术

中间件的定义 其实中间件是属于构件的一种。是一种独立的系统软件或服务程序&#xff0c;可以帮助分布式应用软件在不同技术之间共享资源。 我们把它定性为一类系统软件&#xff0c;比如我们常说的消息中间件&#xff0c;数据库中间件等等都是中间件的一种体现。一般情况都是…

减少 try catch ,可以这样干

软件开发过程中&#xff0c;不可避免的是需要处理各种异常&#xff0c;就我自己来说&#xff0c;至少有一半以上的时间都是在处理各种异常情况&#xff0c;所以代码中就会出现大量的try {...} catch {...} finally {...}代码块&#xff0c;不仅有大量的冗余代码&#xff0c;而且…

d3.js学习笔记①创建html文档

本人之前从未学过HTML、CSS、JavaScript&#xff0c;然而我导是做前端的&#xff0c;要求我必须在三周内掌握d3.js&#xff0c;我只能从0学起并以此记录自己的学习过程。 首先对这三种语言有一个初步的认识&#xff1a;HTML是用于搭建网页框架&#xff0c;CSS是美化网页的&…

软件设计师考试——计算机网络、系统安全分析和设计部分

计算机网路 七层模型 OSI/RM七层模型 网络技术标准与协议 TCP协议 DHCP协议 DNS协议 计算机网络的分类——拓扑结构 按分布范围&#xff1a; 局域网城域网广域网因特网 按拓扑结构&#xff1a; 总线型星型环型 网络规划与设计 逻辑网络设计 物理网络设计 分层设计 IP地址…

VirboxLM-免服务版授权码,快速实现一机一码

一、产品介绍 ​ 授权码是由深盾科技开发的一款软件保护及授权管理产品 ​&#xff0c;一方面要保护软件代码不被逆向&#xff0c;另一方面要控制软件的授权使用。软件用户只需要输入授权码&#xff08;由数字和字母组成的一串字符&#xff09;&#xff0c;激活授权码后即可使…

这年头,谁还在「贩卖」生活方式?

【潮汐商业评论/原创】 “我已经很久没有追寻过品牌购物了”Anna如是说。 如今的Anna对商品的选择往往会考虑性价比以及简洁的外观&#xff0c;去品牌化、简单已经成为其新的生活方式。 日本作者三浦展在《第四消费时代》一书中提到&#xff0c;在第三消费社会&#xff0c;新…

Java版本企业工程项目管理系统平台源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理)

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…

Android 获取奔溃crash的日志(adb logcat或者dropbox)

1.通过adb logcat 来获取&#xff1a; 使用场景&#xff1a;测试或者开发小伙伴 抓取。 先执行adb logcat -c 清理缓存日志 接着&#xff0c;抓取当前时间段开始的日志: adb logcat -v time >D:/crash.log 也可以抓取指定进程的日志&#xff1a; adb logcat -v time | fi…

利用POSIX多线程API函数进行多线程开发

本书文字内容源自 <<linux C/C服务器开发实践>> 支持正版图书&#xff0c;测试代码根据测试目的&#xff0c;可自行修改测试。 前言 在用POSIX多线程API函数进行开发之前&#xff0c;我们首先要熟悉这些API函数。常见的与线程有关的基本API函数见下表 使用这些A…

亚马逊云科技综合解决方案助力美的智能化,成本节省30%

很多人都有和客服打交道的体验&#xff0c;而这种体验大概率不佳&#xff0c;人工客服迟迟不应&#xff0c;解答问题也不精准&#xff0c;糟糕的客服体验对于面向消费者的企业来说亦是一大难题&#xff0c;严重者甚至会导致客户流失、评价滑坡等后果&#xff0c;作为知名科技电…

FileInputStream.read和FileChannel.read的区别

FileChannel怎么来的 FileChannel channel new FileInputStream("").getChannel() FileChannel的read()方法 channel.read(byteBuffer) 实现类FileChannelImpl 首先映入眼帘的就是非常熟悉的synchronized关键字&#xff0c; private final Object positionLock ne…

宏基因组组装 | 就现在!做出改变!!

微生态研究的核心难点是什么&#xff01; 基因组组装&#xff01; 从宏基因组数据中组装获得细菌的完整基因组&#xff08;complete MAGs&#xff09;是微生物组研究的长期目标&#xff0c;但基于NGS的宏基因组测序和组装方法是无法实现完整的细菌基因组组装的。即便是红极一…

appium-app测试-环境搭建手机和adb设置

1、手机设置&#xff08;Android手机-readMI k50&#xff09;&#xff1a; 1.1开发者模式设置 入口&#xff1a;设置–我的设备–全部参数与信息&#xff1b; 连续点击MIUI版本7下&#xff0c;进入开发者模式 1.2、开发者选项设置 入口&#xff1a;设置–更多设置–开发者选项…

np.convolve(x,h, mode=‘##‘)的使用

用法&#xff1a; np.convolve(a,v,mode) a代表卷积数据&#xff0c;v卷积核大小&#xff0c;mode卷积方式&#xff0c;mode卷积方式有三种 same full valid mode可能的三种取值情况&#xff1a; full’ 默认值&#xff0c;返回每一个卷积值&#xff0c;长度是NM-1,在卷积的…

MyBatis:使用 MyBatis 实现增删改查、各种配置解析

文章目录 MyBatis&#xff1a;Day 01一、简介二、第一个 MyBatis 程序1. 步骤2. 注意 三、增、删、改、查四、扩展1. Map2. 模糊查询 五、配置解析&#xff08;参考手册&#xff09;1. 环境配置&#xff1a;environments2. 属性优化&#xff1a;properties3. 类型别名&#xff…

中国厨房更净一步:一场科技“下凡”带来的方太式浪漫

世界上恐怕没有任何一个民族&#xff0c;比中国人对美食的情结更悠远了。 正如《菜根谭》里说的&#xff0c;“醲肥辛甘非真味&#xff0c;真味只是淡&#xff1b;神奇卓异非至人&#xff0c;至人只是常”。 寻常人家的一蔬一饭&#xff0c;是厨房里的幸福记忆&#xff0c;也承…

大数据分析案例-基于朴素贝叶斯算法构建微博谣言检测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

干货!ICLR 2023 | 更稳定高效的因果发现方法-自适应加权

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; ╱ 个人简介╱ 张岸 新加坡国立大学NExT实验室博士后&#xff0c;主要研究Robust & Trustable AI。 个人主页&#xff1a;https://anzhang314.github.io/ 01 内容简介 可微分的因果发现方法&#xff0c;是从…