一、顺序(线性)查找
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;
}
}