演算法初探--遞迴演算法

joker丶牧羊人發表於2018-10-30
【本文概要和說明】
1、簡要說明遞迴演算法
2、例項說明和演示

(本文采用 PHP 語言在CI框架下進行編寫和說明)
【⚠️:文中使用的表述和說明,僅代表個人觀點和理解來書寫,非正式官方解釋】
複製程式碼

一、什麼是遞迴演算法

遞迴:就是指函式呼叫自身的方法。

二、理解和注意事項(要素)

理解:
呼叫自身,其實就是說邏輯和最外層的函式實現是一樣的,我們可以理解為在外層函式執行到某一點時,邏輯就會和外層函式一樣,即:每一次呼叫都是將大問題化解成規模較小的問題進行解決。
我們的使用遞迴的目的是為了實現某個功能,所以我們應該有停止遞迴的條件,然後將遞迴結果返回作為功能實現的資料資訊,我們就需要有一個條件可以停止遞迴,停止之後需要根據功能的需求做對應的邏輯處理。

要素:
1、需要提取出重複的邏輯,為遞迴做好準備。
2、需要一個停止遞迴的條件節點,防止無限遞迴。
3、需要給出停止遞迴後的實現方式,根據需求結果而定。

三、例項說明

1、我們先用幾個簡單的例子理解一下遞迴。

案例一:求 n 的階乘
分析:我們知道階乘的表示式為 n! = 1 * 2 * 3 * ... * n

我們先以 5 的階乘為例:
1! = 1 --------------------------- 1 --------- 1
2! = 2 * 1 ------------------------ 2 * 1! ----- 2 * (2 - 1)!
3! = 3 * 2 * 1 --------------------- 3 * 2! ----- 3 * (3 - 1)!
4! = 4 * 3 * 2 * 1 ------------------ 4 * 3! ----- 4 * (4 - 1)!
5! = 5 * 4 * 3 * 2 * 1 --------------- 5 * 4! ----- 5 * (5 - 1)!
... ... ... ... ... ... ... ... ...
n! = n * (n - 1)!

我們用常規方法實現階乘,程式碼如下:

public function factorial_normal($num)
{
    $n = 1;
    $result = 1;
    while($n <= $num){
        $result *= $n;
        $n ++;
    }

    return $result;
}
複製程式碼

我們用遞迴方式實現階乘,程式碼如下:

public function factorial_recursive($num)
{
    if($num == 1)
    {
        return 1;
    }

    $result = $num * $this->factorial_recursive($num - 1);
    return $result;
}
複製程式碼

案例二:給定一個關鍵字,將陣列中包含該關鍵字的 key 對應的 value 前都加上一個標記 ‘Mark:’。

// 遍歷陣列,找出給定陣列中所有指定 key 的值,並新增 Mark 標記
public function deepLoop(&$arr, $keyword = '')
{
    // 設定匹配正規表示式
    $reg = "/" . $keyword . "/i";

    // 判斷陣列和關鍵字的有效性
    if( ! is_array($arr) || $keyword == '' || $keyword == null)
    {
        return $arr;
    }

    // 迴圈陣列,找出指定的 key, 並給對應的值加上 Mark 標記
    foreach($arr as $key => $value)
    {
        if(is_array($value))
        {
            $this->deepLoop($value, $keyword);
        }
        else
        {
            if(preg_match($reg, $key))
            {
                $value = 'Mark: ' . strval($value);
            }
        }

        $arr[$key] = $value;
    }

    return $arr;
}
複製程式碼

除錯(我們執行 $this->deepLoop($userInfo, 'name');):
我們首先使用一維陣列:

$userInfo = [
    'userName' => 'user1',
    'userAge' => 18,
    'testName' => 'user test name'
];
複製程式碼

執行截圖:

演算法初探--遞迴演算法

多維陣列:

$userInfo = [
    'userName' => 'user1',
    'userAge' => 18,
    'testName' => 'user test name',
    'child' => [
        'userName' => 'user1',
        'userAge' => 18,
        'testName' => 'user test name',
        'child' => [
            [
                'userName' => 'user1',
                'userAge' => 18,
                'testName' => 'user test name'
            ],
            [
                'userName' => 'user1',
                'userAge' => 18,
                'testName' => 'user test name'
            ]
        ]
    ]
];
複製程式碼

執行截圖:

演算法初探--遞迴演算法

案例三:列印出指定路徑下的目錄結構
分析:
1、我們首先需要知道該目錄下有些什麼東西(資料夾和檔案)
2、要對目錄下的東西進行分類處理

實現程式碼:

public function dirLoop($path, &$treeData = [])
{
    // 判斷給定的 path 是否是一個正確的路徑
    if( ! is_dir($path))
    {
        return $path;
    }

    $docList = scandir($path);

    $reg = '/^\.[\w]+$/';
    foreach($docList as $key => $doc)
    {
        if($doc == '.' || $doc == '..' || preg_match($reg, $doc))
        {
            continue;
        }
        else
        {
            $newPath = $path . '/' . $doc;
            if(is_dir($newPath))
            {
                $treeData[$path][$newPath] = [];
                $this->dirLoop($newPath, $treeData[$path]);
            }
            else
            {
                $treeData[$path][$newPath] = 'f';
            }
        }
    }

    return $treeData;
}
複製程式碼

執行截圖:

演算法初探--遞迴演算法

最後的返回處理需要根據自己的需求進行返回。

【如若文件有錯誤,歡迎大家不吝賜教。如果發現有侵權等行為,請聯絡我,我將對應處理,謝謝~~~】

相關文章