1.顺序查找
思想很简单,直接存代码
public class SeqSearch {
public static void main(String[] args) {
int[] arr = {
10,8,78,56,32,47};
System.out.println("下标值为:"+seq(arr,56));
}
public static int seq(int[] arr, int value) {
for(int i = 0; i < arr.length; ++i) {
if(arr[i] == value) {
return i;
}
}
return -1;
}
}
2.二分查找
也叫折半查找,前提是排好序的数组,先找中间值,如果待查找的数比中间值小,就往数组的左边去找,反之去右边继续查找
代码:
public class BinarySearch {
public static void main(String[] args) {
//int[] arr = { 1, 8, 10, 89, 1000, 1234 };
int[] arr = new int[100];
for(int i = 0; i < arr.length; ++i) {
arr[i] = i+1;
}
System.out.println(binary(arr, 0, arr.length - 1, 37));
}
public static int binary(int[] arr, int left, int right, int value) {
System.out.println("查找");
if(left > right) {
return -1;
}
int mid = (left + right) / 2;
if(value > arr[mid]) {
//右递归查找
return binary(arr, mid + 1, right, value);
} else if(value < arr[mid]) {
//左递归查找
return binary(arr, left, mid - 1, value);
} else {
return mid;
}
}
}
二分查找拓展:
新需求:当待查找的数有多个相同数值时,希望能找出所有的值
思路:借助一个数组,当找到这个mid值时不慎立即返回 ,而是利用循环判断mid左右值是否也相同,相同就将该下标放进数组,最后返回该数组即可。
代码如下:
import java.util.ArrayList;
public class BinarySearch_2 {
public static void main(String[] args) {
//新需求:int[] arr = { 1, 8, 10, 89, 1000,1000, 1000, 1234 };
//当待查找的数有多个相同数值时,希望能找出所有的值
/*
* 思路:在找到mid的时候不要立即返回
* 2.向mid索引值的左边扫描,将所有满足1000的元素下标加入到集合ArrayList中
* 3.向mid索引值的右边扫描,将所有满足1000的元素下标加入到集合ArrayList中
* 4.将ArrayList返回
*/
int[] arr = {
1, 8, 10, 89, 1000, 1000, 1000, 1000, 1234 };
ArrayList<Integer> li = binary_2(arr, 0, arr.length, 1000);
System.out.println(li.toString());
}
public static ArrayList<Integer> binary_2(int[] arr, int left, int right, int value) {
int mid = (right - left) / 2 + left;//防止数据过大,溢出
ArrayList<Integer> li = new ArrayList<Integer>();
if(left > right) {
return null;
}
if(value > arr[mid]) {
return binary_2(arr, mid + 1, right, value);
} else if(value < arr[mid]) {
return binary_2(arr, left, mid - 1, value);
} else {
// 2.向mid索引值的左边扫描,将所有满足1000的元素下标加入到集合ArrayList中
int temp = mid - 1;
while(true) {
if(temp < 0 || arr[temp] != arr[mid])
break;
//将temp加入到li
li.add(temp);
temp -= 1;
}
li.add(mid);
//3.向mid索引值的右边扫描,将所有满足1000的元素下标加入到集合ArrayList中
temp = mid + 1;
while(true) {
if(temp > arr.length - 1 || arr[temp] != arr[mid]) {
break;
}
li.add(temp);
temp += 1;
}
return li;
}
}
}
3.插值查找
与二分查找类似,对mid的定义不同,可详见代码中对mid的设定
int mid = left + (right - left) * ((value - arr[left]) / (arr[right] - arr[left]));
注意事项:A.对数据量较大,关键字(即数组中的各个值)分布比较均匀的查找来说,采用插值查找速度较快。没什么难点,把mid值的公式记住就行了
内联代码片
public class InsertSearch {
public static void main(String[] args) {
int[] arr = new int[100];
for(int i = 0; i < arr.length; ++i) {
arr[i] = i+1;
}
int index = insert(arr, 0, arr.length - 1, 37);
System.out.println(index);
}
/**
* @param arr 数组
* @param left 最左边值的下标
* @param right 最右边值的下标
* @param value 待查找的值
* @return 找到返回待查找值的下标,找不到返回-1
*/
public static int insert(int[] arr, int left, int right, int value) {
System.out.println("查找");
int mid = left + (right - left) * ((value - arr[left]) / (arr[right] - arr[left]));
if(left > right) {
return -1;
}
if(value > arr[mid]) {
return insert(arr, mid + 1, right, value);
} else if(value < arr[mid]) {
return insert(arr, left, mid - 1, value);
} else
return mid;
}
}
4.斐波拉契查找
看了两遍视频都是蒙圈的,现在也有点迷糊。
大致实现思路:类似黄金分割比,斐波拉契数列也可分割成一个黄金比例。
依旧是改变mid的值,但此处对我来说有点难以理解。
注意点:
1.先给斐波拉契设置一个长度,不能比你要查得数组短。
2.当待查找的数组长度小于斐波拉契数列的长度时要将数组长度补全的和斐波拉契数列长度一致,填充的数在最后填充,且必须和最大值相同。
内联代码片
import java.util.Arrays;
public class FibonacciSearch {
public static int MaxSize = 10;
public static void main(String[] args) {
int[] arr = {
1, 8, 10, 89, 1000, 1234};
System.out.println(fibonacci(arr, 89));
}
//因为后面mid = low + F[k - 1] - 1,需要使用到斐波拉契数列,此处先获取一个斐波拉契数列
public static int[] fib() {
//非递归
int[] f = new int[MaxSize];
f[0] = 1;
f[1] = 1;
for(int i = 2; i < MaxSize; ++i) {
f[i] = f[i-1] + f[i-2];
}
return f;
}
//编写斐波拉契查找算法,非递归
public static int fibonacci(int[] a, int value) {
int left = 0;
int right = a.length - 1;
int k = 0; //表示斐波拉契分割数值的下标
int mid = 0;//存放mid值
int[] F = fib();//获取斐波拉数列
for (int i : F) {
System.out.print(i+" ");
}
//获取到斐波拉契分割数 值的下标
while( a.length - 1 > F[k] - 1) {
k++;
}
//因为f[k]值可能大于a的长度,因此我们需要使用Arrays类,构造一个新的数组,并指向a
int[] temp = Arrays.copyOf(a, F[k]);
//不足的部分会使用0填充
//但是不能用填充,因为数是排好序的,所以此处用a数组最后的数填充temp
for(int i = right + 1; i< temp.length; ++i) {
temp[i] = a[right];
}
//循环查找k,
while(left <= right) {
mid = left + F[k - 1] - 1;
if(value < temp[mid]) {
//向左查找
right = mid - 1;
k--;
/*
* 对k的说明:
* 1.全部元素 = 前面的元素 + 后边元素
* 2.F[k] = F[k-1] + F[k-2]
* 3.因为前面有F[k-1]个元素,所以可以继续拆分成F[k-1] = F[k-2] + F[k-3]
* 4.即在F[k-1]的前面继续查找
*/
} else if(value > temp[mid]) {
//向右查找
left = mid + 1;
k -= 2;
/*
* 对k的说明:
* 1.全部元素 = 前面的元素 + 后边元素
* 2.F[k] = F[k-1] + F[k-2]
* 3.因为前面有F[k-2]个元素,所以可以继续拆分成F[k-1] = F[k-3] + F[k-4]
* 4.即在F[k-2]的前面继续查找
* 5.即下次循环mid = F[k-1-2]
*/
} else {
//找到
//需要确定,返回的是哪个下标
if(mid <= right) {
return mid;
} else
// 出现这种情况是查找到补充的元素
// 而补充的元素与high位置的元素一样
return right;
}
}
return -1;
}
}
难点:
对k的计算,整道题就有点玄乎的感觉,虽然自己按着流程查找了一遍,确实能找到,但还是有点费解。现在理解还不透彻,先就写到这。
学习心得:斐波拉契 = 肥波纳妾(弹幕看见的,当时笑屎),就这个有点难吧,其他的自己能理解,现在也写的出来。明天记得刷题(今天)