java查找算法_【Java】 大话数据结构(10) 查找算法(1)(顺序、二分、插值、斐波那契查找)...

本文根据《大话数据结构》一书,实现了Java版的顺序查找、折半查找、插值查找、斐波那契查找。

注:为与书一致,记录均从下标为1开始。

顺序表查找

顺序查找

顺序查找(Sequential Search):从第一个到最后一个记录依次与给定值比较,若相等则查找成功。

顺序查找优化:设置哨兵,可以避免每次循环都判断是否越界。在数据量很多时能提高效率。

时间复杂度:O(n),n为记录的数。

以下为顺序查找算法及其优化的Java代码:

package Sequential_Search;

/**

* 顺序表查找

* 数组下标为0的位置不用来储存实际内容

* @author Yongh

*

*/

public class Sequential_Search {

/*

* 顺序查找

*/

public int seqSearch(int[] arr,int key) {

int n=arr.length;

for(int i=1;i

if(key==arr[i])

return i;

}

return 0;

}

/*

* 顺序查找优化,带哨兵

*/

public int seqSearch2(int[] arr,int key) {

int i=arr.length-1;

arr[0]=key; //将arr[0]设为哨兵

while(arr[i]!=key)

i--;

return i; //返回0说明查找失败

}

public static void main(String[] args) {

int[] arr = {0,45,68,32,15};

Sequential_Search aSearch = new Sequential_Search();

System.out.println(aSearch.seqSearch(arr, 15));

System.out.println(aSearch.seqSearch(arr, 45));

}

}

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

4

1

Sequential_Search

有序表查找

折半查找(二分查找)

折半查找,又称作二分查找。必须满足两个前提:

1.存储结构必须是顺序存储

2.关键码必须有序排列

假设数据按升序排列。从中间项与关键值(key)开始对比,若关键值(key)>中间值,则在右半区间继续查找,反之则左半区间继续查找。以此类推,直至找到匹配值,或者查找内无记录,查找失败。

时间复杂度:O(logn),可从二叉树的性质4推得。

折半查找的Java实现代码:

package OrderedTable_Search;

/**

* 折半查找

* @author Yongh

*

*/

public class BinarySearch {

public int binarySearch(int[] arr,int n,int key) {

int low=1;

int high=n;

while(low<=high) {

int mid = (low+high)/2;

if(arr[mid]

low=mid+1; //要+1

else if(arr[mid]>key)

high=mid-1; //要-1

else

return mid;

}

return 0;

}

public static void main(String[] args) {

int[] arr = {0,1,16,24,35,47,59,62,73,88,99};

int n=arr.length-1;

int key=62;

BinarySearch aSearch = new BinarySearch();

System.out.println(aSearch.binarySearch(arr, n, key));

}

}

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

4

BinarySearch

插值查找

对于表长较大,关键字分布比较均匀的查找表来说,可以采用插值查找:

将折半查找中代码的第12行

7c82628158d7368daeb579d63477da4d.png

改进为:

b14c6c7edb01cbd810cdbe0d8b9737a7.png

改进后的第12行代码如下:

int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]);/*插值*/

注意:关键字分布不均匀的情况下,该方法不一定比折半查找要好。

斐波那契查找

斐波那契数列如下所示:

38b80c70a5f020148d5d567de439aec6.png

斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即mid=low+F(k-1)-1(F代表斐波那契数列),如下图所示:

10dec7b8221481676b8583125a6be343.png

对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的两段,即如上图所示。从而中间位置为mid=low+F(k-1)-1

类似的,每一子段也可以用相同的方式分割,从而方便编程。

但顺序表长度n不一定刚好等于F[k]-1,所以需要将原来的顺序表长度n增加至F[k]-1。这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到:

while(n>fib(k)-1)

k++;

顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。

时间复杂度:O(logn)

以下为具体的Java代码,还有不理解的地方可看对应处的注释:

package OrderedTable_Search;

/**

* 斐波那契查找

* 下标为0位置不存储记录

* 顺便编写了斐波那契数列的代码

* @author Yongh

*

*/

public class FibonacciSearch {

/*

* 斐波那契数列

* 采用递归

*/

public static int fib(int n) {

if(n==0)

return 0;

if(n==1)

return 1;

return fib(n-1)+fib(n-2);

}

/*

* 斐波那契数列

* 不采用递归

*/

public static int fib2(int n) {

int a=0;

int b=1;

if(n==0)

return a;

if(n==1)

return b;

int c=0;

for(int i=2;i<=n;i++) {

c=a+b;

a=b;

b=c;

}

return c;

}

/*

* 斐波那契查找

*/

public static int fibSearch(int[] arr,int n,int key) {

int low=1;//记录从1开始

int high=n; //high不用等于fib(k)-1,效果相同

int mid;

int k=0;

while(n>fib(k)-1)//获取k值

k++;

int[] temp = new int[fib(k)];//因为无法直接对原数组arr[]增加长度,所以定义一个新的数组

System.arraycopy(arr, 0, temp, 0, arr.length); //采用System.arraycopy()进行数组间的赋值

for(int i=n+1;i<=fib(k)-1;i++) //对数组中新增的位置进行赋值

temp[i]=temp[n];

while(low<=high) {

mid=low+fib(k-1)-1;

if(temp[mid]>key) {

high=mid-1;

k=k-1; //对应上图中的左段,长度F[k-1]-1

}else if(temp[mid]

low=mid+1;

k=k-2; //对应上图中的右端,长度F[k-2]-1

}else {

if(mid<=n)

return mid;

else

return n;//当mid位于新增的数组中时,返回n

}

}

return 0;

}

public static void main(String[] args) {

int[] arr = {0,1,16,24,35,47,59,62,73,88,99};

int n=10;

int key=59;

System.out.println(fibSearch(arr, n, key)); //输出结果为:6

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值