馬房山實驗報告大學C語言實驗 圖書管理系統(一)——追求卓越
阿新 • • 發佈:2020-12-24
一般的陣列修改操作的複雜度是O(1),求字首和操作的複雜度是O(n);而同時維護一個字首和陣列時修改操作的複雜度是O(n),求字首和操作複雜度是O(1);
當我們有m次操作時,時間複雜度就會達到O(mn),達到了平方級別,而我們維護一個樹狀陣列時求字首和和修改操作的複雜度是O(logn),總時間複雜度只有O(mlogn),達到了很快的程度。
首先要了解lowbit運算,二進位制分解下最小的2的次冪。即當我們求11100的lowbit時返回的是100(二進位制下)。
1 int lowbit(int x) 2 { 3 return x & -x; 4 }
樹狀陣列思想
樹狀陣列的本質思想是使用樹結構維護”字首和”,從而把時間複雜度降為O(logn)O(logn)。
對於一個序列,對其建立如下樹形結構:
每個結點t[x]儲存以x為根的子樹中葉結點值的和
每個結點覆蓋的長度為lowbit(x)
t[x]結點的父結點為t[x + lowbit(x)]
樹的深度為log2n+1
兩個基礎操作:
1.查詢(即求字首和)
sum(x)表示將查詢序列前x個數的和
以sum(7)為例:
查詢這個點的字首和,需要從這個點向左上找到上一個結點,將加上其結點的值。向左上找到上一個結點,只需要將下標 x -= lowbit(x),例如 7 - lowbit(7) = 6。
1 int sum(int x) 2 { 3 int res = 0; 4 for (inti = x; i ; i -= lowbit(i)) res += t[i]; 5 return res; 6 }
2.修改
add(x, k)表示將序列中第x個數加上k。
以add(3, 5)為例:
在整棵樹上維護這個值,需要一層一層向上找到父結點,並將這些結點上的t[x]值都加上k,這樣保證計算區間和時的結果正確。時間複雜度為O(logn)。
1 void add(int x, int k) 2 { 3 for (int i = x; i <= n; i += lowbit(i)) t[i] += k; 4 }