四种查找算法代码实现

四种查找算法实现

顺序查找

特点:不需要对序列进行排序

	/**
	 * @param arr 要查找的无序数组	
	 * @param findVal 要查找的值
	 * @return 值在数组的位置下标
	 */	
	public static ArrayList<Integer> seqSearch(int[] arr, int findVal) {
		ArrayList<Integer> sub = new ArrayList<>();
		for (int i = 0; i < arr.length; i++) {
			if (findVal == arr[i]) {
				sub.add(i);
			}
		}
		if (!sub.isEmpty()) {
			return sub;
		} else
			throw new IndexOutOfBoundsException("未找到");
	}

二分查找

特点:针对有序序列,递归

	/*
	 * 二分查找法:针对有序序列
	 * left=right=mid时,不能跳出循环,此时相当于遍历到最边缘的数
	 * 要比较findVal与边缘数的值
	*/	
	/**
	 * @param arr 要查找的有序数组
	 * @param left 该有序数组的左索引
	 * @param right 该有序数组的右索引
	 * @param findVal 要查找的值
	 * @return 值在数组的位置下标
	 */
	public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int findVal) {
		ArrayList<Integer> sub = new ArrayList<Integer>();
		int mid = (left + right) / 2;
		int temp = 0;
		if (left > right) {
			throw new IndexOutOfBoundsException("未找到");
		}
//		递归调用有返回值的方法时,要记得逐层返回值
		if (findVal > arr[mid]) {
//			binarySearch(arr, mid + 1, right, findVal);
			return binarySearch(arr, mid + 1, right, findVal);
		} else if (findVal < arr[mid]) {
//			binarySearch(arr, left, mid - 1, findVal);
			return binarySearch(arr, left, mid - 1, findVal);
		} else {
			temp = mid - 1;
			while (temp >= 0 && arr[temp] == findVal) {
				sub.add(temp);
				temp--;
			}
			sub.add(mid);
			temp = mid + 1;
			while (temp < arr.length && arr[temp] == findVal) {
				sub.add(temp);
				temp++;
			}
			return sub;
		}
	}
插值查找

特点:递归,是二分查找的升级。

思想:基于二分查找算法,将查找点的选择改进为自适应选择,提高查找效率。对于分布比较均匀的有序序列查找比较快。

相较于二分查找,主要改变:

m i d = l e f t + r i g h t − l e f t 2 → m i d = l e f t + f i n d V a l − a r r [ l e f t ] a r r [ r i g h t ] − a r r [ l e f t ] ( r i g h t − l e f t ) . mid=left+\frac {right-left} 2 \rightarrow mid=left+\frac {findVal-arr[left]}{arr[right]-arr[left]}(right-left). mid=left+2rightleftmid=left+arr[right]arr[left]findValarr[left](rightleft).


	/*
	 * 插值查找法:针对有序序列
	 */
	/**
	 * @param arr     要查找的有序数组
	 * @param left    该有序数组的左索引
	 * @param right   该有序数组的右索引
	 * @param findVal 要查找的值
	 * @return 值在数组的位置下标
	 */
	public static ArrayList<Integer> insertValueSearch(int[] arr, int left, int right, int findVal) {
		ArrayList<Integer> sub = new ArrayList<Integer>();
		if (left > right || findVal < arr[left] || findVal > arr[right]) {
			throw new IndexOutOfBoundsException("未找到");
		}
		int temp = 0;
		int mid = left + (findVal - arr[left]) / (arr[right] - arr[left]) * (right - left);
		System.out.println("~~");
//		递归调用有返回值的方法时,要记得逐层返回值
		if (findVal > arr[mid]) {
			return insertValueSearch(arr, mid + 1, right, findVal);
		} else if (findVal < arr[mid]) {
			return insertValueSearch(arr, left, mid - 1, findVal);
		} else {
			temp = mid - 1;
			while (temp >= 0 && arr[temp] == findVal) {
				sub.add(temp);
				temp--;
			}
			sub.add(mid);
			temp = mid + 1;
			while (temp < arr.length && arr[temp] == findVal) {
				sub.add(temp);
				temp++;
			}
			return sub;
		}

	}
斐波那契查找

特点:是二分查找的升级。

思想:运用黄金比例的概念在有序数列中选择查找点进行查找,提高查找效率。

  • 相较于二分查找,主要改变:

m i d = l e f t + r i g h t − l e f t 2 → m i d = l e f t + f i b ( k − 1 ) − 1. mid=left+ \frac{right-left}2 \rightarrow mid=left+fib(k-1)-1. mid=left+2rightleftmid=left+fib(k1)1.

其中 f i b ( k − 1 ) fib(k-1) fib(k1)为 fibnoacci 数列,当 k → ∞ k \rightarrow \infty k时, f i b ( k − 1 ) f i b ( k ) \frac {fib(k-1)}{fib(k)} fib(k)fib(k1) 满足黄金分割比例 ≈ 0.618. \approx 0.618. 0.618.

  • 采用 f i b ( k ) − 1 = f i b ( k − 1 ) − 1 + f i b ( k − 2 ) − 1 + 1 fib(k)-1=fib(k-1)-1+fib(k-2)-1+1 fib(k)1=fib(k1)1+fib(k2)1+1代替传统 f i b ( k ) = f i b ( k − 1 ) + f i b ( k − 2 ) fib(k)=fib(k-1)+fib(k-2) fib(k)=fib(k1)+fib(k2)的原因:

为了便于将长度为 f i b ( k ) − 1 fib(k)-1 fib(k)1的有序数列划分为 f i b ( k − 1 ) − 1 , m i d , f i b ( k − 2 ) − 1 fib(k-1)-1,mid,fib(k-2)-1 fib(k1)1,mid,fib(k2)1三部分。

//	生成fibnoacci数列,k>=0
	public static int[] fibonacci(int k) {
		int[] fib = new int[k + 1];
		fib[0] = 1;
		if (k > 0) {
			fib[1] = 1;
			for (int i = 2; i <= k; i++) {
				fib[i] = fib[i - 1] + fib[i - 2];
			}
		}
		return fib;
	}
	/*
	 * fibnoacci查找  对有序序列采用非递归方法
	 * 每次循环都更新左、右、中索引(left,right,mid), 
	 * 直至找到findVal或者超出索引才退出循环
	 */
	/**
	 * @param arr 要查找的有序序列
	 * @param findVal	要查找的值
	 * @return	要查找的值在有序序列的位置下标
	 */
	public static ArrayList<Integer> fibonacciSearch(int[] arr, int findVal) {
		int left = 0, right = arr.length - 1;
		if (findVal < arr[left] || findVal > arr[right]) {
			throw new IndexOutOfBoundsException("未找到");
		}
		ArrayList<Integer> sub = new ArrayList<>();
		int k = 0;
		int[] fib = fibonacci(k);
//		确定fibnoacci最大值与待查找数组的长度
		while (fib[k] < arr.length) {
			k++;
			fib = fibonacci(k);
		}
//		将数组补充长度至fib[k],防止起初mid跳到原数组外,补充值为arr的最大值
		int[] a = Arrays.copyOf(arr, fib[k]);
		for (int i = arr.length; i < a.length; i++) {
			a[i] = arr[arr.length - 1];
		}
		int mid = 0, temp = 0;
		while (true) {
			if (left > right || k < 1) {
				throw new IndexOutOfBoundsException("超出索引");
			}
			mid = left + fib[k - 1] - 1;
			if (findVal < a[mid]) {
				right = mid - 1;
				k--;
			} else if (findVal > a[mid]) {
				left = mid + 1;
				k -= 2;
			} else {
				if (mid < right) {
					temp = mid - 1;
					while (temp >= 0 && a[temp] == findVal) {
						sub.add(temp);
						temp--;
					}
					sub.add(mid);
					temp = mid + 1;
					while (temp < arr.length && a[temp] == findVal) {
						sub.add(temp);
						temp++;
					}
				} else {
//		当找到值但在原数组外,说明为最大值,则返回最大值在原数组的下标
					temp = right - 1;
					while (temp >= 0 && a[temp] == findVal) {
						sub.add(temp);
						temp--;
					}
					sub.add(right);
				}
				return sub;
			}
		}
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值