原文URL: http://www.cnblogs.com/CareySon/archive/2012/04/19/ImpleBinaryTreeWithCSharp.htmlhtml
樹是一種非線性結構。樹的本質是將一些節點由邊鏈接起來,造成層級的結構。而二叉樹是一種特殊的樹,使得樹每一個子節點必須小於等於2.而二叉查找樹又是一類特殊的二叉樹。使得每個節點的左節點或左子樹的全部節點必須小於這個節點,右節點必須大於這個節點。從而方便高效搜索。post
下面來看如何使用C#實現二叉查找樹。測試
二叉查找樹是節點的集合。所以首先要構建節點,如代碼1所示。spa
//二叉查找樹的節點定義
public class Node { //節點自己的數據 public int data; //左孩子 public Node left; //右孩子 public Node right; public void DisplayData() { Console.Write(data+" "); } }
代碼1.節點的定義htm
構建二叉樹是經過向二叉樹插入元素得以實現的,全部小於根節點的節點插入根節點的左子樹,大於根節點的,插入右子樹。依此類推動行遞歸。直到找到位置進行插入。二叉查找樹的構建過程其實就是節點的插入過程。C#實現代碼如代碼2所示。blog
public void Insert(int data) { Node Parent; //將所需插入的數據包裝進節點 Node newNode=new Node(); newNode.data=data; //若是爲空樹,則插入根節點 if(rootNode==null) { rootNode=newNode; } //不然找到合適葉子節點位置插入 else { Node Current = rootNode; while(true) { Parent=Current; if(newNode.data<Current.data) { Current=Current.left; if(Current==null) { Parent.left=newNode; //插入葉子後跳出循環 break; } } else { Current = Current.right; if (Current == null) { Parent.right = newNode; //插入葉子後跳出循環 break; } } } } }
代碼2.實現二叉樹的插入排序
二叉樹的遍歷分爲先序(PreOrder),中序(InOrder)和後序(PostOrder)。先序首先遍歷根節點,而後是左子樹,而後是右子樹。中序首先遍歷左子樹,而後是根節點,最後是右子樹。然後續首先遍歷左子樹,而後是右子樹,最後是根節點。所以,咱們能夠經過C#遞歸來實現這三種遍歷,如代碼3所示。遞歸
//中序
public void InOrder(Node theRoot) { if (theRoot != null) { InOrder(theRoot.left); theRoot.DisplayData(); InOrder(theRoot.right); } } //先序 public void PreOrder(Node theRoot) { if (theRoot != null) { theRoot.DisplayData(); PreOrder(theRoot.left); PreOrder(theRoot.right); } } //後序 public void PostOrder(Node theRoot) { if (theRoot != null) { PostOrder(theRoot.left); PostOrder(theRoot.right); theRoot.DisplayData(); } }
代碼3.實現二叉排序樹的先序,中序和後續遍歷get
二叉查找樹由於已經有序,因此查找最大值和最小值很是簡單,找最小值只須要找最左邊的葉子節點便可。而找最大值也僅須要找最右邊的葉子節點,如代碼4所示。it
//找到最大節點
public void FindMax() { Node current = rootNode; //找到最右邊的節點便可 while (current.right != null) { current = current.right; } Console.WriteLine("\n最大節點爲:" + current.data); } //找到最小節點 public void FindMin() { Node current = rootNode; //找到最左邊的節點便可 while (current.left != null) { current = current.left; } Console.WriteLine("\n最小節點爲:" + current.data); }
代碼4.二叉查找樹找最小和最大節點
由於二叉查找樹已經有序,因此查找時只須要從根節點開始比較,若是小於根節點,則查左子樹,若是大於根節點,則查右子樹。如此遞歸,如代碼5所示。
//查找
public Node Search(int i) { Node current = rootNode; while (true) { if (i < current.data) { if (current.left == null) break; current = current.left; } else if (i > current.data) { if (current == null) break; current = current.right; } else { return current; } } if (current.data != i) { return null; } return current; }
代碼5.二叉查找樹的查找
二叉樹的刪除是最麻煩的,須要考慮四種狀況:
咱們首先須要找到被刪除的節點和其父節點,而後根據上述四種狀況分別處理。若是遇到被刪除元素是根節點時,還須要特殊處理。如代碼6所示。
//刪除二叉查找樹中的節點,最麻煩的操做
public Node Delete(int key) { Node parent = rootNode; Node current = rootNode; //首先找到須要被刪除的節點&其父節點 while (true) { if (key < current.data) { if (current.left == null) break; parent = current; current = current.left; } else if (key > current.data) { if (current == null) break; parent = current; current = current.right; } //找到被刪除節點,跳出循環 else { break; } } //找到被刪除節點後,分四種狀況進行處理 //狀況一,所刪節點是葉子節點時,直接刪除便可 if (current.left == null && current.right == null) { //若是被刪節點是根節點,且沒有左右孩子 if (current == rootNode&&rootNode.left==null&&rootNode.right==null) { rootNode = null; } else if (current.data < parent.data) parent.left = null; else parent.right = null; } //狀況二,所刪節點只有左孩子節點時 else if(current.left!=null&¤t.right==null) { if (current.data < parent.data) parent.left = current.left; else parent.right = current.left; } //狀況三,所刪節點只有右孩子節點時 else if (current.left == null && current.right != null) { if (current.data < parent.data) parent.left = current.right; else parent.right = current.right; } //狀況四,所刪節點有左右兩個孩子 else { //current是被刪的節點,temp是被刪左子樹最右邊的節點 Node temp; //先判斷是父節點的左孩子仍是右孩子 if (current.data < parent.data) { parent.left = current.left; temp = current.left; //尋找被刪除節點最深的右孩子 while (temp.right != null) { temp = temp.right; } temp.right = current.right; } //右孩子 else if (current.data > parent.data) { parent.right = current.left; temp = current.left; //尋找被刪除節點最深的左孩子 while (temp.left != null) { temp = temp.left; } temp.right = current.right; } //當被刪節點是根節點,而且有兩個孩子時 else { temp = current.left; while (temp.right != null) { temp = temp.right; } temp.right = rootNode.right; rootNode = current.left; } } return current; }
代碼6.二叉查找樹的刪除
如今咱們已經完成了二叉查找樹所需的各個功能,下面咱們來對代碼進行測試:
BinarySearchTree b = new BinarySearchTree();
/*插入節點*/ b.Insert(5); b.Insert(7); b.Insert(1); b.Insert(12); b.Insert(32); b.Insert(15); b.Insert(22); b.Insert(2); b.Insert(6); b.Insert(24); b.Insert(17); b.Insert(14); /*插入結束 */ /*對二叉查找樹分別進行中序,先序,後序遍歷*/ Console.Write("\n中序遍歷爲:"); b.InOrder(b.rootNode); Console.Write("\n先序遍歷爲:"); b.PreOrder(b.rootNode); Console.Write("\n後序遍歷爲:"); b.PostOrder(b.rootNode); Console.WriteLine(" "); /*遍歷結束*/ /*查最大值和最小值*/ b.FindMax(); b.FindMin(); /*查找結束*/ /*搜索節點*/ Node x = b.Search(15); Console.WriteLine("\n所查找的節點爲" + x.data); /*搜索結束*/ /*測試刪除*/ b.Delete(24); Console.Write("\n刪除節點後先序遍歷的結果是:"); b.InOrder(b.rootNode); b.Delete(5); Console.Write("\n刪除根節點後先序遍歷的結果是:"); b.InOrder(b.rootNode); Console.ReadKey(); /*刪除結束*/
代碼7.測試二叉查找樹
運行結果如圖1所示:
圖1.測試運行結果
樹是節點的層級集合,而二叉樹又是將每一個節點的孩子限制爲小於等於2的特殊樹,二叉查找樹又是一種特殊的二叉樹。二叉樹對於查找來講是很是高效,尤爲是查找最大值和最小值。