JS-七大查找算法


  • 順序查找
  • 二分查找
  • 插值查找
  • 斐波那契查找
  • 樹表查找
  • 分塊查找
  •  哈希查找

查找定義:根據給定的某個值,在查找表中確定一個其關鍵字等於給定值的數據元素(或記錄)。
查找算法分類:
1)靜態查找和動態查找;
注:靜態或者動態都是針對查找表而言的。動態表指查找表中有刪除和插入操作的表。
2)無序查找和有序查找。
無序查找:被查找數列有序無序均可;
有序查找:被查找數列必須為有序數列。
平均查找長度(Average Search Length,ASL):需和指定key進行比較的關鍵字的個數的期望值,稱為查找算法在查找成功時的平均查找長度。
對於含有n個數據元素的查找表,查找成功的平均查找長度為:ASL = Pi*Ci的和。
Pi:查找表中第i個數據元素的概率。
Ci:找到第i個數據元素時已經比較過的次數。

順序查找

說明:順序查找適合於存儲結構為順序存儲或鏈接存儲的線性表。
  基本思想:順序查找也稱為線形查找,屬於無序查找算法。從數據結構線形表的一端開始,順序掃描,依次將掃描到的結點關鍵字與給定值k相比較,若相等則表示查找成功;若掃描結束仍沒有找到關鍵字等於k的結點,表示查找失敗。
  復雜度分析: 
  查找成功時的平均查找長度為:(假設每個數據元素的概率相等) ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;
  當查找不成功時,需要n+1次比較,時間復雜度為O(n);
  所以,順序查找的時間復雜度為O(n)。

    <script>
        function SequenceSearch(arr, value) {
            for (let i = 0; i < arr.length; i++) {
                if (arr[i] == value) {
                    return i;
                }
            }
            return -1;
        }
        var arr = [1,3,4,5,2,4,2]
        console.log(SequenceSearch(arr,2))
    </script>

二分查找 

說明:元素必須是有序的,如果是無序的則要先進行排序操作。
  基本思想:也稱為是折半查找,屬於有序查找算法。用給定值k先與中間結點的關鍵字比較,中間結點把線形表分成兩個子表,若相等則查找成功;若不相等,再根據k與該中間結點關鍵字的比較結果確定下一步查找哪個子表,這樣遞歸進行,直到查找到或查找結束發現表中沒有這樣的結點。
  復雜度分析:最壞情況下,關鍵詞比較次數為log2(n+1),且期望時間復雜度為O(log2n);
注:折半查找的前提條件是需要有序表順序存儲,對於靜態查找表,一次排序后不再變化,折半查找能得到不錯的效率。但對於需要頻繁執行插入或刪除操作的數據集來說,維護有序的排序會帶來不小的工作量,那就不建議使用。——《大話數據結構》

    <script>
        // 遞歸
        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;
    </script>
    <script>
        // 非遞歸 用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 + 1) / 2);
                if (data[m] == dest) {
                    return m;
                }
                if (data[m] > dest) {
                    end = m - 1;
                } else {
                    start = m + 1;
                }
            }
            return falsex
    </script>

插值查找

基本思想:基於二分查找算法,將查找點的選擇改進為自適應選擇,可以提高查找效率。當然,差值查找也屬於有序查找。
mid=low+1/2*(high-low);將查找的點改進為如下:
mid=low+(key-a[low])/(a[high]-a[low])*(high-low),
  注:對於表長較大,而關鍵字分布又比較均勻的查找表來說,插值查找算法的平均性能比折半查找要好的多。反之,數組中如果分布非常不均勻,那么插值查找未必是很合適的選擇。
  復雜度分析:查找成功或者失敗的時間復雜度均為O(log2(log2n))。

    <script>
        function InsertionSearch(arr, val, start, end) {
            var end = end || data.length - 1;
            var start = start || 0;
            var mid = start + (val - arr[low]) / (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);
            }
        }
    </script>

斐波那契查找

斐波那契數列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(從第三個數開始,后邊每一個數都是前兩個數的和)。斐波那契查找也屬於一種有序查找算法。
斐波那契數組的實現:

    <script>
        function getNum1(index) {
            if (index == 1 || index == 2) {
                return 1;
            } else {
                return getNum(index - 1) + getNum(index - 2);
            }
        }
        function getNum2(index) {
            if (index == 1 || index == 2) {
                return 1;
            } else {
                var one = 1;
                var two = 1;
                for (var i = 3; i <= index; i++) {
                    if (i == 3) {
                        one = 1;
                        two = 1;
                    }
                    else {
                        var temp = one;
                        one = two;
                        two = temp + two;
                    }
                }
                return one + two
            }
        }
        function getNum3(index) {
            var F = [];
            F[0] = 0;
            F[1] = 1;
            for (var i = 2; i < index - 1; i++) {
                F[i] = F[i - 1] + F[i - 2];
            }
            return F[index];
        }
    </script>

基本思路:

相對於折半查找,一般將待比較的key值與第mid=(low+high)/2位置的元素比較,比較結果分三種情況:
1)相等,mid位置的元素即為所求
2)>,low=mid+1;
3)<,high=mid-1。
斐波那契查找與折半查找很相似,他是根據斐波那契序列的特點對有序表進行分割的。他要求開始表中記錄的個數為某個斐波那契數小1,及n=F(k)-1;
開始將k值與第F(k-1)位置的記錄進行比較(及mid=low+F(k-1)-1),比較結果也分為三種
1)相等,mid位置的元素即為所求
2)>,low=mid+1,k-=2;
說明:low=mid+1說明待查找的元素在[mid+1,high]范圍內,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個,所以可以遞歸 的應用斐波那契查找。

    <script>
        function search(array, value) {
            let low = 0, high = 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 < high + 5; i++) {
                F[i] = F[i - 1] + F[i - 2];
            }
            while (high > F[k] - 1) { //尋找第k項
                k++;
            }
            for (let i = high; i < F[k] - 1; i++) { //補全有序數組
                array[i] = array[high];
            }
            while (low <= high) {
                mid = low + F[k - 1] - 1;
                if (array[mid] > value) {
                    high = mid - 1;
                    k = k - 1; //長度縮減為F[k-1]-1
                } else if (array[mid] < value) {
                    low = mid + 1;
                    k = k - 2; //長度縮減為F[k-2]-1
                } else {
                    if (m <= n) //相等則找到位置
                        return mid;
                    else {
                        return n; //大於原始長度,則說明等於數組最后一項 
                    }
                }
                return -1;
            }
        }
    </script>

樹表查找

最簡單的樹表查找算法——二叉樹查找算法。
基本思想:二叉查找樹是先對待查找的數據進行生成樹,確保樹的左分支的值小於右分支的值,然后在就行和每個節點的父節點比較大小,查找最適合的范圍。 這個算法的查找效率很高,但是如果使用這種查找方法要首先創建樹。
    二叉查找樹(BinarySearch Tree,也叫二叉搜索樹,或稱二叉排序樹Binary Sort Tree)或者是一棵空樹,或者是具有下列性質的二叉樹:
    1)若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
    2)若任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
    3)任意節點的左、右子樹也分別為二叉查找樹。
    二叉查找樹性質:對二叉查找樹進行中序遍歷,即可得到有序的數列。

索引查找(分塊查找)

分塊查找又稱索引順序查找,它是順序查找的一種改進方法。
  算法思想:將n個數據元素"按塊有序"划分為m塊(m ≤ n)。每一塊中的結點不必有序,但塊與塊之間必須"按塊有序";即第1塊中任一元素的關鍵字都必須小於第2塊中任一元素的關鍵字;而第2塊中任一元素又都必須小於第3塊中的任一元素,……
  算法流程:
  step1 先選取各塊中的最大關鍵字構成一個索引表;
  step2 查找分兩個部分:先對索引表進行二分查找或順序查找,以確定待查記錄在哪一塊中;然后,在已確定的塊中用順序法進行查找。

哈希查找  

哈希查找和哈希算法看這里
  哈希查找 https://www.cnblogs.com/yw09041432/p/5908444.html
  哈希算法 https://www.cnblogs.com/xiohao/p/4389672.html http://www.sohu.com/a/232586831_100078137

貪心算法

遵循一種近似解決問題的技術,期盼通過每個階段的局部最優選擇(當前最好的解),從而達到全局的最優(全局最優解)。貪心得到結果是一個可以接受的解,不一定總是得到最優的解。
最少硬幣找零問題:最少硬幣找零是給出要找零的錢數,以及可以用硬幣的額度數量,找出有多少種找零方法。
如:美國面額硬幣有:1,5,10,25
我們給36美分的零錢,看能得怎樣的結果?

    <script>
        function MinCoinChange(coins) {
            var coins = coins;
            var cache = {};
            this.makeChange = function (amount) {
                var change = [], total = 0;
                for (var i = coins.length; i >= 0; i--) {
                    var coin = coins[i];
                    while (total + coin <= amount) {
                        change.push(coin);
                        total += coin;
                    }
                }
                return change;
            }
        }
        var minCoinChange = new MinCoinChange([1, 5, 10, 25]);
        minCoinChange.makeChange(36);
        //一個25, 一個10, 一個1
    </script>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM