摘要: 一个二叉树的Java实现。可以学习广义表达式及二叉树的递归及非递归处理技巧。
难度:初级。
为了克服对树结构编程的畏惧感和神秘感,下定决心将二叉树的大部分操作实现一遍,并希望能够掌握二叉树编程的一些常用技术和技巧。
[1] 数据结构和表示: 二叉树的输入输出格式采用广义表表达式形式,内部表示采用左孩子右孩子的链式存储。
[2] 已经实现的操作有:
A. 根据二叉树的广义表表达式来创建二叉树(含表达式合法性检测);
B. 根据二叉树的前序和中序遍历列表来创建二叉树;
C. 根据二叉树的中序和后序遍历列表来创建二叉树;
D. 二叉树的“左孩子右孩子”链式存储转化为广义表表达式;
E. 二叉树的前序、中序、后序的递归和非递归遍历;层序遍历;结点关联列表;
F. 求解二叉树的高度、结点总数、叶子结点总数、所有的叶子结点列表;根结点到所有叶子结点的路径;最长路径;
G. 二叉树复制,二叉树全等性比较,二叉树交换(将二叉树的所有结点的左右子树互换)
[3] 尚待实现的操作:
A. 求解二叉树中所有最长(短)路径
E. 其它
[4] 二叉树 Java 实现代码:
1 /**
2 * BinaryTree: 实现二叉树,可以根据给定的广义表表达式、前序及中序遍历列表、中序及后序遍历列表创建二叉树;
3 * 二叉树的前序、中序、后序的递归和非递归遍历,层序遍历;求解二叉树的一些特性
4 *
5 * @author shuqin1984 2011-3-19
6 *
7 */
8 package datastructure.tree;
9 import java.util.ArrayList;
10 import java.util.Iterator;
11 import java.util.LinkedList;
12 import java.util.List;
13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern;
15
16 public class BinaryTree {
17
18 /** 二叉树的广义表表示 */
19 private String expression;
20 /** 树的根结点 */
21 private TreeNode root;
22
23 /**
24 * 用于检测二叉树广义表表达式合法性的编译了的正则表达式:
25 * 合法的广义表表达式可以是:
26 * [1] 基本表达式: A,A(,), A(B,), A(,B), A(B,C)
27 * [2] 上述的 A,B,C 可以是 [1] 中的基本表达式
28 * [3] A,B,C 可允许的取值范围由应用决定,这里仅允许是 大小写字母,数字,+-/*%
29 * [4] 表达式中不含任何空格符,因此,在检查表达式之前,必须确保表达式中不含空格符
30 *
31 */
32 private static String permittedChars = "[a-zA-Z0-9//+//-//*/////%]";
33 private static String basicUnit = "[a-zA-Z0-9//+//-//*/////%//(//),]";
34 private static Pattern basicPattern = Pattern.compile("" + "|" + permittedChars + "|" + permittedChars + "//(" + permittedChars + "?," + permittedChars + "?//)?");
35 private static Pattern extendPattern = Pattern.compile(permittedChars + "//(" + basicUnit + "*," + basicUnit + "*//)");
36
37 /**
38 * 构造器
39 * @param root 树的根结点
40 */
41 public BinaryTree(TreeNode root) {
42 this.root = root;
43 }
44
45 /**
46 * 构造器
47 * @param expression 二叉树的广义表表达式
48 */
49 private BinaryTree(String expression) {
50 this.expression = expression;
51 }
52 /**
53 * 树结点实现
54 */
55 private class TreeNode {
56
57 private char ch;
58 private TreeNode rchild;
59 private TreeNode lchild;
60
61 public TreeNode(char ch, TreeNode rchild, TreeNode lchild) {
62 this.ch = ch;
63 this.rchild = rchild;
64 this.lchild = lchild;
65 }
66 public char getCh() {
67 return ch;
68 }
69 public TreeNode getRchild() {
70 return rchild;
71 }
72 public void setRchild(TreeNode rchild) {
73 this.rchild = rchild;
74 }
75 public TreeNode getLchild() {
76 return lchild;
77 }
78 public void setLchild(TreeNode lchild) {
79 this.lchild = lchild;
80 }
81
82 public String toString()
83 {
84 return "" + getCh();
85 }
86 }
87
88 /**
89 * 结点关联类
90 */
91 private class NodeLink {
92
93 private TreeNode node1;
94 private TreeNode node2;
95
96 public NodeLink(TreeNode node1, TreeNode node2) {
97 this.node1 = node1;
98 this.node2 = node2;
99 }
100
101 public String toString() {
102
103 return "(" + node1.getCh() + "," + node2.getCh() + ")";
104 }
105
106 }
107
108 /**
109 * 【设置/获取】属性
110 */
111 public TreeNode getRoot() {
112 return root;
113 }
114 public void setRoot(TreeNode root) {
115 this.root = root;
116 }
117
118
119 /**
120 * getPreOrderList: 获得树的先序遍历列表
121 * @param flag 是否采用递归遍历的标记;若 flag = true, 采用递归遍历;否则,采用非递归遍历
122 * @return 二叉树的先序遍历列表
123 */
124
125 public List<TreeNode> getPreOrderList(boolean flag) {
126
127 List<TreeNode> nodelist = new ArrayList<TreeNode>();
128 if (flag == true) {
129 nodelist = preOrderTraverse(getRoot(), nodelist);
130 }
131 else {
132 nodelist = preOrderTraverseIter(getRoot());
133 }
134 return nodelist;
135 }
136
137 /**
138 * getInOrderList: 获得树的中序遍历列表
139 * @param flag 是否采用递归遍历的标记;若 flag = true, 采用递归遍历;否则,采用非递归遍历
140 * @return 获得树的中序遍历列表
141 */
142
143 public List<TreeNode> getInOrderList(boolean flag) {
144
145 List<TreeNode> nodelist = new ArrayList<TreeNode>();
146 if (flag == true) {
147 nodelist = inOrderTraverse(getRoot(), nodelist);
148 }
149 else {
150 nodelist = inOrderTraverseIter(getRoot());
151 }
152 return nodelist;
153 }
154
155 /**
156 * getPostOrderList: 获得树的后序遍历列表
157 * @param flag 是否采用递归遍历的标记;若 flag = true, 采用递归遍历;否则,采用非递归遍历
158 * @return 获得树的后序遍历列表
159 */
160
161 public List<TreeNode> getPostOrderList(boolean flag) {
162
163 List<TreeNode> nodelist = new ArrayList<TreeNode>();
164 if (flag == true) {
165 nodelist = postOrderTraverse(getRoot(), nodelist);
166 }
167 else {
168 nodelist = postOrderTraverseIter(getRoot());
169 }
170 return nodelist;
171 }
172
173 /**
174 * 获得树的层序遍历列表
175 *
176 * @return 获得树的层序遍历列表
177 */
178
179 public List<TreeNode> getFloorOrderList() {
180
181 List<TreeNode> nodelist = new ArrayList<TreeNode>();
182 nodelist = floorOrderTraverse(getRoot());
183 return nodelist;
184 }
185
186 /**
187 * createBinaryTree: 根据树的广义表表示构造二叉树
188 * @throws Exception
189 */
190 public static BinaryTree createBinaryTree(String expression) throws Exception
191 {
192 BinaryTree bt = new BinaryTree(trimSpace(expression));
193 bt.createBinaryTree();
194 return bt;
195 }
196
197 /**
198 * createBinaryTree: 根据二叉树的广义表表达式来创建二叉树
199 * @exception 若二叉树的广义表表达式不合法,则抛出异常
200 */
201 private void createBinaryTree() throws Exception {
202
203 // 检查传入的二叉树广义表示法是否合法有效
204 if (!checkValid(expression))
205 throw new Exception("广义表表达式不合法,无法创建二叉树!");
206
207 // 使用 LinkedList 来执行栈的功能
208 LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
209 TreeNode newnode = null;
210 int flag = 0; // flag = 0: 创建左子树 | flag = 1: 创建右子树
211
212 for (char ch: expression.toCharArray()) {
213 switch (ch) {
214
215 // 遇到 "(" 时,表示该结点可能有孩子结点,将该父结点压入栈中
216 case '(':
217 stack.push(newnode);
218 flag = 0;
219 break;
220
221 // 遇到 ")" 时,表示已经扫描完父结点的右孩子结点的值,弹出该父结点
222 case ')':
223 stack.pop();
224 break;
225
226 // 遇到 "," 时, 表示将要扫描父结点的右孩子结点的值。
227 case ',':
228 flag = 1;
229 break;
230
231 // 遇到结点的值,将其加入二叉树中
232 default:
233
234 newnode = new TreeNode(ch, null, null);
235 if (root == null) {
236 root = newnode;
237 }
238 else {
239 if (flag == 0) {
240 TreeNode topnode = stack.peek();
241 topnode.setLchild(newnode);
242 }
243 else
244 {
245 TreeNode topnode = stack.peek();
246 topnode.setRchild(newnode);
247 }
248 }
249 break;
250 }
251 }
252 }
253
254 /**
255 * checkValid: 判断给定二叉树的广义表表示是否合法有效
256 *
257 * @param expression 给定二叉树的广义表表示【字符串形式】
258 * @return 如果给定的二叉树广义表表示合法有效,返回true; 否则,返回 false
259 *
260 */
261 private static boolean checkValid(String expression)
262 {
263 Matcher m = null;
264 if (basicPattern.matcher(expression).matches())
265 return true;
266 else if ((m = extendPattern.matcher(expression)).matches()) {
267 int index = separatorIndex(expression);
268 if (index == -1) { // 不存在能够分割二叉树广义表达式的左右子树表达式的逗号
269 return false;
270 }
271 String rightEx = "";
272 String leftEx = "";
273 if (index > 2) {
274 leftEx = expression.substring(2, index); // 左子树的广义表达式
275 }
276 if (index < expression.length()-2) {
277 rightEx = expression.substring(index+1, expression.length()-1); // 右子树的广义表达式
278 }
279 return checkValid(leftEx) && checkValid(rightEx);
280 }
281 else {
282 return false;
283 }
284 }
285
286
287 /**
288 * getGeneralList: 获取该二叉树的广义表表示(字符串表示)
289 */
290 public String getGeneralListString()
291 {
292 StringBuilder sb = new StringBuilder("");
293 if (expression == null) {
294 createGeneralList(root, sb);
295 return sb.toString();
296 }
297 return expression;
298 }
299
300 /**
301 * getGeneralList: 根据给定二叉树生成其广义表表示(字符串形式)
302 * @param root 树的根结点
303 * @return 树的广义表表示【字符串形式】
304 */
305 private void createGeneralList(TreeNode root, StringBuilder sb) {
306
307 if (root != null) {
308
309 sb.append(root.getCh());
310 if (root.getLchild() != null || root.getRchild() != null) {
311 sb.append('(');
312 if (root.getLchild() != null) {
313 createGeneralList(root.getLchild(), sb);
314 }
315 sb.append(',');
316 if (root.getRchild() != null) {
317 createGeneralList(root.getRchild(), sb);
318 }
319 sb.append(')');
320 }
321 }
322 }
323
324 /**
325 * size: 获取二叉树的结点总数
326 *
327 * @param root 树的根结点
328 * @return 树的结点总数
329 *
330 */
331 public int size(TreeNode root) {
332
333 if (root == null)
334 return 0;
335 else {
336 return size(root.getLchild()) + size(root.getRchild()) + 1;
337 }
338 }
339
340 /**
341 * leafCounter: 获取二叉树的叶子结点数目
342 *
343 * @param root 树的根结点
344 * @return 树的叶子结点数目
345 *
346 */
347 public int leafCounter(TreeNode root) {
348 if (root == null)
349 return 0;
350 else {
351 if (root.getLchild() == null && root.getRchild() == null)
352 return 1;
353 else
354 return leafCounter(root.getLchild()) + leafCounter(root.getRchild());
355 }
356 }
357
358 /**
359 * getLeafNodes : 获取该二叉树的所有叶子结点
360 */
361 public List<TreeNode> getLeafNodes()
362 {
363 List<TreeNode> leaflist = new ArrayList<TreeNode>();
364 getLeafNodes(getRoot(), leaflist);
365 return leaflist;
366 }
367
368 /**
369 * printLeafPaths : 打印该二叉树的所有叶子结点到根的路径
370 */
371 public void printLeafPaths()
372 {
373 List<TreeNode> leafPath = new ArrayList<TreeNode>();
374 buildLeafPaths(root, leafPath);
375 }
376
377 /**
378 * buildLeafPaths : 递归求解给定二叉树的所有叶子结点到根的路径
379 * @param root 给定二叉树的根结点
380 * @param path 存放某个叶子结点到根的路径
381 */
382 public void buildLeafPaths(TreeNode root, List<TreeNode> path)
383 {
384 if (root != null) {
385 path.add(root); // 将从根结点到叶子结点的路径上的结点保存起来
386 if (root.getLchild() == null && root.getRchild() == null) { // 到达叶子结点,完成一条路径,并可对其处理
387 processPath(path);
388 }
389 else {
390 buildLeafPaths(root.getLchild(), path);
391 if (root.getLchild() != null) {
392 path.remove(path.size()-1); // 回溯,从左子树到右子树,删除前一条路径上的叶子结点
393 }
394 buildLeafPaths(root.getRchild(), path);
395 if (root.getRchild() != null) {
396 path.remove(path.size()-1);
397 }
398 }
399 }
400 }
401
402 /**
403 * processPath : 处理从某叶子结点到根结点的路径的操作
404 */
405 private void processPath(List<TreeNode> path)
406 {
407 System.out.println(listToString(path));
408 }
409
410 /**
411 * getLeafNodes: 递归求解给定二叉树的所有叶子结点
412 * @param root 给定二叉树的根结点
413 * @param leaflist 给定二叉树的所有叶子结点
414 */
415 private void getLeafNodes(TreeNode root, List<TreeNode> leaflist)
416 {
417 if (root != null) {
418 if (root.getLchild() == null && root.getRchild() == null) {
419 leaflist.add(root);
420 return ;
421 }
422 getLeafNodes(root.getLchild(), leaflist);
423 getLeafNodes(root.getRchild(), leaflist);
424 }
425 }
426
427
428 /**
429 * height: 获取二叉树的高度
430 *
431 * @param root 树的根结点
432 * @return 树的高度
433 *
434 */
435
436 public int height(TreeNode root)
437 {
438 if (root == null)
439 return 0;
440 else
441 return 1 + Math.max(height(root.getLchild()), height(root.getRchild()));
442 }
443
444 /**
445 * getNodelinkList: 获取该二叉树的结点关联列表
446 * @return 树的结点关联列表
447 */
448 public List<NodeLink> getNodelinkList() {
449
450 List<NodeLink> linklist = new ArrayList<NodeLink>();
451 createNodelinkList(getRoot(), linklist);
452 return linklist;
453
454 }
455
456 /**
457 * createNodelinkList: 递归求解给定二叉树的结点关联列表表示
458 * @param root 给定二叉树的根结点
459 * @param linklist 存放给定二叉树的结点关联对象
460 */
461 private void createNodelinkList(TreeNode root, List<NodeLink> linklist) {
462
463 if (root != null) {
464 if (root.getLchild() != null) {
465 NodeLink nodelink = new NodeLink(root, root.getLchild());
466 linklist.add(nodelink);
467 createNodelinkList(root.getLchild(), linklist);
468 }
469 if (root.getRchild() != null) {
470 NodeLink nodelink = new NodeLink(root, root.getRchild());
471 linklist.add(nodelink);
472 createNodelinkList(root.getRchild(), linklist);
473 }
474 }
475 }
476
477 /**
478 * preOrderTraverse: 二叉树的递归先序遍历
479 *
480 */
481 private List<TreeNode> preOrderTraverse(TreeNode root, List<TreeNode> nodelist) {
482
483 if (root != null) {
484 nodelist.add(root);
485 preOrderTraverse(root.getLchild(), nodelist);
486 preOrderTraverse(root.getRchild(), nodelist);
487 }
488
489 return nodelist;
490 }
491
492 /**
493 * preOrderTraverseIter: 二叉树的非递归先序遍历
494 */
495 private List<TreeNode> preOrderTraverseIter(TreeNode root) {
496 LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
497 List<TreeNode> nodelist = new ArrayList<TreeNode>();
498 TreeNode pNode = root;
499 for (;;) {
500 while (pNode != null) {
501 nodelist.add(pNode); // 访问根结点
502 stack.push(pNode); // 根结点入栈
503 pNode = pNode.getLchild(); // 访问左子树
504 }
505 pNode = stack.pop();
506 pNode = pNode.getRchild(); // 访问右子树
507 if (pNode == null && stack.isEmpty()) { break; }
508 }
509 return nodelist;
510 }
511
512 /**
513 * inOrderTraverse: 二叉树的递归中序遍历
514 *
515 */
516 private List<TreeNode> inOrderTraverse(TreeNode root, List<TreeNode> nodelist) {
517
518 if (root != null) {
519 inOrderTraverse(root.getLchild(), nodelist);
520 nodelist.add(root);
521 inOrderTraverse(root.getRchild(), nodelist);
522 }
523
524 return nodelist;
525 }
526
527 /**
528 * inOrderTraverseIter: 二叉树的非递归中序遍历
529 */
530
531 private List<TreeNode> inOrderTraverseIter(TreeNode root) {
532
533 LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
534 List<TreeNode> nodelist = new ArrayList<TreeNode>();
535
536 TreeNode pNode = root;
537 for (;;) {
538 while (pNode != null) { // 访问左子树
539 stack.push(pNode);
540 pNode = pNode.getLchild();
541 }
542 pNode = stack.pop();
543 nodelist.add(pNode); // 访问根结点
544 pNode = pNode.getRchild(); // 访问右子树
545 if (pNode == null && stack.isEmpty()) { break; }
546 }
547
548 return nodelist;
549 }
550
551 /**
552 * postOrderTraverse: 二叉树的递归后序遍历
553 */
554 private List<TreeNode> postOrderTraverse(TreeNode root, List<TreeNode> nodelist) {
555
556 if (root != null) {
557 postOrderTraverse(root.getLchild(), nodelist);
558 postOrderTraverse(root.getRchild(), nodelist);
559 nodelist.add(root);
560 }
561
562 return nodelist;
563 }
564
565 /**
566 * postOrderTraverseIter: 二叉树的非递归后序遍历
567 */
568 private List<TreeNode> postOrderTraverseIter(TreeNode root) {
569
570 LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
571 List<TreeNode> nodelist = new ArrayList<TreeNode>();
572
573 int flag = 0; // 标识是否访问过右子树; flag = 0 表示没有访问; flag = 1 表示已经访问过
574 TreeNode pNode = root;
575 TreeNode tmpNode = null;
576 loop1:
577 for (;;) {
578 while (pNode != null) { // 访问左子树
579 stack.push(pNode);
580 pNode = pNode.getLchild();
581 flag = 0;
582 }
583 loop2:
584 for (;;) {
585 if (!stack.isEmpty()) {
586
587 if (flag == 0) // 尚未访问根结点的右子树
588 {
589 pNode = stack.peek(); // 取根结点的右子树,访问其右子树
590 pNode = pNode.getRchild();
591 flag = 1;
592 continue loop1;
593 }
594
595 if (flag == 1) { // 已经访问过右子树
596 pNode = stack.pop();
597 nodelist.add(pNode); // 访问根结点,实际上是左右子树均为空的叶子结点
598 tmpNode = pNode; // 访问某个结点后,立即访问其父结点的右子树
599 pNode = stack.peek(); // 取该结点的父结点
600 if (pNode != null) { // 父结点不为空(没有回溯到整棵树的根结点)
601 if (tmpNode == pNode.getRchild()) {
602 // 如果刚刚访问的结点正是其父结点的右孩子,则直接回溯访问其父结点;
603 continue loop2;
604 }
605 else { // 否则,访问其父结点的右子树
606 pNode = pNode.getRchild();
607 continue loop1;
608 }
609 }
610
611 }
612
613
614 }
615 else // 栈空,递归调用结束,退出
616 {
617 break loop1;
618 }
619 }
620
621 }
622 return nodelist;
623 }
624
625 /**
626 * floorOrderTraverse: 二叉树的层序遍历
627 *
628 * @param root 树的根结点
629 * @return 树的层序遍历列表
630 *
631 */
632 private List<TreeNode> floorOrderTraverse(TreeNode root) {
633
634 // 使用 LinkedList 来执行队列的功能
635 LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
636 List<TreeNode> nodelist = new ArrayList<TreeNode>();
637 if (root != null) {
638 nodelist.add(root);
639 queue.addLast(root);
640 while(queue.size() > 0) {
641 TreeNode node = queue.removeFirst();
642 if (node.getLchild() != null) {
643 nodelist.add(node.getLchild());
644 queue.addLast(node.getLchild());
645 }
646 if (node.getRchild() != null) {
647 nodelist.add(node.getRchild());
648 queue.addLast(node.getRchild());
649 }
650 }
651 }
652
653 return nodelist;
654 }
655
656 /**
657 * copyBinaryTree: 复制二叉树
658 * @return 复制后的二叉树
659 */
660 public BinaryTree copyBinaryTree()
661 {
662 TreeNode anotherRoot = null;
663 anotherRoot = copy(getRoot());
664 return new BinaryTree(anotherRoot);
665 }
666
667 /**
668 * copy: 复制二叉树
669 * @param srcRoot 要复制的二叉树的根结点
670 * @param destRoot 目标二叉树的根结点
671 */
672 private TreeNode copy(TreeNode srcRoot)
673 {
674 if (srcRoot != null) {
675 TreeNode newNode = new TreeNode(srcRoot.getCh(), null, null);
676 newNode.setLchild(copy(srcRoot.getLchild()));
677 newNode.setRchild(copy(srcRoot.getRchild()));
678 return newNode;
679 }
680 return null;
681 }
682
683 /**
684 * equalsTo: 比较该二叉树与给定二叉树 another 是否全等;
685 * 若全等则返回 true, 否则返回 false.
686 */
687 public boolean equalsTo(BinaryTree another)
688 {
689 return compareEqual(root, another.getRoot());
690 }
691
692 /**
693 * equalsTo : 比较给定的两个二叉树是否全等
694 * 两个二叉树全等当且仅当
695 * A. 两个二叉树均为空; 或者
696 * B. 两个二叉树均非空,且所有对应位置的结点都相同,对应结点之间的关联也完全相同.
697 */
698 private boolean compareEqual(TreeNode root, TreeNode anotherRoot)
699 {
700 return (root == null && anotherRoot == null) ||
701 ((root != null && anotherRoot != null) &&
702 (root.getCh() == anotherRoot.getCh()) &&
703 (compareEqual(root.getLchild(), anotherRoot.getLchild())) &&
704 (compareEqual(root.getRchild(), anotherRoot.getRchild())));
705 }
706
707 /**
708 * swapTree : 将该二叉树的所有结点的左右孩子互换
709 */
710 public void swapTree()
711 {
712 StringBuilder sb = new StringBuilder("");
713 swapTree(root);
714 createGeneralList(root, sb);
715 expression = sb.toString();
716 }
717
718 /**
719 * swapTree : 将给定的二叉树的所有结点的左右孩子互换
720 * @param root 给定二叉树的根结点
721 */
722 private void swapTree(TreeNode root)
723 {
724 if (root != null) {
725 TreeNode tmp = root.getLchild();
726 root.setLchild(root.getRchild());
727 root.setRchild(tmp);
728 swapTree(root.getLchild());
729 swapTree(root.getRchild());
730 }
731 }
732
733 /**
734 * longestPath: 获取该二叉树中的一条最长路径
735 * @return 二叉树中的一条最长路径
736 */
737 public List<TreeNode> longestPath()
738 {
739 List<TreeNode> longestPath = new ArrayList<TreeNode>();
740 longestPath(root, longestPath);
741 return longestPath;
742 }
743
744 /**
745 * longestPath: 递归求解给定二叉树的一条最长路径
746 * @param root 给定二叉树的根结点
747 * @param longestPath 存放二叉树的最长路径上的结点
748 */
749 private void longestPath(TreeNode root, List<TreeNode> longestPath)
750 {
751 if (root != null) {
752 longestPath.add(root);
753 if (root.getLchild() == null && root.getRchild() == null) { // 左右子树均空
754 return ;
755 }
756 if (root.getLchild() != null && root.getRchild() == null) { // 左子树非空,右子树为空,则最长路径的结点必在左子树路径上
757 longestPath(root.getLchild(), longestPath);
758 }
759 if (root.getLchild() == null && root.getRchild() != null) { // 左子树非空,右子树为空,则最长路径的结点必在右子树路径上
760 longestPath(root.getRchild(), longestPath);
761 }
762 if (root.getLchild() != null && root.getRchild() != null) { // 左右子树均非空;分别求解左右子树的最长路径,取最大者
763 List<TreeNode> leftLongestPath = new ArrayList<TreeNode>();
764 List<TreeNode> rightLongestPath = new ArrayList<TreeNode>();
765 longestPath(root.getLchild(), leftLongestPath);
766 longestPath(root.getRchild(), rightLongestPath);
767 if (leftLongestPath.size() >= rightLongestPath.size()) {
768 longestPath.addAll(leftLongestPath);
769 } else if (leftLongestPath.size() < rightLongestPath.size()) {
770 longestPath.addAll(rightLongestPath);
771 }
772
773 }
774 }
775 }
776
777
778
779 /**
780 * listToString: 返回二叉树的结点列表的字符串表示
781 *
782 * @param nodelist 树的结点列表
783 * @return 二叉树的结点列表的字符串表示
784 *
785 */
786 public String listToString(List<TreeNode> nodelist) {
787
788 if (nodelist == null || nodelist.size() == 0) {
789 return "[ 空树 ]";
790 }
791 StringBuilder str = new StringBuilder("[");
792 Iterator<TreeNode> iter = nodelist.iterator();
793 while (iter.hasNext()) {
794 TreeNode node = iter.next();
795 str.append(node.getCh()+" ");
796 }
797 str.deleteCharAt(str.length()-1);
798 str.append(']');
799 return str.toString();
800 }
801
802
803 /**
804 * createBinaryTree: 根据前序和中序遍历列表生成二叉树
805 *
806 * @param preOrderList 前序列表字符串
807 * @param inOrderList 中序列表字符串
808 * @throws Exception
809 *
810 */
811 public static BinaryTree createBinaryTree(String preOrderList, String inOrderList) throws Exception {
812 BinaryTree bt = new BinaryTree(getGeneralList(preOrderList, inOrderList));
813 bt.createBinaryTree();
814 return bt;
815 }
816
817 /**
818 * getGeneralist: 根据前序和中序遍历列表生成二叉树的广义表表示【字符串形式】
819 *
820 * @param preOrderList 前序列表字符串
821 * @param inOrderList 中序列表字符串
822 * @return generalList 广义表表示
823 *
824 */
825
826 private static String getGeneralList(String preOrderList, String inOrderList) {
827
828 String s = "";
829 if (preOrderList.length() > 0 || inOrderList.length() > 0) {
830
831 // 如果只含一个结点值,就直接返回
832 if (preOrderList.length() == 1)
833 return preOrderList;
834
835 // 根据前序遍历, 第一个是根结点的值
836 char ch = preOrderList.charAt(0);
837
838 // 根据中序遍历及根结点,将前序列表分为左右子树列表。
839 int index = inOrderList.indexOf(ch);
840 String inOrderLeft = inOrderList.substring(0, index); // 左子树的中序遍历列表
841 String inOrderRight = inOrderList.substring(index+1); // 右子树的中序遍历列表
842 String preOrderLeft = preOrderList.substring(1, inOrderLeft.length()+1); // 左子树的前序遍历列表
843 String preOrderRight = preOrderList.substring(inOrderLeft.length()+1); // 右子树的前序遍历列表
844 s += ch;
845 s += "(" + getGeneralList(preOrderLeft,inOrderLeft) + "," + getGeneralList(preOrderRight,inOrderRight) + ")";
846 }
847 return s;
848 }
849
850 /**
851 * createBinaryTree: 根据中序和后序遍历列表生成二叉树
852 *
853 * @param inOrderList 中序列表
854 * @param postOrderList 后序列表
855 * @param flag 标记
856 *
857 * @throws Exception
858 */
859 public static BinaryTree createBinaryTree(String inOrderList, String postOrderList, boolean flag) throws Exception {
860 BinaryTree bt = new BinaryTree(getGeneralList(inOrderList, postOrderList, flag));
861 bt.createBinaryTree();
862 return bt;
863 }
864
865
866
867 /**
868 * getGeneralList: 根据中序和后序遍历生成二叉树的广义表表示【字符串形式】
869 *
870 * @param inOrderList 中序列表
871 * @param postOrderList 后序列表
872 * @param flag 标记
873 * @return generalList 广义表表示
874 *
875 */
876
877 private static String getGeneralList(String inOrderList, String postOrderList, boolean flag) {
878
879 String s = "";
880 if (inOrderList.length() > 0 || postOrderList.length() >0) {
881
882 // 如果只含一个结点值,就直接返回
883 if (inOrderList.length() == 1)
884 return inOrderList;
885
886 // 根据后序遍历规则,最后一个是根结点的值
887 char ch = postOrderList.charAt(postOrderList.length()-1);
888
889 // 根据中序遍历及根结点,将前序列表分为左右子树列表。
890 int index = inOrderList.indexOf(ch);
891 String inOrderLeft = inOrderList.substring(0, index); // 左子树的中序遍历列表
892 String inOrderRight = inOrderList.substring(index+1); // 右子树的中序遍历列表
893 String postOrderLeft = postOrderList.substring(0, inOrderLeft.length()); // 左子树的前序遍历列表
894 String postOrderRight = postOrderList.substring(inOrderLeft.length(),
895 inOrderLeft.length()+inOrderRight.length()); // 右子树的前序遍历列表
896 s += ch;
897 s += "(" + getGeneralList(inOrderLeft,postOrderLeft,true) + "," + getGeneralList(inOrderRight,postOrderRight,true) + ")";
898 }
899 return s;
900 }
901
902 /**
903 * trimSpace: 将广义表表达式字符串中的空格符去掉
904 */
905 private static String trimSpace(String s)
906 {
907 StringBuilder sb = new StringBuilder("");
908 for (int i=0; i < s.length(); i++) {
909 char ch = s.charAt(i);
910 if (!(new Character(ch).toString().matches("//s"))) {
911 sb.append(ch);
912 }
913 }
914 return sb.toString();
915 }
916
917 /**
918 * separatorIndex : 求解广义表表达式中分割左右子树的分隔符的位置
919 * 由于这里使用逗号分割左右子树,则当且仅当其位置应当满足:
920 * 在该分割符之前,左括号的数目恰好比右括号的数目多1.
921 * @return 若存在满足条件的分隔符,则返回其位置;否则返回 -1
922 */
923 private static int separatorIndex(String expression)
924 {
925 int leftBracketCounter=0, rightBacketCounter=0;
926 int index = 0;
927 for (; index < expression.length(); index++) {
928 char ch = expression.charAt(index);
929 if (ch == '(') {
930 leftBracketCounter++;
931 }
932 else if (ch == ')') {
933 rightBacketCounter++;
934 }
935 else if (ch == ',') {
936 if (leftBracketCounter == rightBacketCounter+1) break;
937 }
938 }
939 if (index < expression.length()) {
940 return index;
941 }
942 return -1;
943 }
944
945 }