二叉搜索樹 (BST) 的創建以及遍歷


二叉搜索樹(Binary Search Tree) : 屬於二叉樹,其中每個節點都含有一個可以比較的鍵(如需要可以在鍵上關聯值), 且每個節點的鍵都大於其左子樹中的任意節點而小於右子樹的任意節點的鍵。

1、BST 的總體結構:

主要的幾種變量以及方法如上圖所示,主要有插入、排序、刪除以及查找等方法。鍵采用泛型,繼承 IComparable, 便於比較。

其中節點的類如下圖:

BST 類代碼如下:

 1     public class BST<Tkey, Tval> where Tkey : IComparable
 2     {
 3         private Node root;
 4 
 5         public class Node
 6         {
 7             private Tkey key;
 8             private Tval val;
 9             private int n;
10 
11             public Node(Tkey key, Tval val, int n)
12             {
13                 this.key = key;
14                 this.val = val;
15             }
16             public Tkey Key { get => key; }
17             public Tval Val { get => val; set => val = value; }
18             public Node left { set; get; }
19             public Node right { set; get; }
20             public int N { set => n = value; get => n; }
21         }
22                 
23        public int Size() 
24        public void Insert(Tkey, Tval)
25        public void Delete(Node x)
26        public void InorderTraversal()
27     }

 

 

2、插入新節點

根據鍵大於左節點, 小於右節點的定義,可用如下代碼實現新節點的插入:

 1 public void Insert(Tkey key, Tval val)
 2 {
 3     // 創建私有方法,便於傳入參數 root
 4     root = Insert(root, key, val);
 5 }
 6 
 7 private Node Insert(Node x, Tkey key, Tval val)
 8 {
 9     // 若節點為空(無根節點),則創建新的節點
10     if (x == null)
11     {
12         return new Node(key, val, 1);
13     }
14 
15     // 比較鍵的大小,小於返回 -1 , 大於返回 1, 等於返回 0
16     int t = key.CompareTo(x.Key);
17 
18     if (t > 0) { x.right = Insert(x.right, key, val); }
19     else if (t < 0) { x.left = Insert(x.left, key, val); }
20     else { x.Val = val; }
21 
22     x.N = Size(x.left) + Size(x.right) + 1;
23 
24     return x;
25 }

  

3、計算以該節點為根的節點總節點數

采用遞歸的方法,從根節點到循環到葉子節點

1     public int Size(Node x)
2     {
3         if (x == null) { return 0; }
4         return Size(x.left) + Size(x.right) + 1;
5     }

 

 

4、遍歷

遍歷分為廣度遍歷與深度遍歷,如下圖所示:

深度優先遍歷的幾種方式原理相似, 只是輸出的節點鍵的位置不同而已。

中序遍歷遞歸:

1     public void InorderTraversal_recursive(Node x)
2     {
3         if (x == null) { return; }
4 
5         InorderTraversal(x.left);
6         Console.Write(x.Key + "   ");
7         InorderTraversal(x.right);
8     }

中序遍歷非遞歸:

 1     public void  InorderTraversal_stack()   // 利用堆棧先進后出的特性, 先將全部左節點壓入,然后輸出左節點,每輸出一個左節點后切換到右節點, 繼續輸出
 2     {
 3         Stack<Node> nodeStack = new Stack<Node>();
 4         Node currentNode = root;
 5 
 6         while (nodeStack != null || currentNode != null)  // 此處判斷 curretNode 非空,是因為首次循環 nodeStack 為空, 避免了在循環外添加根節點。
 7         {
 8             while (currentNode != null)  //  將全部左節點壓入堆棧
 9             {
10                 nodeStack.Push(currentNode);
11                 currentNode = currentNode.left;
12             }
13             if (nodeStack.count != 0)
{
14 currentNode = nodeStack.Pop(); 15 Console.Write(currentNode.key + " "); 16 currentNode = currentNode.right; // 切換到右節點
}
17 } 18 }

 

層序遍歷:

 1     // 利用隊列先進先出的特性, 層層輸出
 2     public void LevelTraversal()
 3     {
 4         Queue<Node> nodeQueue = new Queue<Node>();
 5         if (root != null) { nodeQueue.Enqueue(root); }
 6 
 7         while (nodeQueue.Count() != 0)
 8         {
 9             Node currentNode = nodeQueue.Dequeue();
10             Console.Write(currentNode.Key + "   ");
11             // 將去除節點的子節點添加到隊列的尾部
12             if (currentNode.left != null) { nodeQueue.Enqueue(currentNode.left); }
13             if (currentNode.right != null) { nodeQueue.Enqueue(currentNode.right); }
14         }
15     }            

 

5. 證明二叉樹為搜索樹

根據定義,搜索樹是二叉樹的基礎上添加的一個條件: 節點左子樹全部節點小於節點, 節點右子樹大於節點。中序遍歷,全部節點按序遍歷,由此我們只需要證明后一個節點大於前一個節點。

 1     public bool isBST()
 2     {
 3         Stack<Node> nodeStack = new Stack<Node>();
 4         Node currentNode = root;
 5         Node preNode = null;
 6 
 7 
 8         if (nodeStack.Count() != 0 || currentNode != null)
 9         {
10             while (currentNode != null)
11             {
12                 nodeStack.Push(currentNode);
13                 currentNode = currentNode.left;
14             }
15 
16             if (nodeStack.Count() != 0)
17             {
18                 currentNode = nodeStack.Pop();
19                 // 此處需要判斷 preNode 等於空的情況(當進行首個節點判斷時,preNOde 為空, 跳過判斷) 
20                 if (preNode != null && currentNode.Key.CompareTo(preNode.Key) <= 0) { return false; }
21 
22                 preNode = currentNode;
23                 currentNode = currentNode.right;
24             }
25         }
26         return true;
27     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM