淺析斐波那契數列在代碼中的應用

来源:https://www.cnblogs.com/emanjusaka/archive/2023/10/13/page_9.html
-Advertisement-
Play Games

斐波那契數列在代碼中的應用是比較常見的,下麵讓我們來瞭解下一個數學上的數列在代碼中會有哪些應用。瞭解斐波那契,可以給我們提供解決某些問題的思路,優化解決問題的方法。 ...


by emanjusaka from ​ https://www.emanjusaka.top/archives/9 彼岸花開可奈何
本文歡迎分享與聚合,全文轉載請留下原文地址。

前言

斐波那契數列在代碼中的應用是比較常見的,下麵讓我們來瞭解下一個數學上的數列在代碼中會有哪些應用。瞭解斐波那契,可以給我們提供解決某些問題的思路,優化解決問題的方法。

一、定義

F0 = 0,F1 = 1,Fn = F(n - 1) + F(n - 2)

F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
  • 從 F2 開始任意一位都是前兩位之和。
  • 從 F2 開始任意一位與前一位相比的比值,都無限趨近於 (√5 - 1)/2 = 0.618 因此基於黃金分割的計算應用,也被稱為斐波那契應用。

二、三種計算方法

2.1、迴圈計算

public double fibonacci(int n) {
    int f1 = 1;
    int f0 = 0;
    if (n < 2) return n;
    int num = n - 1;
    while (num > 0) {
        f1 += f0;
        f0 = f1 - f0;
        num --;
    }
    return f1;
}

2.2、遞歸計算

public int fibonacciRecursion(int n) {
    if (n < 2){
        return n;
    } else {
        return (fibonacciRecursion(n - 1) + fibonacciRecursion(n - 2));
    }
}

2.3、比奈公式

public double fibonacciClosedForm(long position) {
    int maxPosition = 75;
    if (position < 1 || position > maxPosition) {
        throw new RuntimeException("Can't handle position smaller than 1 or greater than 75");
    }
    double sqrt = Math.sqrt(5);
    double phi = (1 + sqrt) / 2;
    return Math.floor((Math.pow(phi, position)) / sqrt + 0.5);
}

三、散列函數

3.1、除法散列

在用來設計散列函數的除法散列法中,通過取 K 除以 M 的餘數,將關鍵字 K 映射到 M 個槽中的某一個位置上,即散列函數為:h(K) = K mod M 表格大小通常是 2 的冪。

另外除法散列的一個顯著缺點是除法在大多數現代架構(包括 x86)上都是微編程的,並且可能比乘法慢 10 倍。

3.2、乘法散列

乘法散列法整體包含兩步:

  • 用關鍵字k乘上常數A(0<A<1),並去除kA的小數部分
  • 用m乘以這個值,再取結果的底floor 公式:h(K)=Math.floor[m(aK mod 1)]

步驟

  • 假設某電腦的字長為 ww 位,而 kk 正好可容於一個字中(k<2wk<2w)
  • 現在選取範圍[0,2w]內的任意數值 ss,k×sk×s 即可用R1·2w+R0R1·2w+R0來表示
  • 因此(k·A)mod1=k·s/2w(k·A)mod1=k·s/2w就是將k×sk×s整體向右平移 ww 位,此時R0R0即為小數部分
  • 再乘以 2m2m 相當於左移 mm 位,散列值h(k)h(k) 為 R0R0 的前 m 位。

乘法散列只需要單個整數乘法和右移,使其成為計算速度最快的哈希函數之一。但乘法散列可能會在變更計算因數後,較高值的輸入位不會影響較低值的輸出位,問題體現在元素分散不均,不滿足嚴格的雪崩標準。所以通常在會進行異或操作

乘法散列容易受到導致擴散不良的“常見錯誤”的影響——較高值的輸入位不會影響較低值的輸出位。在乘法步驟對此進行校正之前,輸入上的變換將保留的最高位的跨度向下移動,並將它們異或或加到鍵上。所以在輸入上的變換將保留的最高位的跨度向下移動,並將它們異或操作或者加到鍵上。例如 HashMap 的擾動函數。

3.3、斐波那契散列

其實斐波那契散列是一種特殊形式的乘法散列,只不過它的乘法因數選擇的是一個黃金分割比例值,所以叫做斐波那契散列。

斐波那契散列的特性在於將“大數映射到小數”的計算結果在表空間上是均勻分佈的,且計算滿足乘法散列效率高。

四、簡單應用

4.1、偽隨機數生成

斐波那契數列可以用於生成偽隨機數序列。雖然斐波那契數列本身不是真正的隨機數序列,但通過適當的變換和截取,可以得到具有一定隨機性的序列。

package top.emanjusaka;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        System.out.println(fibonacciRandom(5, 8));
    }

    public static List<Integer> fibonacciRandom(int seed, int length) {
        List<Integer> fibSequence = new ArrayList<>(Arrays.asList(0, 1));
        while (fibSequence.size() < seed + length) {
            int nextNumber = fibSequence.get(fibSequence.size() - 1) + fibSequence.get(fibSequence.size() - 2);
            fibSequence.add(nextNumber);
        }
        List<Integer> randomSequence = new ArrayList<>();
        for (int i = seed; i < seed + length; i++) {
            randomSequence.add(fibSequence.get(i));
        }
        return randomSequence;
    }
}

4.2、AVL 二叉樹

在AVL樹中,斐波那契數列可以用於平衡因數的調整和旋轉操作。

AVL樹是一種自平衡二叉搜索樹,它要求左右子樹的高度差不超過1,以保持樹的平衡性。當對AVL樹進行插入或刪除操作時,可能會破壞樹的平衡,這時需要對樹進行旋轉操作來恢復平衡。

在AVL樹的旋轉操作中,涉及到更新節點的高度信息。通常,節點的高度可以通過其子節點的高度來計算。而斐波那契數列正好提供了方便的計算方式。

具體應用如下:

  1. 插入操作:當在AVL樹中插入一個節點時,會導致從插入節點到根節點路徑上的某些節點的平衡因數發生變化。通過向上回溯,我們可以更新路徑上的節點的高度,並檢查它們的平衡狀態。如果某個節點的平衡因數超過了允許的範圍,就需要進行旋轉操作來恢復平衡。在這個過程中,斐波那契數列可以用於更新節點的高度信息。
  2. 刪除操作:當從AVL樹中刪除一個節點時,也會導致樹的平衡性被破壞。類似插入操作,我們需要從刪除節點的父節點向上回溯並更新節點的高度信息。如果某個節點的平衡因數超過了允許的範圍,就需要進行旋轉操作來恢復平衡。斐波那契數列可以用於更新高度信息。
  3. 旋轉操作:斐波那契數列在AVL樹的旋轉操作中扮演了重要的角色。旋轉操作包括左旋和右旋,它們通過改變樹的結構來保持平衡。在旋轉操作中,涉及到節點的高度信息的更新,而斐波那契數列可以方便地計算節點的高度。

4.3、最大公約數

斐波那契數列在最大公約數計算中有一個有趣的應用,稱為"連續整除性質"。

假設我們有兩個正整數a和b,並且a > b。如果a可以被b整除,那麼a與斐波那契數列中位於第a個位置(從1開始計數)的數具有相同的最大公約數。換句話說,gcd(a, b) = gcd(b, F(a)),其中F(n)表示斐波那契數列中第n個數。

這個性質的證明基於斐波那契數列的遞推關係和歐幾裡得演算法的原理。簡單來說,當a能夠被b整除時,可以將a表達為b的倍數加上剩餘部分,即a = qb + r,其中q是商,r是餘數。然後我們可以使用斐波那契數列的遞推關係,即F(n) = F(n-1) + F(n-2),將a和b替換為它們的等價表達式:

gcd(a, b) = gcd(qb + r, b) = gcd(b, r)

這就意味著最初的問題可以轉化為更小的問題,即求b和r的最大公約數。通過重覆應用這個性質,我們最終可以將問題簡化為求最小的b和斐波那契數列中的一個數之間的最大公約數。

這個連續整除性質可以用於計算任意兩個正整數的最大公約數,而不需要直接使用輾轉相除法。通過與斐波那契數列相關聯,它提供了一種更高效的方法來計算最大公約數。

需要註意的是,連續整除性質只適用於a > b的情況,因此在應用時需要確保a和b的大小順序。

4.4、合併排序演算法

在合併排序演算法中,斐波那契數列可以用於確定合併的子數組大小。

合併排序是一種基於分治思想的排序演算法,它將待排序的數組不斷地拆分為較小的子數組,並對這些子數組進行排序,然後再將排好序的子數組合併為一個有序數組。斐波那契數列在確定子數組大小時可以發揮作用。

具體應用如下:

  1. 確定初始子數組大小:在合併排序的初始階段,需要確定用於拆分數組的子數組大小。常規的合併排序演算法中,通常選擇固定的子數組大小(例如2)。而使用斐波那契數列則可以提供更靈活的選項。通過斐波那契數列,可以依次選擇遞增的子數組大小,使得拆分後的子數組大小趨近於黃金比例(1:1.618),以達到更好的平衡。
  2. 動態調整子數組大小:在合併排序的過程中,當兩個子數組合併時,需要確定合併後的子數組大小。傳統的合併排序中,通常是將兩個子數組完全合併為一個新的子數組。而使用斐波那契數列,則可以根據斐波那契數列的順序,選擇部分元素進行合併,以減少合併操作的次數。這樣可以降低演算法的複雜度。

斐波那契數列在合併排序演算法中的應用,主要是為了確定子數組的大小,以實現更靈活和高效的排序過程。利用斐波那契數列的特性,可以使合併排序演算法更加平衡、快速和優化。

本文原創,才疏學淺,如有紕漏,歡迎指正。如果本文對您有所幫助,歡迎點贊,並期待您的反饋交流,共同成長。

原文地址: https://www.emanjusaka.top/archives/9

微信公眾號:emanjusaka的編程棧


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 遞歸函數 含義介紹: 遞歸函數,實際上就是將一個自定義的函數在運行過程中反覆調用他自己,直到遇到結束條件就停止 案例一:求階乘 int len(int n) { if(n == 1) { return 1;//如果階乘運算到最後一位(即1),就結束迴圈 } int sum = n*len(n-1); ...
  • Python - 合併集合 在 Python 中,有幾種方法可以合併兩個或多個集合。您可以使用union()方法,該方法返回一個包含兩個集合中所有項的新集合,或使用update()方法,將一個集合中的所有項插入另一個集合中: 示例,union()方法返回一個包含兩個集合中所有項的新集合: set1 ...
  • 在資料庫處理中,Join操作是最基本且最重要的操作之一,它能將不同的表連接起來,實現對數據集的更深層次分析 ...
  • Java學習筆記二 面向對象(Object Oriented) 屬性(成員變數)跟隨對象放在堆裡面,局部變數(如 p1)放在棧裡面。只有成員變數的前面能添加許可權修飾符,且成員變數自帶預設值。 在一個類中,一個方法可以調用這個類中的其餘方法(包括自身,即遞歸)以及成員變數,不能在方法中再定義方法。 方 ...
  • 本文全面深入地探討了Go非類型安全指針,特別是在Go語言環境下的應用。從基本概念、使用場景,到潛在風險和挑戰,文章提供了一系列具體的代碼示例和最佳實踐。目的是幫助讀者在保證代碼安全和效率的同時,更加精通非類型安全指針的使用。 關註【TechLeadCloud】,分享互聯網架構、雲服務技術的全維度知識 ...
  • 一、業務場景 在多線程併發情況下,假設有兩個資料庫修改請求,為保證資料庫與redis的數據一致性,修改請求的實現中需要修改資料庫後,級聯修改Redis中的數據。 請求一:A修改資料庫數據 B修改Redis數據 請求二:C修改資料庫數據 D修改Redis數據 併發情況下就會存在A —> C —> D ...
  • 如果企業提供 IT 線上服務,那麼可觀測性能力是必不可少的。“可觀測性” 這個詞近來也越發火爆,不懂 “可觀測性” 都不好意思出門了。但是可觀測性能力的構建卻著實不易,每個企業都會用到一堆技術棧來組裝建設。比如數據收集,可能來自某個 exporter,可能來自 telegraf,可能來自 OTEL, ...
  • 1、策略模式 1.1、概述 策略模式是一種行為設計模式,它允許在運行時選擇演算法的行為。它將演算法封裝在獨立的策略類中,使得它們可以相互替換,而不影響客戶端代碼。這種模式通過將演算法的選擇從客戶端代碼中分離出來,提供了更大的靈活性和可維護性。 在Java中,策略模式的設計理念可以通過以下步驟實現: 定義一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...