本文簡單簡介二叉樹的概念,并給出平衡一顆二叉樹的方法

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


 

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


每個元素連著兩個元素,左孩子和右孩子。他們存儲的值的關系有如下規定
Valueleft<Valuemiddle<=Valueright

排序:
在二叉樹中利用遞歸你能很方便的排序
前序遍歷
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
若理解錯誤,歡迎指正!