大話數據結構系列之算法初探(二)

算法定義

算法是解決特定問題求解步驟的描述,在計算機中表現爲指令的有限序列,並且每條指令表示一個或多個操作


算法的特性

輸入與輸出

  • 算法具有零個或多個輸入
  • 算法至少有一個或多個輸出

有窮性

指算法在執行有限的步驟之後,自動結束而不會出現無限循環,並且每一個步驟在可接受的時間內完成

確定性

算法的每一步驟都具有確定的含義,不會出現二義性

可行性

算法的每一步都是可行的,也就是說,每一步驟都能夠通過執行有限次數完成
(備註:特爲解釋,目前計算機界也存在那種沒有實現的極爲複雜的算法,只是限於當前的編程方法、工具和大腦的限制,只存在於理論中)


算法設計的要求

廣義正確性

指算法的輸入至少應該具有輸入、輸出和加工處理無歧義性、能正確反映問題的需求、能夠得到問題的正確答案

狹義正確性(遞增)

  • 算法程序沒有語法錯誤
  • 算法程序對於合法的輸入數據能夠產生滿足要求的輸出結果
  • 算法程序對於非法的輸入數據能夠得出滿足規格說明的結果
  • 算法程序對於精心選擇的,甚至刁難的測試數據都有滿足要求的輸出結果
    備註:一般以第三階段作爲依據標準

可讀性

算法設計的另一目的是爲了便於閱讀、理解和交流
可讀性高有助於人們理解算法、晦澀難懂的算法往往隱含錯誤,不易被發現,並且難於調試和修改

健壯性

當輸入數據不合法時,算法也能做出相關處理,而不是產生異常或莫名其妙的結果

時間效率高和存儲量低

儘量滿足時間效率高和存儲低的需求(在21世紀的一般情況下,都是通過空間來換時間)
人們都希望花最少的錢,用最短的時間,辦最大的事兒,算法也一樣。


算法效率的度量方法

事後統計法

定義:主要通過設計好的測試程序和數據,利用計算機計時器對不同算法編制的程序的運行時間進行比較,從而確定算法效率的高低

缺陷:

  • 時間的比較依賴計算機硬件和軟件等環境因素,有時會掩蓋算法本身的優劣
    舉例:現在一臺四核處理器的計算機,跟當年的286,等機器相比,在處理算法的運算速度上,是不能相提並論的
  • 所用的操作系統、編譯器、運行框架等軟件的不同
  • 同一臺機器,CPU使用率和內存佔用情況不一樣
  • 算法的測試數據設計困難,並且程序的運行時間往往與測試數據的規模有很大關係,我們以什麼規模的測試數據進行比較算法的優劣亦是問題

結論:基於以上缺陷,我們不予採納。
原文寫於 2011-6,隨着時代的進步,之前不好實現的點,現在可能已經實現。且現階段的很多項目在上線前需要預估該程序的伸縮性, 顧補充以下方法可以作爲相應借鑑

JOL
1、官網:–http://openjdk.java.net/projects/code-tools/jol/
定位:分析對象在JVM的大小和分佈

2、對比:
人工可以按照Java基礎數據類型大小及內容大小估算出緩存對象的大概堆佔用,但是麻煩還不準。
OpenJDK,提供了JOL包,可以幫我們在運行時計算某個對象的大小,是非常好的工具

JJMH(Java基準測試工具套件)

參考資料:–http://irfen.me/java-jmh-simple-microbenchmark/

1、什麼是JMH
MH 是 Java Microbenchmark Harness 的縮寫。中文意思大致是 “JAVA 微基準測試套件”。基準測試是指通過設計科學的測試方法、測試工具和測試系統,實現對一類測試對象的某項性能指標進行定量的和可對比的測試。

2、爲什麼要用JMH
在實際開發中,大多都是用main自己寫一個demo進行測試,但是這種測試方式是不科學的,尤其是在對比方法的效率時會存在很大的誤差,和當時的運行環境和執行條件有很大的影響。而使用JMH就可避免此類問題,JMH可以設置預執行,預執行的結果不記錄最終結果,只是爲了運行環境更穩當,然後再執行n次取其平均時間,保證了測試結果的準確性。

3、JMH典型的運用場景
想準確的知道某個方法需要執行多長時間,以及執行時間和輸入之間的相關性;
對比接口不同實現在給定條件下的吞吐量;
查看多少百分比的請求在多長時間內完成;

待實踐:非常好用的計算耗時的工具類—— org.apache.commons.lang.time.DurationFormatUtils.java
待補充:實際使用方式後續提供

事前分析估算方法

定義:在計算機程序編制前,依據統計方法對算法進行估算
影響因素
1、算法採用的策略、方法
2、編譯產生的代碼質量
3、問題的輸入規模
4、機器執行指令的速度

分析
拋開計算機硬件、軟件有關的因素,一個程序的運行時間,依賴於 算法的好壞問題的輸入規模,具體推導請繼續往下。

函數的漸進增長
給定兩個函數 f(n) 和 g(n),如果存在一個整數 N,使得對於所有的 n > N,f(n) 總是比 g(n) 大,那麼,我們說 f(n) 的增長漸進快於 g(n)。
人話
某個算法,隨着 n 的增大,它會越來越優於另一算法,或者越來越差於另一算法。
備註:一般使用漸進增長概念爲標準,來判斷算法的優劣性


算法時間複雜度

定義
在進行算法分析時,語句總的執行次數 T(n) 是關於問題規模 n 的函數,進而分析 T(n) 隨 n 的變化情況並確定 T(n) 的數量級。算法的時間複雜度,也就是算法的時間亮度,記作:T(n) = O(f(n))。它表示隨問題規模 n 的增大,算法執行時間的增長率和 f(n) 的增長率相同,稱作算法的漸近時間複雜度,簡稱爲時間複雜度。其中 f(n) 是問題規模 n 的某個函數。

曲線圖
在這裏插入圖片描述

推導大O階方法

  • 用常數 1 取代運行時間中的所有加法常數。
  • 在修改後的運行次數函數中,只保留最高階項。
  • 如果最高階項存在且不是 1,則去除與這個項相乘的常數。
  • 得到的結果就是大 O 階(具體方法見網上衆多基礎推導)

相關定義
對數:
如果a的x次方等於N(a>0,且a不等於1),那麼數x叫做以a爲底N的對數(logarithm),記作x=logaN。其中,a叫做對數的底數,N叫做真數。
二分法的對數推導

等差數列:
等差數列是指從第二項起,每一項與它的前一項的差等於同一個常數的一種數列,常用A、P表示。這個常數叫做等差數列的公差,公差常用字母d表示。 [1]
例如:1,3,5,7,9……2n-1。通項公式爲:an=a1+(n-1)d。首項a1=1,公差d=2。前n項和公式爲:Sn=a1n+[n*(n-1)d]/2或Sn=[n(a1+an)]/2。注意:以上n均屬於正整數。


常見的時間複雜度

展示:O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)//2的n方<O(n!)<O(n^n)//n的n方

分析

  • O(logn)<O(n)
    再比如O(logn),當數據增大n倍時,耗時增大logn倍(這裏的log是以2爲底的,比如,當數據增大256倍時,耗時只增大8倍,是比線性還要低的時間複雜度)。
    二分查找 O(logn)的算法,每找一次排除一半的可能,256個數據中查找只要找8次就可以找到目標。

  • O(n)<O(nlogn)
    O(nlogn)同理,就是n乘以logn,當數據增大256倍時,耗時增大256*8=2048倍。這個複雜度高於線性低於平方。歸併排序就是O(nlogn)的時間複雜度。

  • O(n)<O(n^2)
    再比如時間複雜度O(n^2),就代表數據量增大n倍時,耗時增大n的平方倍,這是比線性更高的時間複雜度。
    比如冒泡排序,就是典型的O(n^2)的算法,對n個數排序,需要掃描n×n次。

  • O(n!)的含義待定


最壞情況與平均情況

最壞情況:是運行時間的一種保證,就是運行時間不會再壞了。

平均情況:是所有情況中最有意義的,因爲它是期望的運行時間

備註:在計算時間複雜度時,一般都指最壞情況


算法空間複雜度

算法的空間複雜度通過計算算法所需的存儲空間實現,算法空間複雜度的計算公式記作:S(n) = O(f(n)),其中,n 爲問題的規模,f(n) 爲語句關於 n 所佔存儲空間的函數。
我們在寫代碼時,完全可以用空間來換取時間

發佈了240 篇原創文章 · 獲贊 91 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章