正在学Java的各位,这几种Java编程中的经典算法千万不要错过,算法在Java开发中会起到非常重要作用,了解这些常用的算法会让你在工作中达到事半功倍的效果!
看看今天为大家整理经典算法详解:
目录
- 基本查找
- 二分查找
- 分块查找
基本查找
基本查找又称顺序查找。
- 核心:从0索引开始挨个往后查找
我们一起来看一个案例:
需求:定义一个方法利用基本查找,查询某个元素是否存在。
数据如下:{131,127,147,81,103,23,7,79}
我们先来定一个方法用来判断是否存在
// 基本查找
public static boolean basicSearch(int[] arr,int number){
// 利用基本查找来查找number在数组中是否存在
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number){
return true;
}
}
return false;
}
接着定义一个数组,调用方法查找某个值:
int[] arr = {131,127,147,81,103,23,7,79};
System.out.println(basicSearch(arr,81));
System.out.println(basicSearch(arr,82));
我们来运行看一下:
是不是81在就返回一个true,而82不在,直接给你返回一个false呀!
那我们想要返回对应的索引怎么办呢?其实也很简单:
// 查找对应的索引
public static int basicSearch1(int[] arr,int number){
// 利用基本查找来查找number在数组中是否存在
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number){
return i;
}
}
return -1;
}
怎么样,基本查找是不是比较简单呀!我们接着来学习下一个吧。
二分查找
二分查找也称折半查找。
-
前提条件:数组中的数据必须是有序的。
-
核心逻辑:每次排除一半的查找范围。
我们来看一下这张图片,可以定义一个min表示0索引,max表示最大的索引,而二分查找就是将最大索引加上最小索引除2来求出mid范围。拿着中间的那个值和79比较,发现79在左边,那这个时候就可以把右边给忽略了:
这个时候min索引是不变的,max索引所指的就发生变化了,接着还是拿最大索引加上最小索引除2来求出mid范围,这个时候就发现79是在右边,那这个时候max就不变了,把min往右边移:
这个时候在拿最大索引加上最小索引除2来求出mid范围,是不是就找到了79了呀!
- 核心:
- min和max表示要查找的范围。
- mid是在min和max中间的。
- 如果要查找元素在mid的左边,缩小范围时,min不变,max等于mid减1.
- 如果要查找元素在mid的右边,缩小范围时,max不变,min等于mid加1.
下面我们也来实操一下吧:
需求:定义一个方法利用基本查找,查询某个元素是否存在。
数据如下:{7,23,79,81,103,127,131,147}
先来定义一个方法吧:
// 二分查找
public static int binarySearch(int[] arr,int number){
// 1.定义两个变量记录要查找的范围
int min = 0;
int max = arr.length -1;
// 2.利用循环不断去找要查找的数据
while (true){
if(min > max){
return -1;
}
// 3.找到min和max的中间位置
int mid = (min + max) / 2;
// 4.拿着mid指向的元素跟要查找的元素进行比较
if(arr[mid] > number){
// 4.1 num在mid的左边 min不变,max = mid -1
max = mid -1;
}else if(arr[mid] < number){
// 4.2 num在mid的右边 max不变,min = mid +1
min = mid + 1;
}else{
// 4.3 num跟mid指向的元素一样 返回索引
return mid;
}
}
}
接着定义一个数组,调用方法查找某个值:
int[] arr = {7,23,79,81,103,127,131,147};
System.out.println(binarySearch(arr, 127));
System.out.println(binarySearch(arr, 150));
127找到了,直接返回了索引,而150不存在,所有直接返回一个-1。到这里二分查找就学习完毕啦。我们下面来做小结吧:
- 小结:
- 二分查找的优势:
- 提高查找的效率
- 二分查找的前提条件:
- 数据必须是有序的
- 二分查找的过程:
- min和max表示要查找的范围
- mid是在min和max中间的
- 如果要查找元素在mid的左边,缩小范围时,min不变,max等于mid减1
- 如果要查找元素在mid的右边,缩小范围时,max不变,min等于mid加1
分块查找
- 分块原则1:前一块中的最大数据,小于后一块中所有的数据 (块内无序,块间有序)
- 分块原则2:块数数量一般等于数字的个数开根号。比如16个数字一般分为4块左右
- 核心思路:先确定要查找的元素在哪一块,然后在块内挨个查找。
什么意思呢?我们来看一下:
是不是每一块的最小值大于前一块的数据呀。那怎么实现呢?我们来看一下分块查找的实现步骤:
- 实现步骤:
- 1.
创建数组存放每一块对象信息
。 - 2.
先查找数组确定要查找的数据属于哪一块
。 - 3.
在单独遍历这一块数据即可
- 1.
下面我们来看个案例吧:
现在有这么一个数组,完成分块:int[] arr = {16,5,9,12,21,18, 32,23,37,26,45,34,50,48,61,52,73,66};
我们是不是要对数组先进行分块呀:
// 1.要把数据进行分块
int[] arr = {16,5,9,12,21,18,
32,23,37,26,45,34,
50,48,61,52,73,66};
我们先来定义一个类:
//2.定义一个类
class Block{
private int max; // 最大值
private int startIndex; // 启始索引
private int endIndex; // 结束索引
}
接着创建3个块的对象:
// 3.创建3个块的对象
Block b1 = new Block(21,0,5); // 21最大数字 0表示开始索引 5表示结束索引
Block b2 = new Block(45,6,11); // 45最大数字 6表示开始索引 11表示结束索引
Block b3 = new Block(73,12,17); // 73最大数字 12表示开始索引 17表示结束索引
定义索引表用来管理三个块的对象
Block[] blockArr = {b1,b2,b3};
接着定义一个变量表示要查找的元素
// 5.定义一个变量表示要查找的元素
int number = 23;
int number1 = 30;
利用分块查找的原理,查询number的索引
// 利用分块查找的原理,查询number的索引
private static int getIndex(Block[] blockArr, int[] arr, int number) {
// 1.确定number是在哪一块当中
int indexBlock = findIndexBlock(blockArr, number);
if (indexBlock == -1) {
// 表示number不在数组当中
return -1;
}
// 2.获取这一块的起始索引和结束索引
int startIndex = blockArr[indexBlock].getStartIndex();
int endIndex = blockArr[indexBlock].getEndIndex();
// 3.遍历
for (int i = startIndex; i < endIndex; i++) {
if (arr[i] == number) {
return i;
}
}
return -1;
}
这里就将查询number索引单独写一个方法,定义一个方法用来确定number在哪一块当中
// 定义一个方法用来确定number在哪一块当中
private static int findIndexBlock(Block[] blockArr, int number) {
// 从0索引开始遍历blockArr,如果number小于max,那么就表示number是在这一块当中的
for (int i = 0; i < blockArr.length; i++) {
if (number <= blockArr[i].getMax()) {
return i;
}
}
return -1;
}
调用方法,传递索引表,数组,要查找的元素
// 6.调用方法,传递索引表,数组,要查找的元素
int index = getIndex(blockArr, arr, number);
int index1 = getIndex(blockArr, arr, number1);
System.out.println(number + "的索引为:" + index);
System.out.println(number1 + "的索引为:" + index1);
我们来运行看一下:
是不是也能获取到呀,如果没有元素的话就直接返回-1。分块查找这部分是比较难得,我们来看一下完整代码吧:
package Search;
public class Searchdemo3 {
public static void main(String[] args) {
// 1.要把数据进行分块
int[] arr = {16, 5, 9, 12, 21, 18,
32, 23, 37, 26, 45, 34,
50, 48, 61, 52, 73, 66};
// 3.创建3个块的对象
Block b1 = new Block(21, 0, 5); // 21最大数字 0表示开始索引 5表示结束索引
Block b2 = new Block(45, 6, 11); // 45最大数字 6表示开始索引 11表示结束索引
Block b3 = new Block(73, 12, 17); // 73最大数字 12表示开始索引 17表示结束索引
// 4.定义数组用来管理三个块的对象(索引表)
Block[] blockArr = {b1, b2, b3};
// 5.定义一个变量表示要查找的元素
int number = 23;
int number1 = 30;
// 6.调用方法,传递索引表,数组,要查找的元素
int index = getIndex(blockArr, arr, number);
int index1 = getIndex(blockArr, arr, number1);
System.out.println(number + "的索引为:" + index);
System.out.println(number1 + "的索引为:" + index1);
}
// 利用分块查找的原理,查询number的索引
private static int getIndex(Block[] blockArr, int[] arr, int number) {
// 1.确定number是在哪一块当中
int indexBlock = findIndexBlock(blockArr, number);
if (indexBlock == -1) {
// 表示number不在数组当中
return -1;
}
// 2.获取这一块的起始索引和结束索引
int startIndex = blockArr[indexBlock].getStartIndex();
int endIndex = blockArr[indexBlock].getEndIndex();
// 3.遍历
for (int i = startIndex; i < endIndex; i++) {
if (arr[i] == number) {
return i;
}
}
return -1;
}
// 定义一个方法用来确定number在哪一块当中
private static int findIndexBlock(Block[] blockArr, int number) {
// 从0索引开始遍历blockArr,如果number小于max,那么就表示number是在这一块当中的
for (int i = 0; i < blockArr.length; i++) {
if (number <= blockArr[i].getMax()) {
return i;
}
}
return -1;
}
}
//2.定义一个类
class Block {
private int max; // 最大值
private int startIndex; // 启始索引
private int endIndex; // 结束索引
public Block() {
}
public Block(int max, int startIndex, int endIndex) {
this.max = max;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
/**
* 获取
*
* @return max
*/
public int getMax() {
return max;
}
/**
* 设置
*
* @param max
*/
public void setMax(int max) {
this.max = max;
}
/**
* 获取
*
* @return startIndex
*/
public int getStartIndex() {
return startIndex;
}
/**
* 设置
*
* @param startIndex
*/
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
/**
* 获取
*
* @return endIndex
*/
public int getEndIndex() {
return endIndex;
}
/**
* 设置
*
* @param endIndex
*/
public void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
public String toString() {
return "Block{max = " + max + ", startIndex = " + startIndex + ", endIndex = " + endIndex + "}";
}
}
到这里基本的三种查找方式就学习完毕啦,我们下章节继续学习排序会更有意思哟,好啦有什么不懂的可以一起在评论区评论探讨,我们下期不见不散!!!
==最后非常感谢您的阅读,也希望能得到您的反馈 ==