树及树的遍历

1 树

树,顾名思义,长得像一棵树,不过通常我们画成一棵倒过来的树,根在上,叶在下。

1.1 树的一些概念

树及树的遍历


树还可以表示成下面这种方式:

树及树的遍历

从上图可以看出:树可以用来描述包含关系,但包含关系不得出现交叉重叠区域,否则就不能用树描述。


2 树的遍历

2.1 广度优先遍历

树及树的遍历

对于树的广度优先遍历,可以使用队列来完成。

示例:

树节点类:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  class  Node {
    private  String name;
    private  List<Node> childs;
 
    public  Node(String name) {
        super();
        this.name = name;
    }
 
    public  String getName() {
        return  name;
    }
 
    public  List<Node> getChilds() {
        return  childs;
    }
 
    public  void  setChilds(List<Node> childs) {
        this.childs = childs;
    }
}

测试代码:

?

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
public  class  Test {
 
    public  static  void  main(String[] args) {
        // 构造节点
        Node a = new  Node("A");
        Node b = new  Node("B");
        Node c = new  Node("C");
        Node d = new  Node("D");
        Node e = new  Node("E");
        Node f = new  Node("F");
        Node g = new  Node("G");
        Node h = new  Node("H");
        Node i = new  Node("I");
        Node j = new  Node("J");
        Node k = new  Node("K");
        Node l = new  Node("L");
 
        // 构造树
        a.setChilds(Arrays.asList(b, c, d));
        b.setChilds(Arrays.asList(e, f));
        d.setChilds(Arrays.asList(g, h, i));
        f.setChilds(Arrays.asList(j, k));
        h.setChilds(Arrays.asList(l));
 
        // 创建队列
        Queue<Node> que = new  ArrayDeque<Node>();
 
        que.offer(a);
 
        // 操作队列
        while  (!que.isEmpty()) {
            Node temp = que.poll();
            System.out.print(temp.getName());
 
            List<Node> childs = temp.getChilds();
 
            if  (childs != null) {
                for  (int  iter = 0; iter < childs.size(); iter++) {
                    que.offer(childs.get(iter));
                }
            }
        }
    }
}

输出结果

?

1
ABCDEFGHIJKL

队列的状况如下图:

树及树的遍历

2.2 深度优先遍历

深度有限遍历分为:前序遍历(Preorder Traversal),后序遍历(Postorder Traversal)和中序遍历(Inorder Traversal)。

树及树的遍历

其中中序遍历只有对二叉树才有意义

树:

树及树的遍历

2.2.1 前序遍历:

?

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
package  com.demo2;
 
import  java.util.List;
 
//树节点
public  class  Node {
    private  String name;
    private  List<Node> childs;
 
    public  Node(String name) {
        super();
        this.name = name;
    }
 
    public  String getName() {
        return  name;
    }
 
    public  List<Node> getChilds() {
        return  childs;
    }
 
    public  void  setChilds(List<Node> childs) {
        this.childs = childs;
    }
 
    @Override
    public  String toString() {
        return  this.name;
    }
}

?

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
package  com.demo2;
 
import  java.util.ArrayDeque;
import  java.util.Arrays;
import  java.util.Deque;
import  java.util.List;
 
//测试类
public  class  Test {
    public  static  void  main(String[] args) {
        // 构造节点
        Node a = new  Node("A");
        Node b = new  Node("B");
        Node c = new  Node("C");
        Node d = new  Node("D");
        Node e = new  Node("E");
        Node f = new  Node("F");
        Node g = new  Node("G");
        Node h = new  Node("H");
        Node i = new  Node("I");
        Node j = new  Node("J");
        Node k = new  Node("K");
        Node l = new  Node("L");
 
        // 构造树
        a.setChilds(Arrays.asList(b, c, d));
        b.setChilds(Arrays.asList(e, f));
        d.setChilds(Arrays.asList(g, h, i));
        f.setChilds(Arrays.asList(j, k));
        h.setChilds(Arrays.asList(l));
 
        // 创建栈
        Deque<Node> que = new  ArrayDeque<Node>();
        que.push(a);
 
        // 前序遍历
        System.out.println("前序遍历");
        while  (!que.isEmpty()) {
            Node nodeTemp = que.pop();
 
            System.out.print(nodeTemp.getName());
 
            List<Node> childs = nodeTemp.getChilds();
 
            if  (childs != null) {
                for  (int  iter = childs.size() - 1; iter >= 0; iter--) {
                    que.push(childs.get(iter));
                }
            }
        }
 
    }
}

输出结果:

?

1
2
前序遍历
ABEFJKCDGHLI

2.2.2 后序遍历:

后序遍历需要标识“节点是否已经将它的子节点入栈”。因此,在树节点类Node中添加了一个属性boolean mark,mark为true时,表示该节点已经将它的子节点入栈;false表示还没有将该节点的子节点入栈。

?

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
package  com.demo3;
 
import  java.util.List;
 
//树节点类
public  class  Node {
    private  String name;
    private  List<Node> childs;
    private  boolean  mark;
 
    public  Node(String name) {
        super();
        this.name = name;
        this.mark = false;
    }
 
    public  String getName() {
        return  name;
    }
 
    public  List<Node> getChilds() {
        return  childs;
    }
 
    public  void  setChilds(List<Node> childs) {
        this.childs = childs;
    }
 
    public  boolean  isMark() {
        return  mark;
    }
 
    public  void  setMark(boolean  mark) {
        this.mark = mark;
    }
 
    @Override
    public  String toString() {
        return  this.name;
    }
}

?

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
package  com.demo3;
 
import  java.util.ArrayDeque;
import  java.util.Arrays;
import  java.util.Deque;
import  java.util.List;
 
//测试
public  class  Test {
    public  static  void  main(String[] args) {
        // 构造节点
        Node a = new  Node("A");
        Node b = new  Node("B");
        Node c = new  Node("C");
        Node d = new  Node("D");
        Node e = new  Node("E");
        Node f = new  Node("F");
        Node g = new  Node("G");
        Node h = new  Node("H");
        Node i = new  Node("I");
        Node j = new  Node("J");
        Node k = new  Node("K");
        Node l = new  Node("L");
 
        // 构造树
        a.setChilds(Arrays.asList(b, c, d));
        b.setChilds(Arrays.asList(e, f));
        d.setChilds(Arrays.asList(g, h, i));
        f.setChilds(Arrays.asList(j, k));
        h.setChilds(Arrays.asList(l));
 
        // 创建栈
        Deque<Node> que = new  ArrayDeque<Node>();
        que.push(a);
 
        // 后序遍历
        System.out.println("后序遍历");
        while  (!que.isEmpty()) {
            Node nodeTemp = que.peek();
 
            if  (nodeTemp.isMark()) {
                Node node = que.pop();
                System.out.print(node.getName());
            else  {
                List<Node> childs = nodeTemp.getChilds();
                if  (childs != null) {
                    for  (int  iter = childs.size() - 1; iter >= 0; iter--) {
                        que.push(childs.get(iter));
                    }
                }
 
                nodeTemp.setMark(true);
            }
        }
 
    }
}

输出结果:

?

1
2
后序遍历
EJKFBCGLHIDA

2.2.3 二叉树的中序遍历

根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:

   对于任一结点P,

  1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;

  2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;

  3)直到P为NULL并且栈为空则遍历结束

二叉树

树及树的遍历

?

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
//二叉树节点类
public  class  Node {
    private  String name;
 
    private  Node left;
    private  Node right;
 
    public  Node(String name) {
        super();
        this.name = name;
    }
 
    public  String getName() {
        return  name;
    }
 
    public  Node getLeft() {
        return  left;
    }
 
    public  void  setLeft(Node left) {
        this.left = left;
    }
 
    public  Node getRight() {
        return  right;
    }
 
    public  void  setRight(Node right) {
        this.right = right;
    }
 
    @Override
    public  String toString() {
        return  this.name;
    }
}

?

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
import  java.util.ArrayDeque;
import  java.util.Deque;
 
//测试
public  class  Test {
 
    public  static  void  main(String[] args) {
        // 构造节点
        Node a = new  Node("A");
        Node b = new  Node("B");
        Node c = new  Node("C");
        Node d = new  Node("D");
        Node e = new  Node("E");
        Node f = new  Node("F");
        Node g = new  Node("G");
        Node h = new  Node("H");
        Node i = new  Node("I");
        Node j = new  Node("J");
 
        // 构造树
        a.setLeft(b);
        a.setRight(c);
        b.setLeft(d);
        b.setRight(e);
        c.setLeft(f);
        c.setRight(g);
        e.setLeft(h);
        e.setRight(i);
        g.setLeft(j);
 
        // 创建栈
        Deque<Node> que = new  ArrayDeque<Node>();
 
        Node currNode = a;
 
        // 中序遍历算法
        System.out.println("中序遍历:");
        while  (currNode != null  || !que.isEmpty()) {
            while  (currNode != null) {
                que.push(currNode);
                currNode = currNode.getLeft();
            }
 
            currNode = que.pop();
            System.out.print(currNode.getName());
 
            currNode = currNode.getRight();
        }
    }
}

输出结果:

?

1
2
中序遍历:
DBHEIAFCJG

你可能感兴趣的:(树及树的遍历)