在計算機中,二叉樹是每一個節點最多有兩個子樹的樹結構。一般子樹被稱做「左子樹」(left subtree)和「右子樹」(right subtree)。node
二叉樹是一個連通的無環圖,而且每個頂點的度不大於3。有根二叉樹還要知足根結點的度不大於2。有了根節點以後,每一個頂點定義了惟一的父節點,和最多2個子節點。然而,沒有足夠的信息來區分左節點和右節點。ide
從邏輯上講二叉樹有五種形態,如上圖:測試
遍歷是對樹的一種最基本的運算,所謂遍歷二叉樹,就是按必定的規則和順序走遍二叉樹的全部節點,使每個節點都被訪問一次,並且只被訪問一次。因爲二叉樹是非線性結構,所以,樹的遍歷實質上是將二叉樹的各個結點轉換成爲一個線性序列來表示。this
設L、D、R分別表示遍歷左子樹、訪問根節點和遍歷右子樹, 則對一棵二叉樹的遍歷有三種狀況:DLR(稱爲先序遍歷),LDR(稱爲中序遍歷),LRD (稱爲後序遍歷)spa
首先訪問根,再先序遍歷左子樹,最後先序遍歷右子樹。如上圖遍歷的結果是:ABCDE3d
首先中序遍歷左子樹,再訪問根,最後中序遍歷右子樹,如上圖遍歷的結果是:CBDAEcode
首前後序遍歷左子樹,再後序遍歷右子樹,最後訪問根。如上圖遍歷的結果是:CDBEAblog
public class Node { public Node(int i) { Data = i; } public int Data { get; set; } public Node Left { get; set; } public Node Right { get; set; } public void Display(string lr) { Console.Write(lr + ": " + Data); }
先序遍歷遞歸
public void DLRDisplay(Node theNode) { if (theNode != null) { theNode.Display("InOrder"); InOrder(theNode.Left); InOrder(theNode.Right); } }
中序遍歷get
public void LDRDisplay(Node theNode) { if (theNode != null) { InOrder(theNode.Left); theNode.Display("InOrder"); InOrder(theNode.Right); } }
後序遍歷
public void LRDDisplay(Node theNode) { if (theNode != null) { InOrder(theNode.Left); InOrder(theNode.Right); theNode.Display("InOrder"); } }
代碼實現
public enum Order { DLR,//先序遍歷 LDR,//中序遍歷 LRD //後序遍歷 } public abstract class AbstractTreeNode { protected string name; public AbstractTreeNode(string name) { this.name = name; } public AbstractTreeNode Left { get; set; } public AbstractTreeNode Right { get; set; } public abstract void Display(Order order); } public class TreeNode : AbstractTreeNode { public TreeNode(string name) : base(name) { } public override void Display(Order order) { switch (order) { case Order.DLR:// D->L->R DLRDisplay(order); break; case Order.LDR://L->D->R LDRDisplay(order); break; case Order.LRD://L->R->D LRDDisplay(order); break; } } private void DLRDisplay(Order order) { Console.Write(name); if (Left != null) { Left.Display(order); } if (Right != null) { Right.Display(order); } } private void LDRDisplay(Order order) { if (Left != null) { Left.Display(order); } Console.Write(name); if (Right != null) { Right.Display(order); } } private void LRDDisplay(Order order) { if (Left != null) { Left.Display(order); } if (Right != null) { Right.Display(order); } Console.Write(name); } } public class LeafNode : AbstractTreeNode { public LeafNode(string name) : base(name) { } public override void Display(Order order) { Console.Write(name); } }
測試:
/// <summary> /// A /// / \ /// B E /// / \ /// C D /// </summary> /// <param name="args"></param> static void Main(string[] args) { AbstractTreeNode rootA, b, c, d, e; rootA = new TreeNode("A"); b = new TreeNode("B"); c = new LeafNode("C"); d = new LeafNode("D"); e = new LeafNode("E"); rootA.Left = b; rootA.Right = e; b.Left = c; b.Right = d; rootA.Display(Order.DLR);//output->ABCDE Console.WriteLine(); rootA.Display(Order.LDR);//output->CBDAE Console.WriteLine(); rootA.Display(Order.LRD);//output->CDBEA Console.ReadKey(); }
結果:
先序遍歷的結果:ABCDE
中序遍歷的結果:CBDAE
後序遍歷的結果:CDBEA
在這裏其實能夠省略掉葉子節點類,只須要一個實現類TreeNode就能夠了這樣就變得更簡單了:
代碼中能夠刪掉LeafNode類,客戶端只針對TreeNode實現就能夠了。由於這裏沒有針對複雜的樹枝節點的管理操做。所以不須要分別對待樹枝節點和葉子節點。
public enum Order { DLR,//先序遍歷 LDR,//中序遍歷 LRD //後序遍歷 } public abstract class AbstractTreeNode { protected string name; public AbstractTreeNode(string name) { this.name = name; } public AbstractTreeNode Left { get; set; } public AbstractTreeNode Right { get; set; } public abstract void Display(Order order); } public class TreeNode : AbstractTreeNode { public TreeNode(string name) : base(name) { } public override void Display(Order order) { switch (order) { case Order.DLR:// D->L->R DLRDisplay(order); break; case Order.LDR://L->D->R LDRDisplay(order); break; case Order.LRD://L->R->D LRDDisplay(order); break; } } private void DLRDisplay(Order order) { Console.Write(name); if (Left != null) { Left.Display(order); } if (Right != null) { Right.Display(order); } } private void LDRDisplay(Order order) { if (Left != null) { Left.Display(order); } Console.Write(name); if (Right != null) { Right.Display(order); } } private void LRDDisplay(Order order) { if (Left != null) { Left.Display(order); } if (Right != null) { Right.Display(order); } Console.Write(name); } }
測試:
/// <summary> /// A /// / \ /// B E /// / \ /// C D /// </summary> /// <param name="args"></param> static void Main(string[] args) { AbstractTreeNode rootA, b, c, d, e; rootA = new TreeNode("A"); b = new TreeNode("B"); c = new TreeNode("C"); d = new TreeNode("D"); e = new TreeNode("E"); rootA.Left = b; rootA.Right = e; b.Left = c; b.Right = d; rootA.Display(Order.DLR);//output->ABCDE Console.WriteLine(); rootA.Display(Order.LDR);//output->CBDAE Console.WriteLine(); rootA.Display(Order.LRD);//output->CDBEA Console.ReadKey(); }
結果:
先序遍歷的結果:ABCDE
中序遍歷的結果:CBDAE
後序遍歷的結果:CDBEA
兩次測試的結果是同樣的。