Java实现二叉树的遍历.docx
《Java实现二叉树的遍历.docx》由会员分享,可在线阅读,更多相关《Java实现二叉树的遍历.docx(58页珍藏版)》请在冰豆网上搜索。
Java实现二叉树的遍历
一、数据结构分类
(一)按逻辑结构
1.集合(无辑关系)
2.线性结构(线性表):
数组、链表、栈、队列
3.非线性结构:
树、图、多维数组
(二)按存储结构
顺序(数组)储结构、链式储结构、索引储结构、散列储结构
二、二叉树相关性质
∙结点的度:
一个结点的子树的个数记为该结点的度.
∙树的度:
所有节点中度数最大的结节的度数,叶子节点的度为零。
∙树的高度:
一棵树的最大层次数记为树的高度(或深度)。
∙有序(无序)树:
若将树中结点的各子树看成是从左到右具有次序的,即不能交换,则称该树为有序树。
否则称为无序树。
∙二叉树第i层(i≥1)上至多有2^(i-1)个节点。
∙深度为k的二叉树至多有2^k-1个节点(k≥1)。
∙对任何一棵二叉,若叶子节点数为n0,度为2的节点数为n2,则n0=n2+1。
∙具有n个节点的完全二叉树的深度为(㏒2^n)(向下取整)+1。
∙对一棵有n个节点的完全二叉树的节点按层次从上到下,自左至右进行编号,则对任一节点i(1≤i≤n)有:
若i=1,则节点i是二叉树的根,无双亲;若i>1,则其双亲为i/2(向下取整)。
若2i>n,则节点i没有孩子节点,否则其左孩子为2i。
若2i+1>n,则节点i没有右孩子,否则其右孩子为2i+1。
∙若深度为k的二叉树有2^k-1个节点,则称其为满二叉树。
满二叉树是一棵完全二叉树。
∙对于完全二叉树中,度为1的节点个数只可能为1个或0个。
∙对于二叉树,如果叶子节点数为n0,度为1的节点数为n1,度为2的节点数为n2,则节点总数n=n0+n1+n2。
∙对于任意树,总节点数=每个节点度数和+1
∙二叉树的高度等于根与最远叶节点(具有最多祖先的节点)之间分支数目。
空树的高度是-1。
只有单个元素的二叉树,其高度为0。
.
三、二叉树的遍历
遍历是按某种策略访问树中的每个节点,且仅访问一次。
(一)二叉树结构实现
Java代码
1.package tree.bintree;
2./**
3. * 创建 非完全二叉树、完全二叉树、满二叉树
4. *
5. * 由于二叉树的节点增加没有什么规则,所以这里只是简单的使用了递一
6. * 次性把整棵树创建出来,而没有设计出一个一个添加节点的方法与删除
7. *
8. * @author jzj
9. * @date 2009-12-23
10. */
11.public class BinTree {// Bin=Binary(二进位的, 二元的)
12.
13. protected Entry root;//根
14. private int size;//树的节点数
15.
16. /**
17. * 树的节点结构
18. * @author jzj
19. * @date 2009-12-23
20. */
21. protected static class Entry {
22. int elem;//数据域,这里我们作为编号
23. Entry left;//左子树
24. Entry right;//右子树
25.
26. public Entry(int elem) {
27. this.elem = elem;
28. }
29.
30. public String toString() {
31. return " number=" + elem;
32. }
33. }
34.
35. /**
36. * 根据给定的节点数创建一个完全二叉树或是满二叉树
37. * @param nodeCount 要创建节点总数
38. */
39. public void createFullBiTree(int nodeCount) {
40. root = recurCreateFullBiTree(1, nodeCount);
41. }
42.
43. /**
44. * 递归创建完全二叉树
45. * @param num 节点编号
46. * @param nodeCount 节点总数
47. * @return TreeNode 返回创建的节点
48. */
49. private Entry recurCreateFullBiTree(int num, int nodeCount) {
50. size++;
51. Entry rootNode = new Entry(num);//根节点
52. //如果有左子树则创建左子树
53. if (num * 2 <= nodeCount) {
54. rootNode.left = recurCreateFullBiTree(num * 2, nodeCount);
55. //如果还可以创建右子树,则创建
56. if (num * 2 + 1 <= nodeCount) {
57. rootNode.right = recurCreateFullBiTree(num * 2 + 1, nodeCount);
58. }
59. }
60. return (Entry) rootNode;
61. }
62.
63. /**
64. * 根据给定的数组创建一棵树,这个棵树可以是完全二叉树也可是普通二叉树
65. * 数组中为0的表示不创建该位置上的节点
66. * @param nums 数组中指定了要创建的节点的编号,如果为0,表示不创建
67. */
68. public void createBinTree(int[] nums) {
69. root = recurCreateBinTree(nums, 0);
70. }
71.
72. /**
73. * 递归创建二叉树
74. * @param nums 数组中指定了要创建的节点的编号,如果为0,表示不创建
75. * @param index 需要使用数组中的哪个元素创建节点,如果为元素为0,则不创建
76. * @return TreeNode 返回创建的节点,最终会返回树的根节点
77. */
78. private Entry recurCreateBinTree(int[] nums, int index) {
79. //指定索引上的编号不为零上才需创建节点
80. if (nums[index] !
= 0) {
81. size++;
82. Entry rootNode = new Entry(nums[index]);//根节点
83. //如果有左子树则创建左子树
84. if ((index + 1) * 2 <= nums.length) {
85. rootNode.left = (Entry) recurCreateBinTree(nums, (index + 1) * 2 - 1);
86. //如果还可以创建右子树,则创建
87. if ((index + 1) * 2 + 1 <= nums.length) {
88. rootNode.right = (Entry) recurCreateBinTree(nums, (index + 1) * 2);
89. }
90. }
91. return (Entry) rootNode;
92. }
93. return null;
94.
95. }
96.
97. public int size() {
98. return size;
99. }
100.
101. //取树的最左边的节点
102. public int getLast() {
103. Entry e = root;
104. while (e.right !
= null) {
105. e = e.right;
106. }
107. return e.elem;
108. }
109.
110. //测试
111. public static void main(String[] args) {
112.
113. //创建一个满二叉树
114. BinTree binTree = new BinTree();
115. binTree.createFullBiTree(15);
116. ;//15
117. ;//15
118.
119. //创建一个完全二叉树
120. binTree = new BinTree();
121. binTree.createFullBiTree(14);
122. ;//14
123. ;//7
124.
125. //创建一棵非完全二叉树
126. binTree = new BinTree();
127. int[] nums = new int[] { 1, 2, 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 7, 8 };
128. binTree.createBinTree(nums);
129. ;//8
130. ;//8
131.
132. }
133.}
(二)利用二叉树本身特点进行递归遍历(属内部遍历)
由于二叉树所具有的递归性质,一棵非空的二叉树可以看作是由根节点、左子树和右子树3部分构成,因为若能依次遍历这3部分的信息,也就遍历了整个二叉树。
按照左子树的遍历在右子树的遍历之前进行的约定,根据访问根节点位置的不同,可以得到二叉的前序、中序、后序3种遍历方法。
Java代码
1.package tree.bintree;
2.
3./**
4. * 二叉树的三种 内部 遍历:
前序、中序、后序
5. * 但不管是哪种方式,左子树的遍历在右子树的遍历之前遍历是这有三种遍历方式都
6. * 必须遵循的约定
7. * @author jzj
8. * @date 2009-12-23
9. */
10.public class BinTreeInOrder extends BinTree {
11.
12. /**
13. * 节点访问者,可根据需要重写visit方法
14. */
15. static abstract class Visitor {
16. void visit(Object ele) {
17. + " ");
18. }
19. }
20.
21. public void preOrder(Visitor v) {
22. preOrder(v, root);
23. }
24.
25. /**
26. * 树的前序递归遍历 pre=prefix(前缀)
27. * @param node 要遍历的节点
28. */
29. private void preOrder(Visitor v, Entry node) {
30. //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
31. if (node !
= null) {
32. v.visit(node.elem);//先遍历父节点
33. preOrder(v, node.left);//再遍历左节点
34. preOrder(v, node.right);//最后遍历右节点
35. }
36. }
37.
38. public void inOrder(Visitor v) {
39. inOrder(v, root);
40. }
41.
42. /**
43. * 树的中序递归遍历 in=infix(中缀)
44. * @param node 要遍历的节点
45. */
46. private void inOrder(Visitor v, Entry node) {
47. //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
48. if (node !
= null) {
49. inOrder(v, node.left);//先遍历左节点
50. v.visit(node.elem);//再遍历父节点
51. inOrder(v, node.right);//最后遍历右节点
52. }
53. }
54.
55. public void postOrder(Visitor v) {
56. postOrder(v, root);
57. }
58.
59. /**
60. * 树的后序递归遍历 post=postfix(后缀)
61. * @param node 要遍历的节点
62. */
63. private void postOrder(Visitor v, Entry node) {
64. //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
65. if (node !
= null) {
66. postOrder(v, node.left);//先遍历左节点
67. postOrder(v, node.right);//再遍历右节点
68. v.visit(node.elem);//最后遍历父节点
69. }
70. }
71.
72. //测试
73. public static void main(String[] args) {
74.
75. //创建二叉树
76. int[] nums = new int[] { 1, 2, 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 7, 8 };
77. BinTreeInOrder treeOrder = new BinTreeInOrder();
78. treeOrder.createBinTree(nums);
79. "前序遍历 - ");
80. treeOrder.preOrder(new Visitor() {
81. });
82. ;
83. "中序遍历 - ");
84. treeOrder.inOrder(new Visitor() {
85. });
86. ;
87. "后序遍历 - ");
88. treeOrder.postOrder(new Visitor() {
89. });
90. /*
91. * output:
92. * 前序遍历 - 1 2 4 6 3 5 7 8
93. * 中序遍历 - 4 6 2 1 3 7 5 8
94. * 后序遍历 - 6 4 2 7 8 5 3 1
95. */
96. }
97.}
(三)二叉树的非递归遍历(属外部遍历)
1、利用栈与队列对二叉树进行非递归遍历
Java代码
1.package tree.bintree;
2.
3.import ;
4.import ;
5.import ;
6.
7./**
8. * 二叉树的外部遍历:
深度优先(先根)、广度(层次)优先遍历
9. *
10. * @author jzj
11. * @date 2009-12-23
12. */
13.public class BinTreeOutOrder extends BinTree {
14.
15. /**
16. * 二叉树深序优先遍历(即二叉树的先根遍历)迭代器,外部可以使用该迭代器
17. * 进行非递归的遍历,这是一种在二叉树结构外部的一种遍历算法,它没有使用
18. * 二叉树本身的结构特点(左右子树递归)进行递归遍历
19. * @author jzj
20. */
21. private class DepthOrderIterator implements Iterator {
22. //栈里存放的是每个节点
23. private Stack stack = new Stack();
24.
25. public DepthOrderIterator(Entry node) {
26.
27. //根入栈,但在放入左右子节点前会马上出栈,即根先优于左右子节点访问
28. stack.push(node);
29.
30. }
31.
32. //是否还有下一个元素
33. public boolean hasNext() {
34. if (stack.isEmpty()) {
35. return false;
36. }
37. return true;
38. }
39.
40. //取下一个元素
41. public Entry next() {
42. if (hasNext()) {
43. //取栈顶元素
44. Entry treeNode = (Entry) stack.pop();//先访问根
45.
46. if (treeNode.right !
= null) {
47. stack.push(treeNode.right);//再放入右子节点
48. }
49.
50. if (treeNode.left !
= null) {
51. stack.push(treeNode.left);//最后放入左子节点,但访问先于右节点
52. }
53.
54. // 返回遍历得到的节点
55. return treeNode;
56.
57. } else {
58. // 如果栈