之前几篇,我们介绍的都是线性存储结构,从本篇开始,我们要来介绍计算机科学中两个非常重要的非线性存储结构,其中之一就是本篇的重点 —— 树(Tree)。
二叉树(Binary Tree)
类似于真实世界,计算机科学中的树也有不同种类,我们首先学习最简单的树 —— 二叉树。一旦我们学会二叉树之后我们就可以快速学习其他类型的树了。

树的应用非常多,例如: 
- 展示层级结构(File 和 Folder)
- 数据库索引(Index)
- 编译器(Syntax Tree)
- 压缩(JPEG、MP3)
- 自动补全
有一类特殊的二叉树称为二叉搜索树,他的特点是: 左子树的所有值小于该节点,右子树的所有值都大于该节点。

Building a BinarySearchTree
| public class BinarySearchTree<T> where T : IComparable{
 private class Node<T>
 {
 public T Value { get; private set; }
 
 public Node<T> LeftChild { get; set; }
 
 public Node<T> RightChild { get; set; }
 
 public Node(T value)
 {
 Value = value;
 }
 }
 
 private Node<T> Root { get; set; }
 
 public void Insert(T value)
 {
 var node = new Node<T>(value);
 if (Root == null)
 {
 Root = node;
 return;
 }
 
 var current = Root;
 
 while (true)
 {
 if (current.Value.CompareTo(value) == 1)
 {
 if (current.LeftChild == null)
 {
 current.LeftChild = node;
 break;
 }
 current = current.LeftChild;
 }
 else
 {
 if (current.RightChild == null)
 {
 current.RightChild = node;
 break;
 }
 current = current.RightChild;
 }
 }
 }
 
 public bool Find(T value)
 {
 var current = Root;
 while (current != null)
 {
 if (current.Value.CompareTo(value) == 1)
 {
 current = current.LeftChild;
 }
 else if (current.Value.CompareTo(value) == -1)
 {
 current = current.RightChild;
 }
 else
 {
 return true;
 }
 }
 return false;
 }
 }
 
 | 
Traversing Trees
不同于线性结构,树的遍历分为两种方式:
- 广度优先(BREADTH FIRST): 以层次顺序遍历,先遍历同一层次,再遍历下一层次
- 深度优先(DEPTH FIRST): 以深度顺序遍历,又可分为前序、中序、后序三种方式
- 前序遍历(Pre-Order): Root -> Left ->  Right
- 中序遍历(In-Order): Left -> Root ->  Right
- 前序遍历(Post-Order): Left ->  Right -> Root
注意: 前中后指的是何时访问 Root 元素。
Recursion
在实现树的遍历代码之前,我们首先要介绍在计算机科学中极其常用的概念 —— 递归。
“In order to understand recursion, one must first understand recursion.”
 
| public int Factorial(int n) {
 
 if (n == 0)
 {
 return 1;
 }
 
 return n * Factorial(n - 1);
 }
 
 | 
Depth First Traversal
| public void TraversePreOrder(){
 TraversePreOrder(Root);
 }
 
 private void TraversePreOrder(Node<T> root)
 {
 if (root == null)
 {
 return;
 }
 Console.WriteLine(root.Value);
 TraversePreOrder(root.LeftChild);
 TraversePreOrder(root.RightChild);
 }
 
 public void TraverseInOrder()
 {
 TraverseInOrder(Root);
 }
 
 private void TraverseInOrder(Node<T> root)
 {
 if (root == null)
 {
 return;
 }
 TraverseInOrder(root.LeftChild);
 Console.WriteLine(root.Value);
 TraverseInOrder(root.RightChild);
 }
 
 public void TraversePostOrder()
 {
 TraversePostOrder(Root);
 }
 
 private void TraversePostOrder(Node<T> root)
 {
 if (root == null)
 {
 return;
 }
 TraversePostOrder(root.LeftChild);
 TraversePostOrder(root.RightChild);
 Console.WriteLine(root.Value);
 }
 
 | 
Equality Checking
| public bool Equal(Tree<T> other){
 return Equal(Root, other.Root);
 }
 
 private bool Equal(Node<T> first, Node<T> second)
 {
 if (first == null && second == null)
 {
 return true;
 }
 
 if (first != null && second != null)
 {
 return first.Value.Equals(second.Value)
 && Equal(first.LeftChild, second.LeftChild)
 && Equal(first.RightChild, second.RightChild);
 }
 return false;
 }
 
 |