二叉树以及其节点的实现
1. 二叉树节点的定义及实现
根据二叉树的特点可知,二叉树的子节点最多有两个子树,分别是左子树和右子树。所以,一个二叉树的节点应有三个部分组成:
² 当前节点数据<T>;
² 左子节点的引用;
² 右子节点的引用。
如下图左部分的Node类定义。
Node类的实现:


/// <summary>
/// 二叉树节点代码
/// </summary>
/// <typeparam name="T"></typeparam>
public class Node<T>
{
private T _data;
private Node<T> _lChild;
private Node<T> _rChild;
/// <summary>
/// 二叉树当前节点的数据
/// </summary>
public T Data
{
get { return _data; }
set { _data = value; }
}
/// <summary>
/// 二叉树左子节点的引用
/// </summary>
public Node<T> LChild
{
get { return _lChild; }
set { _lChild = value; }
}
/// <summary>
/// 二叉树右子节点的引用
/// </summary>
public Node<T> RChild
{
get { return _rChild; }
set { _rChild = value; }
}
public Node()
{
_data = default(T);
_lChild = null;
_rChild = null;
}
public Node(T _data)
{
this._data = _data;
_lChild = null;
_rChild = null;
}
public Node(T _data, Node<T> _lChild, Node<T> _rChild)
{
this._data = _data;
this._lChild = _lChild;
this._rChild = _rChild;
}
public Node(Node<T> _lChild, Node<T> _rChild)
{
this._lChild = _lChild;
this._rChild = _rChild;
}
}
2 二叉树的实现
二叉树的实现主要有能下几个功能:
Ø 构造一个新的二叉树
Ø 插入指定节点的左子节点;
Ø 插入指定节点的右子节点;
Ø 删除指定节点的左子节点;
Ø 删除指定节点的右子节点;
Ø 判断二叉树是否为空;
Ø 判断节点是否为叶子节点。
代码实现如下:


1


2

3

4

5

6



7

8

9

10


11

12

13



14

15

16

17

18



19

20

21

22

23

24



25

26

27

28

29

30

31


32

33

34

35



36



37



38

39

40


41

42

43

44

45

46



47


48

49

50

51

52

53

54

55

56

57

58


59

60

61

62

63

64



65

66

67

68

69

70

71

72


73

74

75

76

77



78

79



80

81

82


83

84

85

86

87

88

89

90

91

92

93


94

95

96

97

98

99



100

101



102

103

104

105

106

107

108

109

110


111

112

113

114

115



116

117

118

119


120

121

122

123

124

125



126

127

128

129

3 二叉树的遍历
二叉树的遍历是按照某种顺序对树中的每个节点访问且只能访问一次的过程,包括查询、修改、计算等。
二叉树的遍历实际是将非线性结构线性化,它是二叉树的各种计算和操作的基础。
由二叉树的定义可知,一棵二叉树由根结点、左子树和右子树三部分组成,若规定D、L、R分别代表遍历根结点、遍历左子树、遍历右子树,则二叉树的遍历方式有6种:DLR、DRL、LDR、LRD、RDL、RLD。由于先遍历左子树和先遍历右子树在算法设计上没有本质区别,所以,只讨论三种方式:DLR(先序遍历)、LDR(中序遍历)和LRD(后序遍历)。
先序遍历:先访问根节点,再访问左子树,再访问右子树。
中序遍历:先访问左子树,再访问根节点,最后访问右子树。
后序遍历:先访问左子以,再访问右子树,最后访问根节点。
3.1 先序遍历(DLR)
先序遍历的基本思想是:首先访问根结点,然后先序遍历其左子树,最后先序遍历其右子树。先序遍历的递归算法实现如下。(这里只是获取节点的值)


/// <summary>
/// 先序遍历之递归
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public string perOrderNode(Node<char> node)
{
if (node == null)
return null;
StringBuilder nodeValues = new StringBuilder();
nodeValues.Append(node.Data);
//递归调用
nodeValues.Append(perOrderNode(node.LChild));
nodeValues.Append(perOrderNode(node.RChild));
return nodeValues.ToString();
}
public string perOrderRecursion(BinaryTree.BinaryTree<char> tree)
{
return perOrderNode(tree.Header);
}
非递归算法实现:


/// <summary>
/// 二叉树先序遍历之非递归算法
/// 利用栈实现二叉树的遍历.
/// </summary>
/// <param name="tree"></param>
/// <returns></returns>
public string perOrderNoRecursion(BinaryTree.BinaryTree<char> tree)
{
StringBuilder result = new StringBuilder();
Stack<Node<char>> rightStack = new Stack<Node<char>>();
Node<char> curNode = tree.Header;
while (curNode != null || rightStack.Count != 0)
{
if (curNode != null)
{
result.Append(curNode.Data);
if (curNode.RChild != null)
{
//如果右子节点不为NULL,则先放入Stack中.
rightStack.Push(curNode.RChild);
}
curNode = curNode.LChild;
}
else
{
curNode = rightStack.Pop();
}
}
return result.ToString();
}
3.2 中序遍历(LDR)
中序遍历的基本思想是:首先中序遍历根结点的左子树,然后访问根结点,最后中序遍历其右子树。中序遍历的递归算法实现如下: (附件)
3.3 后序遍历(LRD)
后序遍历的基本思想是:首先后序遍历根结点的左子树,然后后序遍历根结点的右子树,最后访问根结点。后序遍历的递归算法实现如下: (附件)
代码下载