线性查找
/**
* 线性查找
* @param array
* @param value
* @return
*/
public static int SeqSearch(int[] array,int value){
for (int i = 0; i < array.length; i++) {
if(value == array[i]){
return i;
}
}
return 0;
}
二分查找
/**
* 二分查找(要求数组有序)
* @param array
* @param leftIndex
* @param rightIndex
* @param findValue
* @return
*/
public static int binarySearch(int[] array,int leftIndex,int rightIndex,int findValue){
if(leftIndex > rightIndex){
return -1;
}
int middleIndex = (leftIndex + rightIndex) / 2;
if(array[middleIndex] < findValue){
return binarySearch(array,middleIndex + 1,rightIndex,findValue);
}else if(array[middleIndex] > findValue){
return binarySearch(array,leftIndex,middleIndex - 1,findValue);
}else {
return middleIndex;
}
}
/**
* 查找所有满足条件的集合
* @param array
* @param leftIndex
* @param rightIndex
* @param findValue
* @return
*/
public static List<Integer> binarySearchAll(int[] array, int leftIndex, int rightIndex, int findValue){
if(leftIndex > rightIndex){
return new ArrayList<>();
}
int middleIndex = (leftIndex + rightIndex) / 2;
if(array[middleIndex] < findValue){
return binarySearchAll(array,middleIndex + 1,rightIndex,findValue);
}else if(array[middleIndex] > findValue){
return binarySearchAll(array,leftIndex,middleIndex - 1,findValue);
}else {
ArrayList<Integer> list = new ArrayList<>();
list.add(middleIndex);
//先向左找
int tmpLeftIndex = middleIndex - 1;
while(true){
if(tmpLeftIndex < 0 || array[tmpLeftIndex] < array[middleIndex]){
break;
}
list.add(tmpLeftIndex--);
}
//再向右找
int tmpRightIndex = middleIndex + 1;
while(true){
if(tmpRightIndex > rightIndex || array[tmpRightIndex] > array[middleIndex]){
break;
}
list.add(tmpRightIndex++);
}
return list;
}
}
插值查找
插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。
mid=(findValue-array[leftIndex])*(leftIndex-rightIndex)/(array[leftIndex]-array[rightIndex])+leftIndex;
对于数据量较大,关键字分布比较均匀的查找来说,采用插值查找,速度比较块。
关键字不均匀的情况下,该方法不一定比折半查找要好。
/**
* 插值查找(要求数组有序)
* @param array
* @param leftIndex
* @param rightIndex
* @param findValue
* @return
*/
public static int insertSearch(int[] array,int leftIndex,int rightIndex,int findValue){
if(leftIndex > rightIndex || findValue < array[leftIndex] || findValue > array[rightIndex]){
return -1;
}
int forecastIndex = (findValue-array[leftIndex])*(leftIndex-rightIndex)/(array[leftIndex]-array[rightIndex])+leftIndex;
if(array[forecastIndex] > findValue){
return insertSearch(array,leftIndex,forecastIndex-1,findValue);
}else if(findValue > array[forecastIndex]){
return insertSearch(array,forecastIndex + 1,rightIndex,findValue);
}else {
return forecastIndex;
}
}
斐波那契(黄金分割法)查找
介绍
黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位的近似值是0.618。由于按比例设计的造型十分美丽,因此称为黄金分割。
斐波那契数列{1,1,2,3,5,8,13,21,34,55}的相邻的两个数的比例,无限接近黄金分割值0.618。
原理
forecaseIndex = low + F(k - 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 的两段。从而中间位置为forecaseIndex = low + F(k - 1) - 1;
类似的,每一段也可以用相同的方式分割。
但顺序表的长度不一定刚好等于F[k] - 1,所以需要将原来的顺序表长度增加至F(K) - 1。这里的k值只要能使得F(K) - 1恰好大于或等于n即可,新增加的位置都赋为n位置的值即可。
/**
* 斐波那契(黄金分割法)查找(要求数组有序)
* @param array
* @param findValue
* @return
*/
public static int fibonacciSezrch(int[] array,int findValue){
int tmpLeftIndex = 0;
int tmpRightIndex = array.length - 1;
int k = 0;//斐波那契数组下标
int[] fibArray = getFibArray(20);
//
while(tmpRightIndex > fibArray[k] - 1) {
k++;
}
int[] tmpArray = Arrays.copyOf(array, fibArray[k]);
for (int i = tmpRightIndex + 1; i < fibArray[k]; i++) {
tmpArray[i] = array[tmpRightIndex];
}
while(tmpLeftIndex <= tmpRightIndex){
int forecaseIndex = tmpLeftIndex + fibArray[k - 1] - 1;
if(findValue < tmpArray[forecaseIndex]){
tmpRightIndex = forecaseIndex - 1;
//(F(k) - 1) = (F(k - 1) - 1) + (F(k - 2) - 1) + 1;
k--;
}else if(findValue > tmpArray[forecaseIndex]){
tmpLeftIndex = forecaseIndex + 1;
//(F(k) - 1) = (F(k - 1) - 1) + (F(k - 2) - 1) + 1;
k-=2;
}else {
if(forecaseIndex <= tmpRightIndex){
return forecaseIndex;
}else {
return tmpRightIndex;
}
}
}
return -1;
};
/**
* 获取一个斐波那契数组
* @param size
* @return
*/
public static int[] getFibArray(int size){
int[] array = new int[size];
array[0] = 1;
array[1] = 1;
for (int i = 2; i < size; i++) {
array[i] = array[i - 1] + array[i - 2];
}
return array;
}