本文簡單簡介二叉樹的概念,并給出平衡一顆二叉樹的方法
關于二叉樹
現在有N個元素的數組或者鏈表,要查找一個元素必須遍歷數組直到找到元素。假如元素在是數組中最后一個或者數組中不存在這樣的元素,那么很不幸,我們要遍歷整個數組。如果N非常大,那將是非常痛苦的一件事情。
用二叉樹情況就好多了:
1. 更快的查找
2. 增加元素時,元素被自動排列
原理:
在鏈表或數組中,元素一個接著一個,如圖

在二叉樹中情況不太一樣了

每個元素連著兩個元素,左孩子和右孩子。他們存儲的值的關系有如下規定
Value(left)<Value(middle)<=Value(right)
排序:
在二叉樹中利用遞歸你能很方便的排序
前序遍歷
PrintElement(pTopMostElement)
.
.
void PrintElement(TreeElement* pElement)

{
if (pElement)

{
PrintElement(pElement->LeftChild)
pElement->PrintMe()
PrintElement(pElement->RightChild)
}
}

后序遍歷:
PrintElementReversed(pTopMostElement)
.
.
void PrintElementReversed(TreeElement* pElement)

{
if (pElement)

{
PrintElementReversed(pElement->RightChild)
pElement->PrintMe()
PrintElementReversed(pElement->LeftChild)
}
}

如何使二叉樹平衡?
添加元素的順序將影響二叉樹的形態,以3,6,4,8,1,9,2,7,5的順序得到

以1,2,3,4,5,6,7,8,9將得到

有以下方法可以考慮:
1. 以非排序的元素插入元素,不能要求給出的元素是高度不排序的
2. 以一組隨機元素構造二叉樹,然后替換這些元素,然后通過旋轉得到平衡的樹。參考隨機樹。
3. 重構這稞樹
重構整稞樹
1. 把元素拷貝到數組中,以升序排序
2. 清空這棵樹
3. 從數組中高度不排序的選取元素插入樹中可以這樣完成第三步:

可以遞歸的實現:
// Assuming array ranges from [0..arraySize-1]
GetFromOrderedArray(0,arraySize-1)
.
.
void GetFromOrderedArray(int lowBound,int highBound)


{
if (hi < low) return;
middlePos = lowBound+(highBound-lowBound)/2
// middlePos is now at the element in the middle
// between lowBound and highBound, so we just add
// it to the tree

AddElement ( theOrderedArray[middlePos] )

// Pick the middle one "to the left"
AddFromOrderedArray(lowBound,middlePos-1)

// Pick the middle one "to the right"
AddFromOrderedArray(middlePos+1,highBound)
}

刪除一個元素
首先要找到要刪除的元素E,有兩種方法:
1. 通過遍歷找到這個元素E
2. 給每個元素一個指向雙親的指針
接下來就是刪除的過程了:
1. 剪斷E與他雙親的連接
2. 將左右孩子所在的子樹同其他元素一樣加到樹中
3. 刪除E
void RemoveElement(TreeElement* theOneToRemove)


{
TreeElement* pParent = theOneToRemove->GetParent();

// Ok, so it has a parent, then we'll simply just disconnect it.
if (pParent)

{
if (pParent->GetLeftChild() == theOneToRemove)

{
pParent->SetLeftChild(NULL);
}
else

{
ASSERT(pParent->GetRightChild() == theOneToRemove);
pParent->SetRightChild(NULL);
}
}
else

{
// No parent? Then we're removing the root element.
theTopMostElement = NULL;
}

// Disconnected, now we reconnect its children (if any)
// just by adding them as we add any other node.
if (theOneToRemove->GetLeftChild())
AddElement(theOneToRemove->GetLeftChild());
if (theOneToRemove->GetRightChild())
AddElement(theOneToRemove->GetRightChild());

//Zap the element (if that's what you want to do)
delete theOneToRemove;

}

注解:
通過函數回調 遍歷二叉樹
注:函數回調例如AddElement(theOneToRemove->GetRightChild());
簡而言之,回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用為調用它所指向的函數時,我們就說這是回調函數。
可以把調用者與被調用者分開。調用者不關心誰是被調用者,所有它需知道的,只是存在一個具有某種特定原型、某些限制條件(如返回值為int)的被調用函數。
#內容選自CodeGuru
若理解錯誤,歡迎指正!