在計算機科學中,算法的時間複雜度是一個函數,他定性描述該算法的運行時間。這是一個代表算法輸入值的字符串的長度函數。時間複雜度常用大符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,亦即考察輸入值大小趨近無窮時的情況。
常數時間
若對於一個算法,的上界與輸入大小無關,則稱其具有常數時間,記作時間。一個例子是訪問數組中的單個元素,因爲訪問它只需要一條指令。但是,找到無序數組中的最小元素則不是,因爲這需要遍歷所有元素來找出最小值。這是一項線性時間的操作,或稱爲時間。如果預先知道元素的數量並假設數量保持不變,則改操作也可以稱爲具有常數時間。
雖然被稱爲“常數時間”,運行時間本身並不必須與問題規模無關,但它的上界必須是與問題規模無關的確定值。舉例,“如果a>b則交換a、b的值”這項操作,儘管具體時間會取決於條件“a>b”是否滿足,但它依然是常數時間,因爲存在一個常量t使得所需時間不超過t。
以下是一個常數時間的代碼片段:
int index = 5;
int item = list[index];
if (condition){
// 固定時間操作
fun1_fixed_time()
}
else{
// 不固定時間的操作
fun2_not_fixed_time()
}
for i = 1 to 100
for j = 1 to 200
{
// 固定時間操作
fun2_fixed_time()
}
如果,其中c是一個常數,這記法等價於標準記法。
對數時間
若算法的,則稱其具有對數時間。計算機使用二進制的計數系統,對數常常以2爲底(即,有時寫作)。然而,由對數的換底公式,和只有一個常數因子不同,這個因子在大記法中被丟失。因此記作,而不論對數的底是多少,是對數時間算法的標準記法。
常見的具體對數時間的算法有二叉樹的相關操作和二分搜索。
對數時間的算法非常有效的,因爲每增加一個輸入,其所需的額外計算時間會變小。
遞歸地將字符串砍半並且輸出是這個類別函數的一個簡單例子。它需要的時間因爲每次輸出之前我們都將字符串砍半。這意味着,如果我們想增加輸出次數,我們需要將字符串長度加倍。
// 遞歸輸出一個字符串的右半部分
var right = function(str)
{
var length = str.length;
// 輔助函數
var help = function(index)
{
// 遞歸情況:輸出右半部分
if(index < length){
// 輸出從index到數組末尾的部分
console.log(str.substring(index, length));
// 遞歸調用:調用輔助函數,將右半部分作爲參數傳入
help(Math.ceil((length + index)/2));
}
// 基本情況:什麼也不做
}
help(0);
}
冪對數時間
對於某個常數k,若算法的,則稱其具有冪對數時間。例如,矩陣鏈排序可以通過一個PRAM模型在冪對數時間內解決。
PRAM模型:它假設有對其容量大小沒有限制的一個共享存儲器,並且有多個功能相同的處理器,在任意時刻處理器可以訪問共享存儲單元。
次線性時間
對於一個算法,若其符合,則其時間複雜度爲次線性時間。實際上除了符合以上定義的算法,其他一些算法也擁有次線性時間的算法複雜度。例如有的Grover算法(葛羅佛算法)。
常見的非合次線性時間算法都採用了諸如平行處理、非古典處理,又或者選擇性地對有保證的輸入結構做出假設。不過,一般情況,例如在頭比特中每個字符串有一個比特作爲索引的字符串組就可能依賴輸入的每個比特,但又符合次線性時間的條件。
“次線性時間算法”通常指那些不符合前一段的描述的算法。它們通常運行於傳統電腦架構系列並且不容許任何對輸入的事先假設。但是它們可以是隨機化算法,並且必須是真隨機算法除了特殊情況。
線性時間
如果一個算法的時間複雜度爲,則稱這個算法具有線性時間,或時間。非正式地說,這意味着對於足夠大的輸入,運行時間增加的大小與輸入成線性關係。例如,一個計算列表所有元素的和的程序,需要的時間與列表的長度成正比。這個描述是稍微不準確的,因爲運行時間可能顯著偏離一個精確的比例,尤其是對於較小的n。
線性對數(準線性)時間
若一個算法時間複雜度,則稱這個算法具有線性對數時間,因此從表達式我們也可以看到,線性對數時間增長得比線性時間要快,但是對於任何含有n,且n的冪指數大於1的多項式時間來說,線性對數時間卻增長得慢。
還有幾個沒看懂,就不寫上去了
資源來源,維基百科:時間複雜度