Java数据结构与算法

目录

查找算法

介绍

顺序(线性)查找

代码实现

 二分查找算法

案例

思路

代码实现

运行结果

 课后思考题

  代码实现

运行效果

 插值算法工作原理

 举例说明

代码实现

注意事项


查找算法

介绍

在Java中,我们常用的查找有四种:

1)顺序(线性)查找

2)二分查找/折半查找

3)插值查找

4)斐波那契查找

顺序(线性)查找

代码实现

package search;

public class SeqSearch {

	public static void main(String[] args) {
		int arr[]={1,9,11,-1,34,89};//没有顺序的数组
		int index=seqSearch(arr, 11);
		if (index==-1) {
			System.out.println("没有找到");
		}else {
			System.out.println("找到,下标为="+index);
		}
	}
	/*这里我们实现的线性查找是找到一个满足条件的值,就返回*/
	public static int seqSearch(int[] arr,int value) {
		//线性查找是逐一比对,发现有相同值,就返回下标
		for (int i = 0; i < arr.length; i++) {
			if (arr[i]==value) {
				return i;
			}
		}
		return -1;
	}
}

 二分查找算法

案例

请对一个有序数组进行二分查找{1,8,10,89,1000,1234},输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。

思路

1.首先确定该数组的中间的下标

mid=(left+right)/2

2.然后让需要查找的数findVal和arr[mid]比较

2.1findVal>arr[mid],说明你要查找的数在mid的右边,因此需要递归的向右查找

2.2findVal<arr[mid],说明你要查找的数在mid的左边,因此需要递归的向左查找

2.3findVal==arr[mid],说明找到,就返回

//什么时候我们需要结束递归

1)找到就结束递归

2)递归完整个数组,仍然没有找到findVal,也需要结束递归当left>right就需要退出

代码实现

package search;

//注意:使用二分查找的前提是该数组是有序的
public class BinarySearch {

	public static void main(String[] args) {
		int arr[]= {1,8,10,89,1000,1234};
		
		int resIndex=binarySearch(arr,0,arr.length-1, 1234);
		System.out.println("resIndex="+resIndex);
	}
	//二分查找算法
	/* arr 数组
	 * left 左边的索引 
	 * right 右边的索引
	 * findVal 要查找的值
	 * 如果找到就返回下标,如果没有找到,就返回-1
	 * */
	public static int binarySearch(int[] arr,int left,int right,int findVal) {
		
		//当left>right时,说明递归整个数组,但是没有找到
		if (left>right) {
			return -1;
		}
		int mid=(left+right)/2;
		int midVal=arr[mid];
		
		if (findVal>midVal) {//向右递归
			return binarySearch(arr, mid+1, right, findVal);		
		}else if (findVal<midVal) {//向左递归
			return binarySearch(arr, left, mid-1, findVal);
		}else {
			return mid;
		}
	}
}

运行结果

 课后思考题

{1,8,10,89,1000,1000,1234}当一个有序数组中,
有多个相同的数值时,如何将所有的数值都查找到,比如这里的1000


  代码实现

package search;

import java.awt.image.RescaleOp;
import java.util.ArrayList;
import java.util.List;

//注意:使用二分查找的前提是该数组是有序的
public class BinarySearch {

	public static void main(String[] args) {
		int arr[]= {1,8,10,89,1000,1000,1234};
		
//		int resIndex=binarySearch(arr,0,arr.length-1, 1234);
//		System.out.println("resIndex="+resIndex);
		
		List<Integer> resIndexList=binarySearch2(arr, 0,arr.length-1,1000);
		System.out.println("resIndexList="+resIndexList);
	}
	//二分查找算法
	/* arr 数组
	 * left 左边的索引 
	 * right 右边的索引
	 * findVal 要查找的值
	 * 如果找到就返回下标,如果没有找到,就返回-1
	 * */
	public static int binarySearch(int[] arr,int left,int right,int findVal) {
		
		//当left>right时,说明递归整个数组,但是没有找到
		if (left>right) {
			return -1;
		}
		int mid=(left+right)/2;
		int midVal=arr[mid];
		
		if (findVal>midVal) {//向右递归
			return binarySearch(arr, mid+1, right, findVal);		
		}else if (findVal<midVal) {//向左递归
			return binarySearch(arr, left, mid-1, findVal);
		}else {
			return mid;
		}
	}
	//完成一个课后思考题:
	/*
	 * 课后思考题:{1,8,10,89,1000,1000,1234}当一个有序数组中,
	 * 有多个相同的数值时,如何将所有的数值都查找到,比如这里的1000
	 *
	 *思路分析:
	 *1.在找到mid值,不要马上返回
	 *2.向mid索引值的左边扫描,将所有满足1000的元素的下标,加入到集合ArrayList
	 *3.向mid索引值的右边扫描,将所有满足1000的元素的下标,加入到集合ArrayList
	 *4.将Arraylist返回
	 */
public static List binarySearch2(int[] arr,int left,int right,int findVal) {
		
		//当left>right时,说明递归整个数组,但是没有找到
		if (left>right) {
			return new ArrayList<Integer>();
		}
		int mid=(left+right)/2;
		int midVal=arr[mid];
		
		if (findVal>midVal) {//向右递归
			return binarySearch2(arr, mid+1, right, findVal);		
		}else if (findVal<midVal) {//向左递归
			return binarySearch2(arr, left, mid-1, findVal);
		}else {
//			思路分析:
//				 *1.在找到mid值,不要马上返回
//				 *2.向mid索引值的左边扫描,将所有满足1000的元素的下标,加入到集合ArrayList
//				 *3.向mid索引值的右边扫描,将所有满足1000的元素的下标,加入到集合ArrayList
//				 *4.将Arraylist返回
			List<Integer> resIndexList=new ArrayList<Integer>();
			//向mid索引值的左边扫描,将所有满足1000的元素的下标,加入到集合ArrayList
			int temp=mid-1;
			while (true) {
				if (temp<0||arr[temp]!=findVal) {//退出
					break;
				}
				//否则,就temp放入到resIndexlist
				resIndexList.add(temp);
				temp-=1;//temp左移		
			}
			resIndexList.add(mid);
			
			//向mid索引值的右边扫描,将所有满足1000的元素的下标,加入到集合ArrayList
			temp=mid-1;
			while (true) {
				if (temp>arr.length-1||arr[temp]!=findVal) {//退出
					break;
				}
				//否则,就temp放入到resIndexlist
				resIndexList.add(temp);
				temp+=1;//temp右移		
			}
			return resIndexList;
		}
	}
}

运行效果

 插值算法工作原理

1)插值查找算法类似于二分查找,不同的是插值查找每次自适应mid处开始查找

2)将折半查找中的求mid索引的公式,low表示左边索引left,high表示右边索引right.

key就是前面将的findVal

3)int midIndex=low+(high-low)*(key-arr[low])/arr[high]-arr[low]);//插值索引

对应前面的代码公式:

int mid=left+(right-left)*(findVal-arr[left])/(arr[right]-arr[left]

4)举例说明插值算法1-100的数组

 举例说明

数组arr={1,2,3,...,100}

假如我们需要查找的值1

使用二分查找的话,我们需要多次递归,才能找到1

使用插值查找算法

int mid=left+(right-left)*(findVal-arr[left])/(arr[right]-arr[left]

int mid=0+(99-0)*(1-1)/(100-1)=0+99*0/99=0

比如我们查找的值100

int mid=0+(99-0)*(100-1)/(100-1)=0+99*99/99=0+99=99

代码实现

package search;

import java.util.Arrays;

public class InsertValueSearch {

	public static void main(String[] args) {
		
		int [] arr=new int[100];
		for (int i = 1; i <= 100; i++) {
			arr[i]=i+1;
		}
		int index=insertValueSearch(arr, 0, arr.length-1,78);
		System.out.println("index="+index);
		//System.out.println(Arrays.toString(arr));
	}
	//编写插值查找算法
	/*
	 * arr 数组
	 * left 左边索引
	 * right 右边索引
	 * findVal 查找值
	 * 如果找到,就返回对应的下标,如果没有找到,返回-1
	 */
	public static int insertValueSearch(int [] arr,int left,int right,int findVal) {
		
		System.out.println("二分查找被调用~~~");
		//注意:findVal<arr[0]和findVal>arr.length-1必须需要
		//否则我们得到的mid可能越界
		if (left>right||findVal<arr[0]||findVal>arr.length-1) {
			return -1;
		}
		//求出mid
		int mid=left+(right-left)*(findVal-arr[left]/(arr[right]-arr[left]));
		int midVal=arr[mid];
		if (findVal>midVal) {//说明应该向右边递归
			return insertValueSearch(arr,mid+1, right, findVal);
			
		}else if (findVal<midVal) {//说明应该向边左递归
			return insertValueSearch(arr, left,mid-1, findVal);		
		}else {
			return mid;
		}
	}
}

注意事项

1)对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度较快。

2)关键字分布不均匀的情况下,该方法不一定比折半查找要好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值