1. 程式人生 > 其它 >馬房山實驗報告大學C語言實驗 圖書管理系統(一)——追求卓越

馬房山實驗報告大學C語言實驗 圖書管理系統(一)——追求卓越

一般的陣列修改操作的複雜度是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 (int
i = 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 }