查找算法(一)
线性查找
public static void main(String[] args) {
int arr[] = {1,8,5,4,2,3,9,7,6};
int index = seqsearch(arr,4);
System.out.println(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;
}
二分查找
要求::在有序数组中进行查找
思路分析:
确定该数组中间的下标——mid=(left+right)/2
让查找的数和中间值比较,大于则右查找,小于则左查找,重复递归,
当找到时结束递归,或者没有找到,left>right
时结束递归
public static int binsearch(int[] arr, int left, int right, int value) {
if(left>right) {
return -1;
}
int mid = (left+right)/2;
if (value>arr[mid]) {
return binsearch(arr, mid+1, right, value);
}else if (value<arr[mid]) {
return binsearch(arr, left, mid-1, value);
}else {
return mid;
}
}
新需求:找到所有的相同的值,并且返回
找到mid
的索引值之后不要着急返回,向左扫描,找到所有的值并将下标加入到集合中,再向右扫描将下标添加到集合中,最后将集合返回
public static ArrayList binsearch1(int[] arr, int left, int right, int value) {
if (left > right) {
return new ArrayList<Integer>();// 通过大小来判断
}
int mid = (left + right) / 2;
if (value > arr[mid]) {
return binsearch1(arr, mid + 1, right, value);
} else if (value < arr[mid]) {
return binsearch1(arr, left, mid - 1, value);
} else {
ArrayList<Integer> rasindexlist = new ArrayList<Integer>();
int temp = mid - 1;
while (true) {
if (temp < 0 || arr[temp] != value) {
break;
}
rasindexlist.add(temp);
temp -= 1;
}
rasindexlist.add(mid);
temp = mid + 1;
while (true) {
if (temp > arr.length - 1 || arr[temp] != value) {
break;
}
rasindexlist.add(temp);
temp += 1;
}
return rasindexlist;
}
}
插值查找
原理:
插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid
处开始查找。
将折半查找中的求mid
索引的公式,low
表示左边索引left,high表示右边索引right.
公式如下图(其中key
时value
):
其他问题同二分查找
public static int insertValueSearch(int[] arr, int left, int right, int findVal) {
//注意:findVal < arr[0] 和 findVal > arr[arr.length - 1] 必须需要
//否则我们得到的 mid 可能越界
if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
return -1;
}
// 求出mid, 自适应
int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
int midVal = arr[mid];
if (findVal > midVal) { // 说明应该向右边递归
return insertValueSearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) { // 说明向左递归查找
return insertValueSearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
插值查找注意事项:
对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度较快.
关键字分布不均匀的情况下,该方法不一定比折半查找要好