對binary heap進行deletemin操作,是o(logn)的。基於下濾的deletemin,最壞情況下每次操作需要比較2logn次。下面介紹一種演算法,最壞情況下每次操作僅需要比較logn+loglogn+o(1)次,然而,資料移動操作的複雜度是相同的:
從root開始,找到一條由最小child構成的路徑,直到底部。對這個路徑進行binary search,找到能插入最後乙個元素的位置,進行與下濾類似的資料移動操作。
這種演算法中,找到一條由最小child構成的路徑需要logn次比較,對路徑進行binary search需要loglogn次比較。但是,這種演算法需要額外的logn個元素位置的記憶空間。其一種實現如下:
void deletemin()
int low = 0;
int mid; int high = level;
while (lowarray[lastele])
count = mid - 1;
else
break;
} int target;
if ((array[path[low]] < array[out]) || low == 0) // 對找到的目標位置進行判斷
target = low;
else
target = low - 1;
for (int i = 0; i < target; i++) // 進行資料移動
array[path[i]] = std::move(array[path[i + 1]]);
array[path[target]] = std::move(array[lastele]);
}
儘管每次deletemin節省了logn-loglogn-o(1)次比較操作,卻多了logn次賦值操作,因此,這種演算法能否節約執行時間,依賴於整數賦值操作是否比對元素進行比較操作更耗時。執行下面的**中deletemin部分,這種演算法可以比下濾演算法節約23%的時間(在筆者的電腦上,執行時間分別為16255ms和13210ms),而如果把資料型別換成int,則只節約約10%的時間(5560ms與5056ms)。
binaryheapbh;
vectordata;
const int start = 0;
const int limit = 200000;
for (int i = start; i < limit; i++)
data.push_back(tostring(i));
random_shuffle(data.begin(), data.end());
for (auto i : data)
bh.insert(i);
while (!bh.isempty())
這種演算法尚有進一步的改進空間。如果我們每次只找前logn-loglogn層元素的最小路徑,然後判斷是在這層上還是在這層下進行binary search,則每次deletemin只消耗logn+logloglogn+o(1)次比較。進一步的,我們可以把這種方法推廣到每次deletemin只需logn+log*n+o(1)次比較。(log*n是讓logn=1的迭代次數,例如,log*2=1,log*16=3)。上述改進的實現如下:
void deletemin()
int low, high, mid;
int levelold = level;
if (array[path[levelold]] > array[lastele]) //如果目標位置在此層之上,對此層之上的路徑進行binary search
else //否則,找到此層之下的最小child路徑直到底部,並對這一區間的路徑進行binary search
low = levelold; high = level;
} while (lowarray[lastele])
high = mid - 1;
else
break;
} int target;
if ((array[path[low]] < array[lastele]) || low == 0)
target = low;
else
target = low - 1;
for (int i = 0; i < target; i++)
array[path[i]] = std::move(array[path[i + 1]]);
array[path[target]] = std::move(array[lastele]);
}
比較次數為logn+log*n+o(1)的演算法,在執行前面提到的**時,與比較次數為logn+loglogn+o(1)的演算法比,節約了2.4%的時間;與比較次數為logn+logloglogn+o(1)的演算法比,節約了約0.8%的時間。(分別為12892ms和12990ms,多次試驗,logn+log*n+o(1)的演算法耗時均最小)
一種二叉堆的泛化實現
本文列出了一種二叉堆的泛化實現方法 所謂二叉堆,其實就是一種完全二叉樹或者近似完全二叉樹,樹中父節點的鍵值總是保持某種固定的序關係於任何乙個子節點的鍵值,且每個節點的左子樹和右子樹也都是二叉堆.這裡列出一種二叉堆的泛化實現方法,其中值得一提的地方有這麼幾處 完整的 可以在gist上找到 using ...
一種二叉樹遍歷方法
偽 如下 inorder tree walk x y x print x.key x x.left while y nil y y.right while y x while x nil print x.key x x.left while x.right nil x x.p x x.right p...
二叉堆的構建 插入 刪除等操作
若設二叉樹的深度為h,除第h層外,其它各層 1 h 1 的結點數都達到最大個數,第h層的所有節點都集中在左邊的若干位置,這就是完全二叉樹 以小根堆舉例 具有完全二叉樹的特性,插入乙個節點的時候,需要保證節點插入後,仍然是一顆完全二叉樹,然後在進行調整,使它滿足二叉堆的另乙個特性 具有完全二叉樹的特性...