一、二分查找
1.代码实现
思路分析: 1.编写一个方法,传入一个数组和数组第一个值位置left和最后一个值的位置right 2.让(left+right)/2就是二分的位置 3.当当前值等于需要查找的值,就返回,不等于进行判断 4.判断条件,当比mid大,向右找,进入递归,那么此时的right值不变,left变成mid+1(之前的中间值不再考虑),向左反之 5.如果此时的left>right,那么说明没有这个数据,就返回
public int search(int[] ints,int value,int left,int right){
if(left > right){
return -1;
}
int result = 0;
int mid = (left+right)/2;
if(ints[mid] == value){
return mid;
}else {
if(ints[mid] > value){//向左找
result = search(ints,value,left,mid - 1);
}else {//向右找
result = search(ints,value,mid + 1,right);
}
}
return result;
}
2.功能完善
实现查找所有相同元素的下标
思路分析: 1.通过返回ArrayList类型返回所有元素下标 2.找到第一个元素时进行两次判断,向左找和向右找 3.当找到元素与第一个元素不同时,或者找到了数组边界,那么就结束,否则就保存索引
public ArrayList<Integer> searchPlus(int[] ints,int value,int left,int right){
if(left > right){
return new ArrayList<Integer>();//如果没找到,那么返回一个空的集合
}
int mid = (left+right)/2;
if(ints[mid] > value){//向左找
return searchPlus(ints,value,left,mid - 1);
}else if(ints[mid] < value){//向右找
return searchPlus(ints,value,mid + 1,right);
}
ArrayList<Integer> list = new ArrayList<>();
int temp = mid - 1;//向左找
while (temp >= 0){
if(ints[temp] == value){
list.add(temp);
temp--;
}else {
break;
}
}
list.add(mid);
temp = mid + 1;//向右找
while (temp < ints.length){
if(ints[temp] == value){
list.add(temp);
temp++;
}else {
break;
}
}
return list;
}
二、插值查找
思路分析: 与二分查找的唯一区别就是在取mid中间值的时候使用了公式进行查找,这样更加节省了查找数据的速度 mid = left + (right - left) * (value - ints[left]) / (ints[right] - ints[left])
public static ArrayList<Integer> insertSearch(int[] ints,int value,int left,int right){
if(left > right){
return new ArrayList<Integer>();//如果没找到,那么返回一个空的集合
}
int mid = left + (right - left) * (value - ints[left]) / (ints[right] - ints[left]);
if(ints[mid] > value){//向左找
return insertSearch(ints,value,left,mid - 1);
}else if(ints[mid] < value){//向右找
return insertSearch(ints,value,mid + 1,right);
}
ArrayList<Integer> list = new ArrayList<>();
int temp = mid - 1;//向左找
while (temp >= 0){
if(ints[temp] == value){
list.add(temp);
temp--;
}else {
break;
}
}
list.add(mid);
temp = mid + 1;//向右找
while (temp < ints.length){
if(ints[temp] == value){
list.add(temp);
temp++;
}else {
break;
}
}
return list;
}
插值查找注意事项:
1)
对于数据量较大,
关键字分布比较均匀
的查找表来说,采用
插值查找
,
速度较快
.
2)
关键字分布不均匀的情况下,该方法不一定比折半查找要好
三、斐波那契查找(黄金分割查找)
斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即mid=low+F(k-1)-1(F代表斐波那契数列)
对F(k-1)-1的理解:
1)
由斐波那契数列
F[k]=F[k-1]+F[k-2]
的性质,可以得到
(
F[k]-1
)
=
(
F[k-1]-1
)
+
(
F[k-2]-1
)
+1
。该式说明:只要顺序表的长度为
F[k]-1
,则可以将该表分成长度为
F[k-1]-1
和
F[k-2]-1
的两段,即如上图所示。从而中间位置为
mid=
low+F
(k-1)-1
2)
类似的,每一子段也可以用相同的方式分割
3)
但顺序表长度
n
不一定刚好等于
F[k]-1
,所以需要将原来的顺序表长度
n
增加至
F[k]-1
。这里的
k
值只要能使得
F[k]-1
恰好大于或等于
n
即可,由以下代码得到
,
顺序表长度增加后,新增的位置(从
n+1
到
F[k]-1
位置),都赋为
n
位置的值即可。