搜索二叉树是序列式容器的底层数据结构;泛型版本能存储各种类型的数据。
二叉树有三个关键数据成员:存储数据,左节点,右节点;在C#中定义为三个属性:Data, Left, Right。
1)为使用方便,实现了<,>两个操作符;主要C#的泛型定义与C++有所区别,不能直接使用模板类的操作符。C#这方面坚持比较严格,会报出operator '<' cannot be applied to operands 'T' and operands 'T'编译错误。这里使用C#的Comparer<T>得到模板类的默认比较操作符解决。Comparer<T>实现的C#的IComparable接口。如果你的类有自己的基类,不妨实现此接口,方便在泛型版本进行比较操作。
2)这里枚举了三种搜索方式 SearchOrder{ InOrder, PreOrder, PostOrder };划分的依据是左,右和父节点之间的先后顺序。L->P->R:InOrder,P->L->R:PreOrder,L->R->P:PostOrder。
3)为方便调试,定义的节点的打印;为保留输出方式的多变性,把StreaWriter传入;比如想打印到标注输出,就可以这样创建StreamWriter:
StreamWriter sw = new StreamWriter(Console.OpenStandardOutput());
sw.AutoFlush = true;
也可以输出到文本文件中。
4)public方法简介:
实际运行结果:
InOrder traversal:
3 16 22 23 37 45 99
23 16 3 22 45 37 99
3 22 16 37 99 45 23
Minmum value:3, Maximum value:99
find a 3
16 22 23 37 45 99
16 22 23 37 99
22 23 37 99
22 23 99
22 99
22
Press any key to continue . . .
源代码清单。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace BinaryTree
{
public class Node<T>
{
private T tData;
private Node<T> left;
private Node<T> right;
public T Data
{
get
{
return tData;
}
set
{
tData = value;
}
}
public Node<T> Left
{
get
{
return left;
}
set
{
left = value;
}
}
public Node<T> Right
{
get
{
return right;
}
set
{
right = value;
}
}
public void Write(StreamWriter sw)
{
sw.Write(tData);
sw.Write(' ');
}
public static bool operator< (Node<T> n1, Node<T> n2)
{
return 0 > Comparer<T>.Default.Compare(n1.Data, n2.Data);
}
public static bool operator >(Node<T> n1, Node<T> n2)
{
return 0 < Comparer<T>.Default.Compare(n1.Data, n2.Data);
}
}
public class BinarySearchTree<T>
{
private Node<T> root;
public Node<T> Root
{
get
{
return root;
}
set
{
root = value;
}
}
public enum SearchOrder{ InOrder, PreOrder, PostOrder };
public BinarySearchTree()
{
root = null;
}
public void Insert(T t)
{
Node<T> newNode = new Node<T>();
newNode.Data = t;
if (root == null)
{
root = newNode;
}
else
{
Node<T> current = root;
Node<T> parent;
while (true)
{
parent = current;
if (0 > Comparer<T>.Default.Compare(t,current.Data))
{
current = current.Left;
if (current == null)
{
parent.Left = newNode;
break;
}
else
{
//next loop
}
}
else
{
current = current.Right;
if (current == null)
{
parent.Right = newNode;
break;
}
}
}
}
}
private void InOrder(Node<T> root, StreamWriter sw)
{
if (root != null)
{
InOrder(root.Left,sw);
root.Write(sw);
InOrder(root.Right, sw);
}
}
private void PreOrder(Node<T> root, StreamWriter sw)
{
if (root != null)
{
root.Write(sw);
PreOrder(root.Left, sw);
PreOrder(root.Right, sw);
}
}
private void PostOrder(Node<T> root, StreamWriter sw)
{
if (root != null)
{
PostOrder(root.Left, sw);
PostOrder(root.Right, sw);
root.Write(sw);
}
}
public void Traverse(Node<T> root, StreamWriter sw, SearchOrder so)
{
switch (so)
{
case BinarySearchTree<T>.SearchOrder.InOrder: InOrder(root, sw); break;
case BinarySearchTree<T>.SearchOrder.PreOrder: PreOrder(root, sw); break;
case BinarySearchTree<T>.SearchOrder.PostOrder: PostOrder(root, sw); break;
}
}
public T FindMin()
{
Node<T> current = root;
while (current.Left != null)
{
current = current.Left;
}
return current.Data;
}
public T FindMax()
{
Node<T> current = root;
while (current.Right != null)
{
current = current.Right;
}
return current.Data;
}
public Node<T> Find(T key)
{
Node<T> current = root;
while (current != null)
{
int cmp = Comparer<T>.Default.Compare(current.Data, key);
if (0 == cmp)
{
return current;
}
else if (0 < cmp)
{
current = current.Left;
}
else
{
current = current.Right;
}
}
return null;
}
public bool Delete(T key)
{
Node<T> current = root;
Node<T> parent = root;
bool isLeft = true;
while (current != null)
{
int cmp = Comparer<T>.Default.Compare(current.Data, key);
if (0 == cmp)
{
if (current.Left == null && current.Right == null)
{
//leaf node
if (current != root)
{
if (isLeft == true)
{
parent.Left = null;
}
else
{
parent.Right = null;
}
}
else
{
root = null;
}
}
else if (current.Left == null)
{
//with right child
if (current == root)
{
root = current.Right;
}
else if (isLeft)
{
parent.Left = current.Right;
}
else
{
parent.Right = current.Right;
}
}
else if (current.Right == null)
{
//with left child
if (current == root)
{
root = current.Left;
}
else if (isLeft)
{
parent.Left = current.Left;
}
else
{
parent.Right = current.Left;
}
}
else
{
isLeft = false;
//two children
Node<T> successor = GetSuccessor(current);
if (successor == root.Right)
{
root = successor;
}
else if (isLeft)
{
parent.Left = successor;
}
else
{
parent.Right = successor;
}
successor.Left = current.Left;
}
return true ;
}
else if (0 < cmp)
{
parent = current;
current = current.Left;
isLeft = true;
}
else
{
parent = current;
current = current.Right;
isLeft = false;
}
}
return false;
}
private Node<T> GetSuccessor(Node<T> delNode)
{
Node<T> sucParent = delNode;
Node<T> suc = delNode;
Node<T> current = delNode.Right;
while (current != null)
{
sucParent = current;
suc = current;
current = current.Left;
}
if (suc != delNode.Right)
{
//only right child
sucParent.Right = current.Right;
}
return suc;
}
}