溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

web算法復(fù)雜度怎么理解

發(fā)布時間:2021-12-21 10:30:39 來源:億速云 閱讀:149 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“web算法復(fù)雜度怎么理解”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

算法學(xué)(Algorithmics)是設(shè)計和研究算法的科學(xué),它的歷史可比計算機科學(xué)的歷史久遠(yuǎn)多了,但今天算法學(xué)卻幾乎全由計算機科學(xué)家實踐。

算法學(xué)是一個非常廣泛的領(lǐng)域,需要不少數(shù)學(xué)知識。當(dāng)然了,并非所有計算機科學(xué)家都需要成為天才的算法學(xué)家。從算法的角度來看,大多數(shù)程序員面臨的問題實際上非常簡單。

但我們有時需要實現(xiàn)一些更復(fù)雜的東西。在這種情況下,算法方面的基本知識就會顯得非常有用。我們并不要求你發(fā)明一種革命性的新算法并給出其復(fù)雜度的具體證明,但為了能夠準(zhǔn)確地使用那些在網(wǎng)絡(luò)上或軟件庫中找到的算法,還是有必要接受一下“基礎(chǔ)培訓(xùn)”的。

懂算法會讓你更有效率,能夠更好地理解你所要解決的問題,也不會寫出不規(guī)范的代碼:有一些代碼盡管可以正常運行,但從算法的角度來看卻是不合理的。一個經(jīng)驗不豐富的程序員可能會直接使用這些不合格的算法(他會想:“代碼能運行,所以應(yīng)該沒什么問題”),但你因為懂算法,就能很快發(fā)現(xiàn)代碼的問題,并改寫出一個優(yōu)秀得多的版本。

聽我說了這些,你可能有點躍躍欲試了。下面是兩個簡單的對于算法復(fù)雜度的研究題,它們可以讓你更準(zhǔn)確地了解算法復(fù)雜度的作用。

尋找最大和最小的元素


問題 1:有一個正整數(shù)列表,我們想要找到列表中最大的整數(shù)。

這個問題的經(jīng)典解法如下:遍歷此列表,并一直保存迄今為止發(fā)現(xiàn)的最大元素,稱其為“當(dāng)前最大值”。

我們可以將此算法描述為:

一開始,“當(dāng)前最大值”等于 0。我們用列表中每一個元素去和“當(dāng)前最大值”做比較,如果當(dāng)前遍歷到的元素比“當(dāng)前最大值”更大,則將“當(dāng)前最大值”設(shè)為當(dāng)前元素的值。在遍歷完整個列表后,“當(dāng)前最大值”就真的“實至名歸”了。

下面我們給出此算法的一種實現(xiàn),是用“世界上最好的編程語言” PHP 來實現(xiàn)的(當(dāng)然,你也可以用其他編程語言來實現(xiàn)):

<?php
function max($list) {
  $current_max = 0;
  foreach ($list as $item)
      if ($item > $current_max)
          $current_max = $item;
  return $current_max;
}
?>

我們可以快速驗證此算法是正確的:我們只需要確認(rèn)在此算法執(zhí)行時,“當(dāng)前最大值”總是等于到目前為止所遍歷到的列表元素里最大的那個值。

我們也注意到此算法是會“結(jié)束”的,它不會陷入無限循環(huán):此算法遍歷完整個列表,然后停止。這看起來像一個不重要的細(xì)節(jié),但實際上有一些編程語言里是可以表示無限多元素的列表的:在這種情況下,我們的算法是不正確的。

現(xiàn)在讓我們研究此算法的復(fù)雜度。我們要考慮哪些操作呢?顯然,大部分工作都在于將當(dāng)前元素與“當(dāng)前最大值”進行比較(畢竟,“當(dāng)前最大值” current_max 的初始化(初始化為 0)并不占多少運行時間),因此我們計算“比較操作”的次數(shù),將其作為此算法的操作數(shù)。

算法的執(zhí)行時間取決于哪些參數(shù)呢?可以想見,執(zhí)行時間并不依賴于列表中每個元素的值(在此,我們假設(shè)兩個整數(shù)的比較時間是恒定的,不論它們的值是多少)。因此,我們用元素列表的長度 N 來量化輸入。

對于一個包含 N 個元素的列表,我們要進行 N 次比較:每個元素都與“當(dāng)前最大值”進行一次比較。因此,算法的時間復(fù)雜度是 O(N):它的執(zhí)行時間是呈線性的,與列表的元素數(shù)目 N 成正比。

那么,此算法的空間復(fù)雜度是多少呢?此算法使用了一個列表,里面的元素占用了一定的內(nèi)存空間。但是,這個列表在我們查找其最大元素之前就已經(jīng)存在了,它所占用的內(nèi)存空間并不是由我們的算法分配的,因此我們說此列表的元素數(shù)目 N 并不會被考慮到算法的空間復(fù)雜度的計算中,我們只考慮由我們的算法直接申請的內(nèi)存。

而我們的算法直接申請的內(nèi)存空間幾乎可以忽略不計,因為最多就是占用了一個臨時變量(current_max),用以存儲“當(dāng)前最大值”。因此,我們的算法所占用的內(nèi)存空間不依賴于列表的長度: (我們將空間復(fù)雜度記為 O(1),表示它不依賴于 N)。

對于我們的算法,現(xiàn)在只剩下一個小細(xì)節(jié)要注意了:如果我們的列表是空的,那么返回的最大值將是 0。要說“一個空的列表的最大值是 0” 顯然不一定是正確的:在某些情況下,如果列表是空的,最好返回一個錯誤。

因此我們可以改進一下我們的算法:我們不再為“當(dāng)前最大值”賦初值為 0,而是以列表的第一個元素(如果該列表為空,則返回一個錯誤)作為“當(dāng)前最大值”的初始值。然后,我們從第二個元素開始比較。

經(jīng)過改進后的算法執(zhí)行 N-1 次比較(因為我們不必將第一個元素與它自己進行比較)。不過,這并沒有改變算法的時間復(fù)雜度:N 和 N-1 之間的時間差并不依賴于 N,它是恒定的,因此我們可以忽略它:兩種算法具有相同的時間復(fù)雜度,它們都是時間線性的(時間復(fù)雜度是 O(N) )。

最后,我們注意到第二個算法也適用于負(fù)數(shù)(如果列表的所有元素都是負(fù)數(shù),第一個算法會返回 0,這顯然不正確)。因此改良后的第二個算法更通用,也更好。

當(dāng)然了,查找列表中最小值的算法和查找最大值是類似的,我們就不贅述了。

尋找不重復(fù)的元素


現(xiàn)在我們來看第 2 個問題。

問題 2:有一個列表 1,其中包含重復(fù)項(多次出現(xiàn)的元素):我們想要構(gòu)建一個包含與列表 1 相同元素的列表 2,但是列表 2 中每個元素只重復(fù)出現(xiàn)一次。

例如,列表 1 里有以下元素:

AABCDBCA

則列表 2 將包含以下元素:

ABCD

你想到解決這個問題的算法了嗎?在閱讀我的解決方案之前,請自己思考一下。

我的解決方案

我的算法如下:

對于給定的包含重復(fù)元素的列表 L,我們要構(gòu)建一個新的列表 U(取英語 Unique(“獨一無二的”)的第一個字母),列表 U 一開始是空的,我們需要往里面填充元素。我們遍歷列表 L,對于列表 L 中的每一個元素,我們確認(rèn)一下它是否存在于列表 U 中(可以用與之前的查找最大元素類似的算法,畢竟就是逐一比較元素嘛)。如果列表 L 中遍歷到的元素還不在列表 U 中,就將這個元素添加進列表 U 中;如果已經(jīng)存在于列表 U 中,就不添加。遍歷完列表 L 后,列表 U 中就擁有了和列表 L 相同的元素,只是這些元素都是不重復(fù)出現(xiàn)的。


練習(xí): 使用你喜歡的編程語言來實現(xiàn)上述從列表中提取不重復(fù)元素的算法。

復(fù)雜度

這個算法的復(fù)雜度是多少?如果你充分理解了之前查找列表最大值的算法的復(fù)雜度的計算,那么這對你來說應(yīng)該很簡單。

對于給定列表 L 中的每個元素,我們都會執(zhí)行遍歷列表 U 的操作,因此執(zhí)行的操作數(shù)與列表 U 包含的元素數(shù)目有關(guān)。

但問題是:列表 U 的大小在遍歷給定列表 L 的過程中會發(fā)生變化,因為我們會添加元素進列表 U。當(dāng)我們遍歷到列表 L 中的第一個元素時,列表 U 還是空的(因此我們不執(zhí)行任何比較操作);當(dāng)我們遍歷到列表 L 的第二個元素時,列表 U 有 1 個元素,所以我們要再執(zhí)行一個比較操作。

但是當(dāng)我們遍歷到列表 L 中的第三個元素時,我們就變得不是那么肯定了:如果列表 L 中的前兩個元素是不相同的,它們都被添加到 U 中,在這種情況下我們要執(zhí)行 2 次比較操作(將列表 L 中的第三個元素分別與列表 U 中的兩個元素作比較);如果前兩個元素是相同的,那么列表 L 中的第二個元素就沒有被添加到列表 U 中,只執(zhí)行 1 次比較操作。

正如我們的課程里已經(jīng)說過的,復(fù)雜度的計算需要考慮在“最壞的情況”(worst case)下:也就是執(zhí)行的操作數(shù)目最多時的復(fù)雜度。因此,我們將認(rèn)為給定列表 L 的所有元素都是不相同的。

在“最壞的情況”下,我們將給定列表 L 的所有元素逐一添加進列表 U 中。假設(shè)給定列表 L 一共有 N 個元素,在遍歷到給定列表 L 的第 N 個元素時,我們已經(jīng)向列表 U 添加了 (N-1) 個元素了,因此這時要做 (N-1) 次比較操作。

所以我們總共要做的比較操作數(shù)是 0 + 1 + 2 + … + (N-1) 。開始時的操作數(shù)少,越到后面做的操作越多(有點像人生,出生時責(zé)任比較少,慢慢地責(zé)任越來越大,要處理的事情也越來越多,不過也說明你在成長,畢竟“能者多勞”)。

上面這一串?dāng)?shù)字相加,得到的總操作數(shù)是 N * (N - 1) / 2(這個不難,是數(shù)學(xué)里面的等差數(shù)列求和公式),由于我們在計算復(fù)雜度時考慮的是 N 很大的情況,上面的結(jié)果可以約等于 N * N / 2,即 N2 / 2 個操作。

因此,我們的算法具有 O(N2) 的時間復(fù)雜度(我們?nèi)コ顺?shù)因子 1/2)。我們也可以稱 O(N2) 為“二次/平方”的復(fù)雜度(正如我們稱 O(N) 具有“線性”的復(fù)雜度)。

與之前那個查找最大元素的算法比起來,現(xiàn)在這個算法除了速度較慢(時間復(fù)雜度較高)之外,還具有更高的空間復(fù)雜度:我們構(gòu)建了一個最初不存在的列表 U(因此申請了內(nèi)存空間)。

在最壞的情況下,列表 U 還具有與給定列表 L 一樣多的元素:因此將為 N 個元素分配空間,這使得空間復(fù)雜度為 O(N)。之前查找最大元素的算法的空間復(fù)雜度是恒定的(O(1)),但現(xiàn)在這個算法的空間復(fù)雜度卻是線性的(O(N))。

該算法只需要比較元素,因此被操作的元素并不一定要是整數(shù):我們可以用相同的算法來消除單詞列表中重復(fù)的單詞,重復(fù)的浮點數(shù),等等。因此,許多算法是與使用的元素的具體類型無關(guān)的。

尋找不重復(fù)的元素:另一種方法


尋找不重復(fù)的元素,其實還有另一種算法(聰明如你可能也想到了):我們可以先對給定列表 L 中的元素進行排序,使得所有重復(fù)的元素都相鄰,這樣排除重復(fù)元素將變得很簡單。

比如給定列表 L 初始是這樣的:

AABCDBCA

我們可以在構(gòu)建列表 U 前,先對列表 L 進行排序,使其變成下面這樣:

AAABBCCD

這樣,我們之后構(gòu)建列表 U 的算法就簡單了。

算法如下:只需遍歷排序后的列表 L,并記住最近一次遍歷到的那個元素。如果當(dāng)前元素與前一個元素相同,則這個元素是重復(fù)的,就不要把它包含在不重復(fù)元素的列表 U 中。

如果重復(fù)的元素彼此不相鄰,則上述算法不再有效。因此我們必須先對列表進行排序。

這個新的算法的時間復(fù)雜度是什么?消除重復(fù)是在列表的單次遍歷中完成的,因此是線性的( O(N))。但由于我們必須先對列表進行排序,因此第一步排序的操作也必須被考慮進這種新算法的總復(fù)雜度中。

當(dāng)然了,在這里提到列表的排序還稍微有一些太早了,因為我們在之后的課程里才會講到排序算法。

盡管目前我們還沒有學(xué)習(xí)排序算法和它們的復(fù)雜度,但我還是想說一下這個新算法的復(fù)雜度問題。

事實證明,這種算法的復(fù)雜度取決于排序的復(fù)雜度:因為,排序基本上會執(zhí)行 N2 個操作,這遠(yuǎn)遠(yuǎn)超過我們之后的構(gòu)建列表 U 時的 N 個操作,所以整體復(fù)雜度是 O(N2)。

然而,也存在更高端的排序算法,雖然仍然執(zhí)行多于 N 個操作,但比 N2 要少得多。

我們將在之后的課程里學(xué)習(xí)排序算法,目前你只需要知道這個多了一步排序的新算法比舊算法更有效,也更“高級”。

“在列表中搜索指定元素”與“找出列表中最大/小值的元素”是非常相似的算法,都是線性時間的(算法的時間復(fù)雜度是 O(N)),空間復(fù)雜度都是 O(1)。

消除列表中的重復(fù)元素的算法更復(fù)雜一些,因為最簡單的算法在時間上具有平方的時間復(fù)雜度(O(N2)),其空間復(fù)雜度具有線性(O(N))。

我希望這些更具體的研究能讓你確信算法學(xué)和算法復(fù)雜度還是很有用的?,F(xiàn)在你也應(yīng)該已經(jīng)習(xí)慣“算法”,“時間復(fù)雜度”,“空間復(fù)雜度”這些基本概念了。

“web算法復(fù)雜度怎么理解”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

web
AI