算法 -查找算法

本文介绍了四种查找算法:顺序查找、二分查找、插值查找和斐波那契查找。顺序查找适合无序线性表,时间复杂度为O(n)。二分查找适用于有序表,期望时间复杂度为O(log2n)。插值查找在均匀分布的有序表中性能优于二分查找。斐波那契查找利用斐波那契数列特性,同样适用于有序表。
摘要由CSDN通过智能技术生成

查找算法

(一)顺序查找

说明:

顺序查找适合于存储结构为顺序存储或链接存储的线性表。
基本思想:

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

复杂度分析:

  • 查找成功时的平均查找长度为:(假设每个数据元素的概率相等) ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;
  • 当查找不成功时,需要n+1次比较,时间复杂度为O(n);
  • 所以,顺序查找的时间复杂度为O(n)。
 function SequenceSearch(arr, value) {
            for (let i = 0; i < arr.length; i++) {
                if (arr[i] == value) {
                    return i;
                }
            }
            return -1;
        }

(二)二分查找

说明:

元素必须是有序的,如果是无序的则要先进行排序操作。
基本思想:

也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。
复杂度分析:

最坏情况下,关键词比较次数为log2(n+1),且期望时间复杂度为O(log2n);
注:折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。

 // 递归
        function binarySearch(data, dest, start, end) {
            if (start > end) { // 新增否则找不到进入死循环了
                return false;
            }
            var end = end || data.length - 1;
            var start = start || 0;
            var mid = Math.floor((start + end) / 2);
            //var mid = parseInt(start+(end-start)/2);
            //直接命中
            if (data[mid] == dest) {
                return mid;
            }

            if (data[mid] > dest) { // 放左
                end = mid - 1;
                return binarySearch(data, dest, start, end);
            } else { // 放右
                start = mid + 1;
                return binarySearch(data, dest, start, end);
            }
            return false;
        }

 // 非递归 用while
        //代码中的判断条件必须是while (left <= right),
        //否则的话判断条件不完整,比如:array[3] = {1, 3, 5};
        //待查找的键为5,此时在(low < high)条件下就会找不到,因为low和high相等时,指向元素5,但是此时条件不成立,没有进入while()中
        function binarySearch2(data, dest) {
            var end = data.length - 1;
            var start = 0;
            while (start <= end) {
                var m = Math.floor((end + start) / 2);
                if (data[m] == dest) {
                    return m;
                }
                if (data[m] > dest) {
                    end = m - 1;
                } else {
                    start = m + 1;
                }
            }
            return false
        }

(三)插值查找

基本思想:

插值查找算法类似于二分查找,不同的是插值查找每次从自适应 mid 处开始查找。当然,差值查找也属于有序查找。

mid=start+1/2*(end-start),改进为:mid=start+[(key-a[start])/(a[end]-a[start])]*(end-start)
注:对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。
复杂度分析:

查找成功或者失败的时间复杂度均为O(log2(log2n))。

 function InsertionSearch(arr, val, start, end) {
            var end = end || data.length - 1;
            var start = start || 0;
            var mid = start + (val - arr[start]) / (arr[end] - arr[start]) * (end - start);
            if (arr[mid] == val) {
                return mid;
            }
            if (arr[mid] > val) {
                return InsertionSearch(arr, val, start, mid - 1);
            }
            else {
                return InsertionSearch(arr, val, mid + 1, end);
            }
        }

(四)斐波那契查找

斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和)。斐波那契查找也属于一种有序查找算法。
斐波那契数组的实现:

function fib(index) {
            if (index == 1 || index == 2) {
                return 1;
            } else {
                return fib(index - 1) + fib(index - 2);
            }
        }

基本思路:

相对于折半查找,一般将待比较的key值与第mid=(start + end)/2位置的元素比较,比较结果分三种情况:

  • 相等,mid位置的元素即为所求
  • >,start = mid+1;
  • <,end = mid-1。

斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;
开始将k值与第F(k-1)位置的记录进行比较(及mid=start+F(k-1)-1),比较结果也分为三种

  • 相等,mid位置的元素即为所求
  • >,start=mid+1,k -= 2;
    说明:start=mid+1说明待查找的元素在[mid+1,end]范围内,k-=2 说明范围[mid+1,end]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。
  • <,end=mid-1,k -= 1。
    说明:end=mid-1说明待查找的元素在[start,mid-1]范围内,k-=1 说明范围[start, mid-1]内的元素个数为F(k-1)-1个,所以可以递归 的应用斐波那契查找。
 function search(array, value) {
            let start = 0, end = array.length - 1, n = array.length - 1;
            let mid, k = 0;
            //构建一个长度大于array数组的斐波那契数组
            var F = [];
            F[0] = 0;
            F[1] = 1;
            for (var i = 2; i < end + 5; i++) {
                F[i] = F[i - 1] + F[i - 2];
            }
            while (end > F[k] - 1) { //寻找第k项
                k++;
            }
            for (let i = end; i < F[k] - 1; i++) { //补全有序数组
                array[i] = array[end];
            }
            while (start <= end) {
                mid = start + F[k - 1] - 1;
                if (array[mid] > value) {
                    end = mid - 1;
                    k = k - 1; //长度缩减为F[k-1]-1
                } else if (array[mid] < value) {
                    start = mid + 1;
                    k = k - 2; //长度缩减为F[k-2]-1
                } else {
                    if (m <= n) //相等则找到位置
                        return mid;
                    else {
                        return n; //大于原始长度,则说明等于数组最后一项 
                    }
                }
                return -1;
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值