二叉查找树
二叉排序树,又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。
若它的左子树不为空,则左子树上所有的结点的值均小于根结构的值;
若它的右子树不为空,则右字数上所有结点的值均大于它的根结点的值;
1. 前序、中序、后序、层次遍历
一般会考查非递归版本的实现,频率很高,在下面的代码递归和非递归版本都有实现。
2. 二叉树的镜像
具体实现在下面的代码中。
3. 二叉树的深度
具体实现在下面的代码中。
4. 二叉树是否是平衡二叉树
用后序遍历的方式,遍历二叉树的每一个结点,在遍历每一个结点前,我们已经遍历了它的左右子树。只要在遍历每个结点时,记录它的深度。具体实现在下面的代码中。
5.输入一个整数S,打印二叉树中路径长度和为S的所有路径。从根节点到叶子节点形成一条路径。
6. 树中两个节点的公共祖先
using System;
using System.Collections.Generic;
namespace StructScript
{
public class BinaryTree<T>
{
//根节点
private TreeNode<T> mRoot;
//比较器
private Comparer<T> mComparer;
public BinaryTree()
{
mRoot = null;
mComparer = Comparer<T>.Default;
}
public bool Contains(T value)
{
if (value == null)
{
throw new ArgumentNullException();
}
TreeNode<T> node = mRoot;
while (node != null)
{
int comparer = mComparer.Compare(value, node.Data);
if (comparer > 0)
{
node = node.RightChild;
}
else if (comparer < 0)
{
node = node.LeftChild;
}
else
{
return true;
}
}
return false;
}
public void Add(T value)
{
mRoot = Insert(mRoot, value);
}
private TreeNode<T> Insert(TreeNode<T> node, T value)
{
if (node == null)
{
return new TreeNode<T>(value, 1);
}
int comparer = mComparer.Compare(value, node.Data);
if (comparer > 0)
{
node.RightChild = Insert(node.RightChild, value);
}
else if (comparer < 0)
{
node.LeftChild = Insert(node.LeftChild, value);
}
else
{
node.Data = value;
}
return node;
}
public int Count
{
get
{
return CountLeafNode(mRoot);
}
}
private int CountLeafNode(TreeNode<T> root)
{
if (root == null)
{
return 0;
}
else
{
return CountLeafNode(root.LeftChild) + CountLeafNode(root.RightChild) + 1;
}
}
public int Depth
{
get
{
return GetHeight(mRoot);
}
}
// 二叉树的深度
private int GetHeight(TreeNode<T> root)
{
if (root == null)
{
return 0;
}
int leftHight = GetHeight(root.LeftChild);
int rightHight = GetHeight(root.RightChild);
return leftHight > rightHight ? leftHight + 1 : rightHight + 1;
}
// 是否是平衡二叉树
// 后序遍历二叉树,在遍历左右子树时,
// 根据左右子树的结点的深度判断是否是平衡二叉树
public bool IsBlanced(BinaryTree<T> bt)
{
int depth = 0;
return IsBlanced(bt.mRoot, ref depth);
}
private bool IsBlanced(TreeNode<T> root, ref int depth)
{
if (root == null)
{
depth = 0;
return true;
}
int leftDepth = 0;
int rightDepth = 0;
if (IsBlanced(root.LeftChild, ref leftDepth)
&& IsBlanced(root.RightChild, ref rightDepth))
{
int diff = leftDepth - rightDepth;
if (diff <= 1 && diff >= -1)
{
depth = 1 + (leftDepth > rightDepth ? leftDepth : rightDepth);
return true;
}
}
return false;
}
public void MirrorBinaryTree()
{
MirrorBinaryTree(mRoot);
}
// 二叉树的镜像
private void MirrorBinaryTree(TreeNode<T> node)
{
if(node == null || (node.LeftChild == null && node.RightChild == null))
{
return;
}
TreeNode<T> tempNode = node.LeftChild;
node.LeftChild = node.RightChild;
node.RightChild = tempNode;
if(node.LeftChild != null)
{
MirrorBinaryTree(node.LeftChild);
}
if(node.RightChild != null)
{
MirrorBinaryTree(node.RightChild);
}
}
// 输入一个整数S,打印二叉树中路径长度和为S的所有路径。
public void FindPath(int sum)
{
Stack<int> stack = new Stack<int>();
int currentSum = 0;
FindPath(mRoot, sum, ref currentSum, stack);
}
private void FindPath(TreeNode<T> node, int sum, ref int currentSum, Stack<int> stack)
{
int data = Convert.ToInt32(node.Data);
currentSum += data;
stack.Push(data);
// 如果是叶子节点,并且路径长度和等于输入整数,打印路径
bool isLeafNode = node.LeftChild == null && node.RightChild == null;
if(isLeafNode && currentSum == sum)
{
Console.WriteLine("Find Path : ");
Stack<int>.Enumerator iter = stack.GetEnumerator();
while (iter.MoveNext())
{
Console.WriteLine(iter.Current);
}
}
// 如果不是叶子节点,则遍历它的子节点
if(node.LeftChild != null)
{
FindPath(node.LeftChild, sum, ref currentSum, stack);
}
if(node.RightChild != null)
{
FindPath(node.RightChild, sum, ref currentSum, stack);
}
// 在返回根节点之前,删除之前节点,currentSum减去相应的值
currentSum -= data;
stack.Pop();
}
public T Max
{
get
{
TreeNode<T> node = mRoot;
while (node.RightChild != null)
{
node = node.RightChild;
}
return node.Data;
}
}
public T Min
{
get
{
if (mRoot != null)
{
TreeNode<T> node = GetMinNode(mRoot);
return node.Data;
}
else
{
return default(T);
}
}
}
public void DelMin()
{
mRoot = DelMin(mRoot);
}
private TreeNode<T> DelMin(TreeNode<T> node)
{
if (node.LeftChild == null)
{
return node.RightChild;
}
node.LeftChild = DelMin(node.LeftChild);
return node;
}
public void Remove(T value)
{
mRoot = Delete(mRoot, value);
}
private TreeNode<T> Delete(TreeNode<T> node, T value)
{
if (node == null)
{
Console.WriteLine("没有找到要删除的节点: " + value);
return null;
}
int comparer = mComparer.Compare(value, node.Data);
if (comparer > 0)
{
node.RightChild = Delete(node.RightChild, value);
}
else if (comparer < 0)
{
node.LeftChild = Delete(node.LeftChild, value);
}
else
{
// 1.如果删除节点没有子节点,直接返回null
// 2.如果只有一个子节点,返回其子节点代替删除节点即可
if (node.LeftChild == null)
{
return node.RightChild;
}
else if (node.RightChild == null)
{
return node.LeftChild;
}
else
{
// 3.当左右子节点都不为空时
// 找到其右子树中的最小节点,替换删除节点的位置
TreeNode<T> tempNode = node;
node = GetMinNode(tempNode.RightChild);
node.RightChild = DelMin(tempNode.RightChild);
node.LeftChild = tempNode.LeftChild;
}
}
return node;
}
private TreeNode<T> GetMinNode(TreeNode<T> node)
{
while (node.LeftChild != null)
{
node = node.LeftChild;
}
return node;
}
// 递归方法实现体内再次调用方法本身的本质是多个方法的简写,递归一定要有出口
public void ShowTree()
{
HierarchyOrder(mRoot);
}
// 前序遍历:首先访问根结点,然后遍历其左子树,最后遍历其右子树。
private void PreOrder(TreeNode<T> node)
{
if (node == null)
{
return;
}
//打印节点数据
Console.WriteLine(node.Data);
PreOrder(node.LeftChild);
PreOrder(node.RightChild);
}
// 对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。
// 前序遍历
private void PreOrder1(TreeNode<T> node)
{
Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
TreeNode<T> curNode = node;
s.Push(node);
while (s.Count > 0)
{
Console.WriteLine(curNode.Data);
if (curNode.RightChild != null)
{
s.Push(curNode.RightChild);
}
if (curNode.LeftChild != null)
{
curNode = curNode.LeftChild;
}
else
{
//左子树访问完了,访问右子树
curNode = s.Pop();
}
}
}
// 中序遍历:首先遍历其左子树,然后访问根结点,最后遍历其右子树。
private void InOrder(TreeNode<T> node)
{
if (node == null)
{
return;
}
InOrder(node.LeftChild);
//打印节点数据
Console.WriteLine(node.Data);
InOrder(node.RightChild);
}
// 对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。
// 中序遍历
private void InOrder1(TreeNode<T> node)
{
Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
TreeNode<T> curNode = node;
while (curNode != null || s.Count > 0)
{
while (curNode != null)
{
s.Push(curNode);
curNode = curNode.LeftChild;
}
if (s.Count > 0)
{
curNode = s.Pop();
Console.WriteLine(curNode.Data);
curNode = curNode.RightChild;
}
}
}
// 后序遍历:首先遍历其左子树,然后遍历其右子树,最后访问根结点。
private void PostOrder(TreeNode<T> node)
{
if (node == null)
{
return;
}
PostOrder(node.LeftChild);
PostOrder(node.RightChild);
//打印节点数据
Console.WriteLine(node.Data);
}
// 后序遍历
private void PostOrder1(TreeNode<T> node)
{
Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
TreeNode<T> curNode = null;
TreeNode<T> preNode = null;
s.Push(node);
while (s.Count > 0)
{
curNode = s.Peek();
if ((curNode.LeftChild == null && curNode.RightChild == null) ||
(preNode != null && (preNode == curNode.LeftChild || preNode == curNode.RightChild)))
{
//如果当前结点没有孩子结点或者孩子节点都已被访问过
Console.WriteLine(curNode.Data);
s.Pop();
preNode = curNode;
}
else
{
if (curNode.RightChild != null)
{
s.Push(curNode.RightChild);
}
if (curNode.LeftChild != null)
{
s.Push(curNode.LeftChild);
}
}
}
}
// 层次遍历
private void HierarchyOrder(TreeNode<T> node)
{
Queue<TreeNode<T>> s = new Queue<TreeNode<T>>();
s.Enqueue(node);
while(s.Count > 0)
{
TreeNode<T> curNode = s.Dequeue();
Console.WriteLine(curNode.Data);
if(curNode.LeftChild != null)
{
s.Enqueue(curNode.LeftChild);
}
if(curNode.RightChild != null)
{
s.Enqueue(curNode.RightChild);
}
}
}
}
public class TreeNode<T>
{
//数据
public T Data { get; set; }
//左孩子
public TreeNode<T> LeftChild { get; set; }
//右孩子
public TreeNode<T> RightChild { get; set; }
public TreeNode(T value, int count)
{
Data = value;
LeftChild = null;
RightChild = null;
}
}
}