二叉尋找樹的特點:
(1)左邊的所有節點都要小於根節點的值
(2)右邊的所有節點都要不小於根節點的值
(3)原樹的子樹都符合(1)(2)條件。
二叉尋找樹又名二叉排序樹,因為只需中序遍曆它就可以得到排序的樹了,對於二叉排序樹的操作主要有:
(1)插入:通過插入來初始化樹。本文是用鏈式,而不是儲存在數組中。
(2)遍曆:有三種方法分別為:先序,中序,後序。
(3)尋找:有三種尋找分別為:尋找最大值,最小值,與某種特定的值的節點。
(4)刪除:刪除一個節點類型有三種分別為:無左右孩子的節點,有一個孩子的節點,有兩個孩子的節點。
樹是由節點和節點之間的邊組成的,所以首先要聲明一個節點類Node,一個節點有兩個孩子和節點的值。
public class Node{ public int value; public Node leftChild; public Node rightChild; public Node(int value) { leftChild = null; rightChild = null; this.value = value; }}
節點類聲明完成後,還需要一個樹類,裡麵包含樹的初始化以及一些對樹的操作,一個預設建構函式來初始化一個空樹和一個輸出接點的值的函數。
class BinarySearchTree{ public Node root; public BinarySearchTree() { root = null; } public void Dispaly(Node node) { Console.Write(node.value + " "); }}
要構成一棵樹,就得插入數值了,根據二叉排序樹的性質,左邊孩子的值全部小於根節點的值,所以在插入一個數值的時候
(1)首先判斷是否為空白樹,也就是根節點是否為空白,如果為空白,就將插入的值放入根節點中。
(2)判斷值與根節點(本樹的根,或者其子數)值的大小,來判斷放在左孩子還是右孩子。
public void Insert(int v){ Node newNode = new Node(v); Node parent; Node current; if (root == null) root = newNode; else { current=root; while (true) { parent=current; if (v < current.value) { current = current.leftChild; if (current == null) { parent.leftChild = newNode; break; } } else { current = current.rightChild; if (current == null) { parent.rightChild = newNode; break; } } } }}
插入完成之後,一棵樹就形成了,現在來遍曆一下,三種遍曆用遞迴實現,使邏輯更清晰
public void InOrder(Node root){ Node node = root; if (node != null) { InOrder(node.leftChild); this.Dispaly(node); InOrder(node.rightChild); }}public void PreOrder(Node root){ Node node = root; if (node != null) { this.Dispaly(node); PreOrder(node.leftChild); PreOrder(node.rightChild); }}public void PostOrder(Node root){ Node node = root; if (node != null) { PostOrder(node.leftChild); PostOrder(node.rightChild); this.Dispaly(node); }}
三種遍曆是根節點的位序不同。接著就是尋找樹中的最大值,最小值,以及特定的值。
(1)最大值:在樹的最右邊的孩子
(2)最小值:在樹的最左邊的孩子
(3)特定值:用迴圈,判斷與根值的大小。
public Node FindMax(){ Node current=root; while (current.rightChild != null) current = current.rightChild; return current;}public Node FindMin(){ Node current = root; while (current.leftChild != null) current = current.leftChild; return current;}public Node Find(int v){ Node current = root; while (true) { if (v < current.value) current = current.leftChild; else if (v > current.value) current = current.rightChild; else return current; if (current == null) return null; }}
最後就是刪除了,由於使用鏈式構成的數,所以在樹中刪除一個節點的方法和在鏈表中刪除一個節點的方法類似,只不過改動的“指標”更多一點,因為樹的節點是一對多的。用if-else語句分別區分刪除的三種類型的節點。
public bool Delete(int v){ Node current=root; Node parent = current; //找到要刪除的節點 while (current.value != v) { parent = current; if (v < current.value) { current = current.leftChild; } else { current = current.rightChild; } if (current == null) return false; } //如果是沒有孩子的節點 if (current.leftChild == null && current.rightChild == null) { if (current == root) root = null; if (current ==parent.leftChild) parent.leftChild = null; if (current ==parent.rightChild) parent.rightChild = null; } //如果是有右孩子的節點 else if (current.rightChild != null) { if (current == root) root = current.leftChild; if (current == parent.leftChild) parent.leftChild = current.rightChild; if (current == parent.rightChild) parent.rightChild = current.rightChild; } //如果是有左孩子的節點 else if(current.leftChild!=null) { if(current==root) root=current.rightChild; if(current==parent.leftChild) parent.leftChild=current.leftChild; if(current==parent.rightChild) parent.rightChild=current.leftChild; } //有兩個孩子的節點 else { Node newNode=GetSuccessor(current); newNode.rightChild=current.rightChild; newNode.leftChild=current.leftChild; if(current==parent.leftChild) parent.leftChild=newNode; if(current==parent.rightChild) parent.rightChild=newNode; } return true;}
其中尋找successor節點的方法如下
/// <summary>/// 刪除一個有兩個孩子的節點時,應該以中序遍曆時將刪節點delNode/// 右鄰節點successor(以刪除的節點為子樹的根節點,最左邊的/// 節點來替代被刪的節點)來代替,因為successor的值是大於delNode 值中/// 最小的/// </summary>/// <param name="delNode"></param>/// <returns></returns>private Node GetSuccessor(Node delNode){ Node current = delNode; while (current.leftChild != null) current = current.leftChild; return current;}
測試如下:
static void Main(string[] args){ BinarySearchTree bs = new BinarySearchTree(); bs.Insert(2); bs.Insert(5); bs.Insert(6); bs.Insert(10); bs.Insert(12); bs.Insert(15); bs.Insert(18); bs.InOrder(bs.root); Console.WriteLine("最大的數:{0}", bs.FindMax().value); Console.WriteLine("最小的數:{0}", bs.FindMin().value); Console.WriteLine("找到節點的值:{0}",bs.Find(6).value); bs.Delete(5); bs.InOrder(bs.root); Console.ReadKey();}
輸出:
總結:
(1)瞭解二叉排序樹的基本原理,就要將其應用。
(2)應該還有順序儲存方式,本文是用鏈式。
(3)大道至簡,從簡至繁。
(4)如有錯誤或者建議請在回複中說明或者發送zabery@126.com