五、查找
1、概念
2、查找算法
常用的查找算法有顺序(线性)查找、二分查找、(折半)查找、插值查找、斐波那契查找
2.1顺序查找
顺序查找(Sequential Search)又叫线性查找,是最基本的查找技术,它的查找过程:从表中第一个(或最后一个)记录开始,逐个进行序列中的元素与给定值的比较,若序列中的元素和给定值相等,则查找成功;如果知道最后一个(或第一个)元素,其元素和给定值的比较都不相等,则表中没有所查的元素,则查找不成功。
public static int sequenceSearch(int[] arr,int value){
int temp=0;
for(int i=0;i<arr.length;i++){
if(arr[i]==value){
temp=i;
break;
}else {
temp= -1;
}
}
return temp;
}
2.4二分查找
算法描述(保证在序列有序)
-
首先确定该数组的中间下标
mid=(left+right)/2
-
然后让需要查找的数find Val和arr[mid]比较
find>arr[mid],说明要查找的数在mid的右边,需要递归的向右查找。 find<arr[mid],说明要查找的数在mid的左边,需要递归的向左查找。 findVal==arr[mid]说明找到,就返回
-
什么时候我们需要结束递归
找到就结束递归 递归完整个数组,仍然没有找到findVal,也需要结束递归,当left>right就需要退出
代码实现1(查找序列中的元素,查找一个)
public static int binarySearch(int[] arr, int left, int right, int value) {
int mid = (right + left) / 2;
if (left > right) {
return -1;
}
if (value > arr[mid]) {
//向右递归
return binarySearch(arr, mid + 1, right, value);
} else if (value < arr[mid]) {
//向左递归
return binarySearch(arr, left, mid - 1, value);
} else {
return mid;
}
}
代码实现2(查找指定元素在序列中的全部位置下标)
public static ArrayList<Integer> binarySearch2(int[] arr, int left, int right, int value) {
int mid = (right + left) / 2;
if (left > right) {
return new ArrayList<>();
}
if (value > arr[mid]) {
//向右递归
return binarySearch2(arr, mid + 1, right, value);
} else if (value < arr[mid]) {
//向左递归
return binarySearch2(arr, left, mid - 1, value);
} else {
ArrayList<Integer> list = new ArrayList<>();
int temp = mid-1;
//向左索引
while (true) {
if (temp< 0 ||arr[temp] != value) {
break;
}
list.add(temp);
temp--;
}
//向右索引
temp=mid+1;
while (true) {
if (temp > arr.length - 1 ||arr[temp] != value) {
break;
}
list.add(temp);
temp++;
}
list.add(mid);
return list;
}
}
2.5插值查找
插值查找算法并不是简单的从中间进行的,它是根据我们需要查询的值渐渐进行搜索的,即根据与所求值的距离进行搜索,其钱前提条件保证序列有序。
mid=left+(right-low)*(findValue-arr[left])/(arr[right]-arr[left])
Note:
- 对于数据量较大,序列中的数据分布比较均匀,采用插值查找,速度较快
- 序列中的数据分布不均匀,插值查找不一定会比折半查找好
public static int insertValueSearch(int[] arr,int left,int right,int findValue){
if(left>right||findValue<arr[left]||findValue>arr[right]){
return -1;
}
int mid=left+(right-left)*(findValue-arr[left])/(arr[right]-arr[left]);
if(findValue>arr[mid]){
//向右递归
return insertValueSearch(arr,mid+1,right,findValue);
}
else if(findValue<arr[mid]){
//向左递归
return insertValueSearch(arr,left,mid-1,findValue);
}
else {
return mid;
}
}
2.6斐波那契查找
算法描述:
斐波那契算法是以斐波那契数列为基础(又称黄金分割数列),它的前一项与后一项的比值随着数字量的增多逐渐逼近黄金分割比值0.618。所以斐波那契查找改变了二分查找中原有的中值mid的求解方式,其mid不再代表中值,而是代表黄金分割点。
1、如果与给定的值相同,则查找成功,返回在表中的位置。
2、如果比给定的值小,向右查找并减少2个斐波那契空间
3、如果比给定值大,向左查找并减少1个斐波那契空间
4、重复过程,直到找到给定的值(成功)或区间为空集(失败)
//斐波那契算法查找
public static int fibonacciSearch(int[] arr, int findValue) {
int left = 0;
int right = arr.length - 1;
int mid = 0;
int k = 0;//记录斐波那契分隔数值的下标
int f[] = fib();//获得斐波那契数列
while (right > f[k] - 1) {
k++;
}
//对数组a中的元素数量与斐波那契f[k]值相等
int[] temp = Arrays.copyOf(arr, f[k]);
//将填充的元素等于原数组的最后一个元素,进行元素补充
for (int i = right + 1; i < temp.length; i++) {
temp[i] = temp[right];
}
//斐波那契查找
while (left <= right) {
mid = left + f[k - 1] - 1;
if (findValue < temp[mid]) {
//分割点左边的数据继续进行分割
right = mid - 1;
k--;
} else if (findValue > temp[mid]) {
//对分割点右边的数据继续进行分割
left = mid + 1;
k -= 2;
} else {
if (mid < right) {
return mid;
} else {
return right;
}
}
}
return -1;
}