查找算法-顺序查找、有序查找

1.顺序表的查找

1)顺序查找

顺序查找又称为线性查找,是一种最简单的查找方法。

        从表的一端开始,向另一端逐个按要查找的值key 与关键码key进行比较,若找到,查找成功,并给出数据元素在表中的位置;若整个表检测完,仍未找到与关键码相同的key值,则查找失败,给出失败信息。

说白了就是,从头到尾,一个一个地比,找着相同的就成功,找不到就失败。很明显的缺点就是查找效率低。

【适用性】:适用于线性表的顺序存储结构和链式存储结构。

 平均查找长度=(n+1)/2.

【顺序查找优缺点】:

缺点:是当n 很大时,平均查找长度较大,效率低;

优点:是对表中数据元素的存储没有要求。另外,对于线性链表,只能进行顺序查找。

 public static int orederSearch(int[] array, int key) {
        if (array.length > 0) {
            for (int i = 0; i < array.length; i++) {
                if (array[i] == key) {
                    return i;
                }
            }
        }
        return -1;
    }

2.有序表的查找

1)折半查找

 在有序表中,取中间元素作为比较对象,若给定值与中间元素的关键码key相等,则查找成功;若给定值小于中间元素的关键码,则在中间元素的左半区继续查找;若给定值大于中间元素的关键码,则在中间元素的右半区继续查找。不断重复上述查找过程,直到查找成功,或所查找的区域无数据元素,查找失败。时间复杂度为o(logn)

折半查找的前提条件是需要有序的顺序存储,对于静态查找表,一次排序后不再变化,这样的算法已经比较好。但是对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,不建议使用

    public static int binarySearch(int[] array, int key) {
        if (array.length > 0) {
            int low, high, mid;
            low = 0;
            high = array.length - 1;
            while (low <= high) {
                mid = (low + high) / 2;//折半
                if (key < array[mid])
                    high = mid - 1;
                else if (key > array[mid])
                    low = mid + 1;
                else
                    return mid;

            }
        }

        return -1;
    }

2)插值查找

 插值查找是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的 查找方法,其核心就在于插值的计算公式 (key-a[low])/(a[high]-a[low])*(high-low)。时间复杂度o(logn)但对于表长较大而关键字分布比较均匀的查找表来说,效率较高

 public static int interpolationSearch(int[] array, int key) {
        if (array.length > 0) {
            int low, high, mid;
            low = 0;
            high = array.length - 1;
            while (low <= high) {
                mid = low + (high - low) * (key - array[low]) / (array[high] - array[low]);//插值
                if (key < array[mid])
                    high = mid - 1;
                else if (key > array[mid])
                    low = mid + 1;
                else
                    return mid;
            }
        }

        return -1;
    }

3)斐波那契查找

      斐波那契查找的前提是待查找的查找表必须顺序存储并且有序。时间复杂度o(logn)
斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,及n=Fk-1;
     开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种
     1)相等,mid位置的元素即为所求
     2)>   ,low=mid+1,k-=2;
     说明:low=mid+1说明待查找的元素在[mid+1,hign]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找
     3)<    ,high=mid-1,k-=1;
     说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1 个,所以可以递归 的应用斐波那契查找
     《查找算法-顺序查找、有序查找》

 public static int fbnacciSearch(int[] array, int key) {
        if (array == null || array.length == 0) {
            return -1;
        } else {
            int length=array.length;
            int[] fb=makeFbnacciArray(20);
            int k=0;
            while (length>fb[k]-1){//找出数组的长度在斐波那契数列中的位置 n<=F[k]-1
                k++;
            }
            //n不一定刚刚好等于F[k]-1 此时扩容原数组 新增的位置的值为原数组的最大值
            int[] temp= Arrays.copyOf(array,fb[k]-1);
            for (int i=length;i<temp.length;i++){
                if(i>=length){
                    temp[i]=array[length-1];
                }
            }
            int low=0;
            int high=array.length-1;
            while (low<=high){
                int middle=low+fb[k-1]-1;
                if(temp[middle]>key){
                    high=middle-1;
                    k=k-1;
                }else if(temp[middle]<key){
                    low=middle+1;
                    k=k-2;
                }else{
                    if(middle<=high){
                        return  middle;//若相等则说明middle为查找的位置
                    }else{
                        return high;//middle的值已经大于high,进入扩展数组的填充部分,既最后一个数就是要查找的数
                    }
                }
            }
        }

        return -1;
    }

    private static int[] makeFbnacciArray(int length) {
        int array[] = null;
        if (length > 2) {
            array = new int[length];
            array[0] = 1;
            array[1] = 1;
            for (int i = 2; i < length; i++) {
                array[i] = array[i - 1] + array[i - 2];
            }
        }
        if (length == 2) {
            array = new int[length];
            array[0] = 1;
        }
        if (length == 1) {
            array = new int[length];
            array[0] = 1;
            array[1] = 1;
        }
        return array;
    }

4.总结

三种有序表的查找本质是分割点的选择不同,各有优劣,实际开发时可根据数据的特点综合考虑再做选择。这里注意主要的运算,折半查找采用乘除(mid = (low + high) / 2
)、插值采用的是四则运算(  mid = low + (high – low) * (key – array[low]) / (array[high] – array[low])),斐波那契采用的是加减(middle=low+fb[k-1]-1)


    原文作者:查找算法
    原文地址: https://blog.csdn.net/junbin1011/article/details/53488353
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞