二叉树的定义:
二叉树是节点的有限集合,该集合或者为空集,或者是由一个根和两颗互不相交的、称为该根的左子树和右子树的二叉树组成。
二叉树的性质:
1、二叉树第i(i>=1)层上至多有2^(i-1)个结点。
2、高度为h的二叉树至多有2^(h)-1个结点。
3、包含n个元素的二叉树的高度至少为log2(n+1)向上取整。
4、任意一颗二叉树中,若叶节点的个数为n0,度为2的结点的个数为n2,则必有n0=n2+1.
5、高度为h的二叉树恰好有2^(h)-1个结点时称为满二叉树。满二叉树是完全二叉树,也是扩充二叉树。
6、一颗二叉树中,只有最下面两层结点的度可以小于2,并且最下面一层的叶节点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。
7、扩充二叉树也称2-树,扩充二叉树中除叶子结点外,其余结点都必须有两个孩子。
8、具有n个结点的完全二叉树的高度为log2(n+1)向上取整。
9、假定对一颗有n个结点的完全二叉树中的结点,按从上到下,从左到右的顺序,从0到n-1编号,设树中某个结点的序号为i,0<=i
(1)当i=0时,该节点为二叉树的根。
(2)若i>0,则该结点的双亲的序号为(i-1)/2向下取整。
(3)若2i+1
(4)若2i+2
C#构建二叉树
1、建立二叉树的类
class Node
{
private object _data;//本节点数据
private Node _left;//左孩子
private Node _right;//右孩子
public object Data
{
get { return _left; }
set { _data = value; }
}
public Node Left
{
get { return _left; }
set { _left = value; }
}
public Node Right
{
get { return _right; }
set { _right = value; }
}
public Node(object data)
{
this._data = data;
}
public override string ToString()
{
return _data.ToString();
}
}
2、构建二叉树
class BinaryTreeFull
{
private Node _head;//头节点,是整个二叉树的入口
private string cStr;//将传入的初始化字符串转换为全局变量
public Node Head //调用Head就相当于拿到了整棵树
{
get { return _head; }
set { _head = value; }
}
public BinaryTreeFull()
{
_head = null;
}
public BinaryTreeFull(string constructStr)//默认以程序遍历构造二叉树
{
cStr = constructStr;//赋值给全局变量
if (cStr[0] == '#')//#表示空节点
{
_head = null;
return;//根节点为空
}
_head = new Node(cStr[0]);//把第一个字符加入二叉树,作为根结点
Add(_head, 0);
}
private void Add(Node parent, int index)
{
int leftIndex = 2 * index + 1;
if (leftIndex < cStr.Length)//存在左孩子
{
if (cStr[leftIndex] != '#')//不为空
{
parent.Left = new Node(cStr[leftIndex]);//加入该结点的左孩子
Add(parent.Left, leftIndex);//继续查找
}
}
int rightIndex = 2 * index + 2;
if (rightIndex < cStr.Length)//存在右孩子
{
if (cStr[rightIndex] != '#')//不为空
{
parent.Right = new Node(cStr[rightIndex]);//加入该结点的右孩子
Add(parent.Right, rightIndex);//继续查找
}
}
}
}
递归的方法遍历二叉树:
1、先序遍历
public void PreOrder(Node node)
{
if (node != null)//只要结点不为空,就输出结点值,然后查找左结点和右结点
{
Console.Write(node);//我在开始
PreOrder(node.Left);
PreOrder(node.Right);
}
}
2、中序遍历
public void InOrder(Node node)
{
if (node != null)
{
InOrder(node.Left);
Console.Write(node);//我在中间
InOrder(node.Right);
}
}
3、后续遍历
public void AfterOrder(Node node)
{
if (node != null)
{
AfterOrder(node.Left);
AfterOrder(node.Right);
Console.Write(node);//我在最后
}
}
4、计算叶子结点个数(先序遍历)
public void CountLeaf(Node node, ref int count)//count用于返回结点个数
{
if (node != null)
{
if ((node.Left == null) && (node.Right == null))
{
count++;
}
CountLeaf(node.Left, ref count);
CountLeaf(node.Right, ref count);
}
}
5、计算节点数
public int Count(Node root)
{
if (root == null) return 0;
return Count(root.Right) + Count(root.Left) + 1;
}
6、计算二叉树的高度
public int Height(Node root)
{
int a, b;
if (root == null) return 0;
a = Height(root.Left);
b = Height(root.Right);
if (a > b)
{
return a + 1;
}
else
{
return b + 1;
}
}
7、复制二叉树
public Node CopyTree(Node root)
{
Node newroot;
if (root == null)
{
newroot = null;
}
else
{
CopyTree(root.Left);
CopyTree(root.Right);
newroot = root;
}
return newroot;
}
8、先序遍历建立二叉树
public static BinaryTreeFull CreateByPre(string s)
{
BinaryTreeFull tree = new BinaryTreeFull(s);//先以层序初始化一个树,再调整
int _count = 0;
Node node = tree.Head;
Stack stack = new Stack();
while (node != null || stack.Count > 0)
{
while (node != null)
{
node.Data = s[_count++];
stack.Push(node);
node = node.Left;
}
if (stack.Count > 0)
{
node = stack.Pop();
node = node.Right;
}
}
return tree;
}
9、中序遍历建立二叉树
public static BinaryTreeFull CreateByIn(string s)
{
BinaryTreeFull tree = new BinaryTreeFull(s);
int _count = 0;
Node node = tree.Head;
Stack stack = new Stack();
while (node != null || stack.Count > 0)
{
while (node != null)
{
stack.Push(node);
node = node.Left;
}
if (stack.Count > 0)
{
node = stack.Pop();
node.Data = s[_count++];
node = node.Right;
}
}
return tree;
}
10、后序遍历建立二叉树
public static BinaryTreeFull CreateByAfter(string s)
{
BinaryTreeFull tree = new BinaryTreeFull(s);
int _count = 0;
Node node = tree.Head;
Node pre = tree.Head;
//pre指针指向“之前出栈节点”,如果为null有问题,因为后序遍历中头结点肯定值最后被访问的
Stack stack = new Stack();
while (node != null || stack.Count > 0)
{
while (node != null)
{
stack.Push(node);
node = node.Left;
}
if (stack.Count > 0)
{
Node temp = stack.Peek().Right;
if (temp == null || temp == pre)
{
node = stack.Pop();
node.Data = s[_count++];
pre = node;
node = null;
}
else
{
node = temp;
}
}
}
return tree;
}
非递归方法遍历二叉树:
1、先序遍历
public void PreStackOrder()
{
Node node = _head;
Stack stack = new Stack();
while (node != null || stack.Count > 0)
{
while (node != null)
{
Console.Write(node);
stack.Push(node);
node = node.Left;
}
if (stack.Count > 0)
{
node = stack.Pop();
node = node.Right;//如果出栈节点没有右孩子的话则继续出栈操作
}
}
}
2、中序遍历
public void InStackOrder()
{
Node node = _head;
Stack stack = new Stack();
while (node != null || stack.Count > 0)
{
while (node != null)
{
stack.Push(node);
node = node.Left;
}
if (stack.Count > 0)
{
node = stack.Pop();
Console.Write(node);
node = node.Right;
}
}
}
3、后续遍历(比较难,先存起来)
public void AfterStackOrder()
{
Stack lstack = new Stack();//用于存放父节点
Stack rstack = new Stack();//用于存放右孩子
Node node = _head, right;//right用于存放右栈出栈的节点
do
{
while (node != null)
{
right = node.Right;
lstack.Push(node);
rstack.Push(right);
node = node.Left;//沿左孩子的方向继续循环
}
node = lstack.Pop();
right = rstack.Pop();
if (right == null)//如果右出栈的元素为空则访问左边出栈的元素
{
Console.Write(node);
}
else
{
lstack.Push(node);//左边出栈元素退回栈
rstack.Push(null);//右边补充一个空元素
}
node = right;//如果右边出栈的部位空,则以上面的规则访问这个右孩子节点
}
while (lstack.Count > 0 || rstack.Count > 0);
}
3.2利用一个栈
public void AfterStackOrder2()//性能更优的单栈非递归算法
{
Node node = _head, pre = _head;
//pre指针指向“之前出栈节点”,如果为null有问题,这里指向头结点,因为后续遍历中头结点肯定值最后被访问的。
Stack stack = new Stack();
while (node != null || stack.Count > 0)
{
while (node != null)
{
stack.Push(node);
node = node.Left;
}
if (stack.Count > 0)
{
Node temp = stack.Peek().Right;//获取栈顶元素的右孩子
if (temp == null || temp == pre)//满足规则1
{
node = stack.Pop();
Console.Write(node);
pre = node;
node = null;
}
else
{
node = temp;//将栈顶节点的右孩子入栈
}
}
}
}
最后,感谢这位博主的文章,博主主页:http://www.cnblogs.com/zhanjindong