Skip to content

Latest commit

 

History

History
204 lines (187 loc) · 4.76 KB

BinarySearch.md

File metadata and controls

204 lines (187 loc) · 4.76 KB
package com.test.xiaolu;

/**
 * 公众号:「一个不甘平凡的码农 」
 * 二分查找
 * @author 小鹿
 *
 */
public class TwoFind {

	/**
	 * 思路:
	 * 1、在数组头、尾定义两个指针(low,height)
	 * 2、取中间数值mid
	 * 3、判断是否为查找值
	 * 4、如果不是,移动 mid 指针,变化low,height
	 * @param args
	 */
	public static void main(String[] args) {
		int[] a = {3,4,6,7,10};
		TwoFind tFind = new TwoFind();
		System.out.print("该数据的下标为:"+tFind.find4(a,5,5));
	}
	
	/**
	 * 功能:最简单的二分查找
	 * @param a 数组
	 * @param n 数组长度
	 * @param value 要查找的值
	 */
	public int simpleFind(int[] a,int n, int value) {
		int low = 0;
		int high = n - 1;
		
		// 当两个指针同时指向一个数据时,必须用 <=
		while(low <= high) {
			//注意:两者之和可能会溢出
			//改进: low + (high - low)/2 或 low + ((high - low)>>2)
			int mid = low + (high - low)/2;
			if(a[mid] == value) {
				return mid;
			}else if(a[mid] < value) {
				// 如果不 + 或 - 会发生死循环
				low = mid + 1;
			}else {
				high = mid - 1;
			}
		}
		return -1;
	}
	
	/**
	 * 功能:递归实现最简单的二分查找
	 * @param a 数据
	 * @param low 初始位置
	 * @param height 终止位置
	 * @param value 查找的值
	 * @return 
	 */
	public int recursionTwoFind(int[] a,int low,int high,int value) {
		//终止条件
		if(low > high) return -1;
		
		//计算中间结点
		int mid = low + (high-low)/2;
		
		//进行递归
		if(a[mid] == value) {
			return mid;
		}else if(a[mid] < value){
			return recursionTwoFind(a, mid + 1, high, value);
		}else {
			return recursionTwoFind(a, low, mid - 1, value);
		}
	}
	
	/**
	 * 变体一:查找第一个值等于给定值的元素
	 * @param a 数组
	 * @param n 数组的长度
	 * @param value 超找的值
	 * @return 该元素的数组下标
	 */
	public int find1(int[] a, int n, int value) {
		int low = 0;
		int high = n - 1;
		
		// 当两个指针同时指向一个数据时,必须用 <=
		while(low <= high) {
			//注意:两者之和可能会溢出
			//改进: low + (high - low)/2 或 low + ((high - low)>>2)
			int mid = low + (high - low)/2;
			if(a[mid] == value) {
				// 找出重复元素中第一个元素
				if(mid == 0 || a[mid - 1] != value) {
					return mid;
				}else {
					high = mid - 1;
				}
			}else if(a[mid] < value) {
				// 如果不 + 或 - 会发生死循环
				low = mid + 1;
			}else {
				high = mid - 1;
			}
		}
		return -1;
	}
	
	/**
	 * 变体二:查找最后一个值等于给定值的元素
	 * @param a 数组
	 * @param n 数组的长度
	 * @param value 超找的值
	 * @return 该元素的数组下标
	 */
	public int find2(int[] a, int n, int value) {
		int low = 0;
		int high = n - 1;
		
		// 当两个指针同时指向一个数据时,必须用 <=
		while(low <= high) {
			//注意:两者之和可能会溢出
			//改进: low + (high - low)/2 或 low + ((high - low)>>2)
			int mid = low + (high - low)/2;
			if(a[mid] == value) {
				// 找出重复元素中第一个元素
				if(mid == n - 1 || a[mid + 1] != value) {
					return mid;
				}else {
					low = mid + 1;
				}
			}else if(a[mid] < value) {
				// 如果不 + 或 - 会发生死循环
				low = mid + 1;
			}else {
				high = mid - 1;
			}
		}
		return -1;
	}
	
	/**
	 * 变体三:查找第一个大于等于给定值的元素
	 * @param a 数组
	 * @param n 数组的长度
	 * @param value 数组的值
	 * @return 
	 */
	public int find3(int[] a, int n, int value) {
		int low = 0;
		int high = n - 1;
		
		// 当两个指针同时指向一个数据时,必须用 <=
		while(low <= high) {
			// 注意:两者之和可能会溢出
			// 改进: low + (high - low)/2 或 low + ((high - low)>>2)
			int mid = low + (high - low)/2;
			if(a[mid] >= value) {
				if((mid == 0) || (a[mid - 1] < value )) {
					return mid;
				}else {
					high = mid - 1;
				}
			}else {
				low = mid + 1;
			}
		}
		return -1;
	}
	
	/**
	 * 变体四:查找第一个小于等于给定值的元素
	 * @param a 数组
	 * @param n 数组的长度
	 * @param value 数组的值
	 * @return 
	 */
	public int find4(int[] a, int n, int value) {
		int low = 0;
		int high = n - 1;
		
		// 当两个指针同时指向一个数据时,必须用 <=
		while(low <= high) {
			// 注意:两者之和可能会溢出
			// 改进: low + (high - low)/2 或 low + ((high - low)>>2)
			int mid = low + (high - low)/2;
			if(a[mid] <= value) {
				if((mid == n-1) || (a[mid + 1] > value )) {
					return mid;
				}else {
					low = mid + 1;
				}
			}else {
				high = mid - 1;
			}
		}
		return -1;
	}
}