演算法系列 演算法入門之遞迴分而治之思想的實現

2022-08-05 17:36:14 字數 3307 閱讀 7903

別想太多,肯定要!!!

你以為的演算法是各種排序,選擇排序、快速排序、歸併排序,廣深搜尋、動態規劃......

然而,演算法實際上指的是解決某個實際問題的方法。

解決同乙個問題的方法有很多,比如迴圈輸出某個陣列,可以有for、for in、for of、map、foreach等,不同的實現方法會反映不同的效能,這些效能通常用執行時間來表示,執行時間越短,效能越好,目前我可以告訴你的是,上面的幾個迴圈中,原生for迴圈的效能是最好的。

下面講的都是非常非常非常非常簡單的演算法知識!!你千萬不要害怕!!

陣列陣列是演算法中最常用到的資料結構,給你一串陣列,你能很快的根據索引找到那個元素。

你或許知道時間複雜度o(n),我們叫他大o表示法,這是大寫字母o,不是數字0,別搞錯了。通常大o表示的是演算法的最差情況。

陣列o(時間複雜度)

讀取o(1)

寫入o(n)

刪除o(n)

陣列的大o很好理解,讀取的時候,最壞情況就是1次,因為陣列是記憶體上連續的位址(計算機的知識),可以直接根據位址(索引)找到那個元素。

寫入的時候,如果是在陣列的末尾push新的元素,那麼前面已有的元素位址不需要改變,但是如果是在陣列的頭部push新的元素,那麼所有已有的元素的位址都要加1,即需要移動n個元素,所以大o是n。

刪除操作時,和插入一樣,最好的情況是刪除末尾的元素,複雜度就是1,最壞的情況是刪除第乙個元素,所有剩下的元素都需要位址減1,即需要移動n次。

或許你會發現上面有點不對勁,在刪除的時候,不是移動 n-1 個元素嗎?其實這就是要知道的大o表示法只是描述次數和資料量的線性關係,我們關注的是線性變化的規律,不在乎那一點點影響。

鍊錶鍊錶比較複雜,我們這裡只關心鍊錶的一些特點。

鍊錶和陣列一樣,通常也存在記憶體中,鍊錶可以存在記憶體的任何地方,它不一定是連續的。這句話你可能不太理解。舉個例子,假設你有的記憶體條有8g,這8g可能被分配給多個應用程式,你建立了乙個陣列,長度是10,那麼,系統會分配10個連續的記憶體位址給你使用。而鍊錶呢,假設你有10個資料,可以通過鍊錶插入到記憶體的空餘位址位置,中間可能被其他資料隔開。類似於插班生來到了你們班,插入了任意乙個空位裡面。

鍊錶還有乙個重要的特性就是他的讀取必須是從頭開始遍歷,因為只有當前的元素位置才有下乙個元素的指標!!你不能直接讀取第n個元素!

鍊錶o(時間複雜度)

讀取o(n)

寫入o(1)

刪除o(1)

你會發現鍊錶的讀取大o是n,也就是說最壞的情況下,如果那個需要讀取的元素剛好在鍊錶的最末尾,那麼,你就需要遍歷整個鍊錶。

寫入和刪除都是o(1),這和鍊錶的特點有關,你可以在任意乙個指標寫入新的元素和刪除鍊錶的元素,而只需要將前乙個元素的指標指向新的元素或者下乙個元素即可。鍊錶沒有位址的概念,所以不需要移動位址。

形象表達記憶體中陣列和鍊錶的特點

上面的文字你覺得抽象的話,可以看下面的**,假設這一段記憶體條,上面一共有8個記憶體位址,現在都是空餘的,當你建立乙個長度為2的陣列時 new array(2),系統會分配2個記憶體位址給陣列,可能是位址0,1。然後繼續建立乙個長度為1的陣列 new array(1),系統會分配1個記憶體位址給陣列,假設是位址4,現在整個記憶體被2個陣列給分割開來了,單個陣列的記憶體一定是連續的,不同的陣列之間不需要連續。

這時候,你再建立乙個鍊錶,有3個元素,現在位址2、3、5、6、7都是空閒的,假設鍊錶的第乙個元素是2,那麼下乙個元素可以指向任意乙個空閒的位址,比如3,到位址3的時候,位址4已經有陣列的元素在占用了,不用擔心,鍊錶可以將指標指向位址5,這樣鍊錶的第三個元素就儲存在位址5上面了。

這樣你是不是更加清晰的理解了陣列和鍊錶的基本特點了。01

2345

67組合型資料結構

陣列和鍊錶也可以組合起來成為一種複合型的資料結構,稱為「鏈組結構」,不是戀父、不是戀母,而是鏈組!

作為前端,實際上只需要考慮和陣列相關的基本演算法就行了,還有就是各種效能提公升的訣竅。

我向演算法工程師請教如何學好演算法,他跟我提議說先看懂漢諾塔,這是乙個小朋友都會玩的遊戲,裡面用到了遞迴的思想。但是我在這裡不說漢諾塔,而是從遞迴的簡單實現入手。

以前我也寫過遞迴的文章,es6中也有尾遞迴優化的介紹。但遞迴的思想不只是應用在階乘演算法中,還有各種場景需要遞迴,特別是在函式式程式設計中,遞迴的地位顯得越發的重要。

遞迴實現倒計時函式

下面這個倒計時函式使用了遞迴,而且使用了尾遞迴優化。你或許不了解尾遞迴優化,我想你可以去看一下 尾遞迴優化特點

function countdown(i) , 1000)

}countdown(10)

遞迴實現階乘

階乘是什麼?n!表示 1x2x3x...xn

function t(i, s=1) 

const s = t(5)

console.log(s)

遞迴之分而治之思想實現陣列元素求和

需求是這樣的,假設你有乙個數字組成的陣列,現在你需要寫乙個函式求所有元素的和,比如[2, 4, 6]。

這裡不單單是遞迴的思想,還有一種思想叫做分而治之,分而治之的思想分為2個步驟,一是找出基線條件。二是每次呼叫遞迴都離基線條件更近一步。

那麼陣列[2, 4, 6]的基線條件是什麼呢?其實它就是乙個臨界情況,比如當陣列元素為空時,或者陣列只剩乙個元素時[2]。這個基線有什麼作用呢?當遞迴達到基線時,就返回結果,不再遞迴。

下面的**實際上是根據這樣乙個步驟去執行的,[2, 4] + 6 => [2] + 4 + 6 => 2 + 4 + 6,通過陣列不斷的拆分和求和,直至陣列達到基線條件,這時候將相加的和返回。

未尾遞迴優化

function add_1(arr, len=arr.length, sum=arr[len-1]) 

const r = add_1([2, 4, 6])

console.log(r) // 12

尾遞迴優化

function add_2(arr, len=arr.length, sum=arr[len-1]) 

const p = add_2([2, 4, 6])

console.log(p) //12

學習演算法是乙個漫長的過程,第一次學網頁設計的時候,div都學習了大半年才搞懂什麼玩意,後來css的學習時間更長,js的學習從開始到現在始終在進行著,正則的學習一開始也是很痛苦,最後,輪到了演算法,只有像以前學習前端知識那樣堅持下去,才能學好演算法!!

經典演算法系列之 遞迴

1 前言 演算法,在計算機中的地位,就相當於人類大腦的決策中樞系統,哪怕最簡單的演算法,其精妙的思維方式,都可以讓人開啟一扇新的視窗。演算法,它不僅僅只是狹義的用來解決電腦科學領域的問題,更是一種 思維方式 演算法思維,是一種深度思考和創造的過程。演算法,只有真正理解了,而不只是所謂的知道,並將應用...

C 演算法系列之排序

插入排序 o n2 基本思路就是玩撲克牌的時候,從牌堆裡摸牌放到手上的思路 include include include include include include const int m 1000 const int n 1000 template void insertsort const...

趣學演算法系列 演算法之美

宣告 本系列為趣學演算法一書學習總結內容,在此推薦大家看這本演算法書籍作為演算法入門,原作者部落格鏈結,本書暫無免費電子版資源,請大家支援正版 書籍簡介 本書內容按照演算法策略分為7章。第1章從演算法之美 簡單小問題 趣味故事引入演算法概念 時間複雜度 空間複雜度的概念和計算方法,以及演算法設計的 ...