Java数据结构与算法(六)——查找算法

一、顺序(线性)查找

package SearchSort;

public class SeqSearch {

	public static void main(String[] args) {
		int arr[] = { 1, 9, 11, -1, 34, 89 };
		int index = seqSearch(arr, 34);
		if (index == -1) {
			System.out.println("没有找到");
		}else {
			System.out.println(arr[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;
	}
}

二、二分查找

package SearchSort;

import java.util.ArrayList;

public class BinarySearch {
	//使用二分查找的前提是数组是有序的
	public static void main(String[] args) {

		int[] arr = { 1, 8, 10, 89, 1000, 1234 };
		int index = binarySearch(arr, 0, arr.length-1, 88);
		System.out.println(index);
		
		int[] arr1 = { 1, 8, 10, 89, 1000, 1000, 1000, 1000, 1234 };
		ArrayList<Integer> index1 = binarySearch2(arr1, 0, arr.length-1, 1000);
		System.out.println(index1);

	}

	//二分查找算法
	/**
	 * 
	 * @param arr
	 * @param left 左指针
	 * @param right 右指针
	 * @param findVal 需要找的值
	 * @return 返回查找到的下标值,如果没有就返回-1
	 */
	public static int binarySearch(int[] arr, int left, int right, int findVal) {

		//递归退出的条件
		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);  //因为向左向右递归是mid+1所以当找不到数时,会出现left>right的情况
		}else {
			return mid;
		}
		
	}
	
	
	//当数组中有多个相同的值时,查找出全部相同的值
	//思路分析
	//1.在找到mid索引值时不要马上返回
	//2.分别向mid索引值左右扫描,将所有符合的值加入到ArrayList中
	//3.将ArrayList返回
	public static ArrayList<Integer> binarySearch2(int[] arr, int left, int right, int findVal) {

		//递归退出的条件
		if (left > right) {
			return new ArrayList<Integer>(); //返回空的ArrayList,通过他的size来判断
		}
		
		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);  //因为向左向右递归是mid+1所以当找不到数时,会出现left>right的情况
		}else {
			
			ArrayList<Integer> arrayList = new ArrayList<Integer>();
			
			arrayList.add(mid);
			
			int temp = mid - 1; //向左扫描的指针
			while (true) {
				if (temp < 0 || arr[temp] != findVal) { //如果temp<0说明左边已经找完,如果arr[temp] != findVal说明当前值不是要找的,结束循环,继续左移
					break;
				}else { //否则就将remp所指的值放入arrayList中
					arrayList.add(temp);
					temp--; //temp左移
				}
			}
			
			temp = mid + 1; //向右扫描的指针
			while (true) {
				if (temp > arr.length - 1  || arr[temp] != findVal) { //如果temp>0说明右边已经找完,如果arr[temp] != findVal说明当前值不是要找的,结束循环,继续右移
					break;
				}else {
					//否则就将remp所指的值放入arrayList中
					arrayList.add(temp);
					temp++; //temp右移
				}
			}
			return arrayList;
		}
	
	}
	
}

三、插值查找

package SortAlgorithm;

import java.util.Arrays;



public class InsertValueSearch {

	public static void main(String[] args) {

		int[] arr = new int[100];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = i;
		}
//		System.out.println(Arrays.toString(arr));
		
		
		int index = insertValueSearch(arr, 0, arr.length - 1, 1);
		System.out.println(index);

	}
	
	
	//插值查找算法
	public static int insertValueSearch(int[] arr,int left,int right,int findValue) {
		System.out.println("查找次数");
		//注意findValue < arr[0] || findValue > arr[arr.length - 1],这两句必须要有
		//首先可以保证查找的值在数组范围内,其次,由于mid的计算需要用到findValue,如果findValue非常大,会导致mid也非常大,造成mid越界
		if (left > right || findValue < arr[0] || findValue > arr[arr.length - 1]) {
			return -1;
		}
		
		//求出mid
		int mid = left + (right - left) * (findValue - arr[left]) / (arr[right] - arr[left]);
		int midValue = arr[mid];
		
		if (findValue > midValue) {
			return insertValueSearch(arr, left, mid - 1, findValue);
		}else if (findValue < midValue) {
			return insertValueSearch(arr, mid + 1, arr.length - 1, findValue);
		}else {
			return mid;
		}
		
	}


}

四、斐波那契查找

package SortAlgorithm;

import java.util.Arrays;

public class FibonacciSearch {

	public static void main(String[] args) {
		
		int[] arr = { 1, 8, 10, 89, 1000, 1234 };
		
//		System.out.println(Arrays.toString(fib()));
		
		int index = fibonacciSearch(arr, 89);
		System.out.println(index);

	}
	
	public static int MaxSize = 20;

	//因为后面会用到斐波那契数列,需要先写一个斐波那契数列
	//非递归的方式完成斐波那契数列
	public static int[] fib() {
		int[] f = new int[MaxSize];
		
		f[0] = 1;
		f[1] = 1;
		for (int i = 2; i < f.length; i++) {
			f[i] = f[i - 1] + f[i - 2];
		}
		return f;
	}
	
	
	//斐波那契查找算法
	//使用非递归的方式
	public static int fibonacciSearch(int[] a, int key) {
		int low = 0;
		int high = a.length - 1;
		int k = 0; //表示斐波那契分割数值的下标
		int mid = 0;
		int[] f = fib(); //获取斐波那契数列
		
		//获取斐波那契分割数值的下标
		//f[k] - 1是需要的最小的可以符合数组的斐波那契值
		while (high > f[k] - 1) {
			k++;
		}
		
		//因为f[k] - 1可能会大于a数组的长度,因此需要用Arrays类,构造一个新的数组,指向a[]
		//不足的部分先暂时使用0填充
		int[] temp = Arrays.copyOf(a, f[k] - 1);
		
		//实际需要使用a数组的最后的数填充temp
		for (int i = high + 1; i < temp.length; i++) {
			temp[i] = a[high];
		}
		
		//使用while循环来处理,找到我们的数key
		while (low <= high) {
			mid = low + f[k - 1] - 1;
			if (key < temp[mid]) { //向左查找
				high = mid - 1;
				//斐波那契数列代表的是待查找数组的下标,也相当于数组的个数
				//为什么是k--
				//全部元素f[k] - 1 = 前面的元素f[k-1]-1 + mid + 后面的元素f[k-2]-1,因为f[k] - 1 = (f[k-1]-1) + (f[k-2]-1) + 1
				//因为前面有f[k-1]-1个元素,所以可以继续拆分,f[k-1] - 1 = (f[(k-1)-1]-1) + (f[(k-1)-2]-1) + 1 = (f[k-2]-1) + (f[k-3]-1) + 1
				//所以为了求下次循环的mid = low + f[k - 2] - 1,以使数组继续循环分割,需要将k-1
				k--;
			}else if (key > temp[mid]) {
				low = mid + 1;
				//为什么是k-2
				//因为后面有f[k-2]-1个元素,所以可以继续拆分,f[k-2] - 1 = (f[(k-2)-1]-1) + (f[(k-2)-2]-1) + 1 = (f[k-3]-1) + (f[k-4]-1) + 1
				//所以为了求下次循环的mid = low + f[k - 3] - 1,以使数组继续循环分割,需要将k-2
				k -= 2;
			}else {//找到
				//需要确定返回的是哪个下标,因为后面有可能填充了一些high
				if (mid <= high) {
					return mid;
				}else {
					return high;
				}
				
			}

		}
		
		return -1;
		
	}
	

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值