在一颗二叉树中寻找一个结点的后继结点(前驱结点)

在一颗二叉树中寻找一个结点的后继结点(前驱结点)

  • 找后继结点
  • 找前驱结点

找后继结点

首先知道什么是后继结点,就是二叉树中序遍历的序列中,某个结点紧随的那个结点比如下面的二叉树以及对应的中序遍历顺序。

这里写图片描述

4的后继是22的后继是57的后继是null

在树的结构中,每个结点有一个指向父亲的域parent,看如下结构

1
2
3
4
5
6
7
8
9
10
11
static class Node{
public int value;
public Node left;
public Node right;
public Node parent;

public Node(int value) {
this.value = value;
}
}

那么如何快速的寻找当前结点node后继结点呢? 其实只需要分为两种情况

  • 第一,如果node结点有右子树,那么就是右子树上最左的结点,例如上图的的右子树上的最左结点是55的右子树上最左的结点是81的右子树上最左的结点是93的右子树上最左的结点是7
  • 第二,如果node结点没有右子树,那么要分两种情况 : a. 看当前结点node 是不是它父亲(node.parent)的左孩子,如果是,那么它父亲(node.parent)就是它的后继;b.如果当前结点是它父亲的右孩子(node.parent.right == node),那么就向上不停的寻找它的后继结点,即当前结点为node,它的父亲为parent,如果node还是parent的右孩子,就令node= parent,parent = parent.parent,一直向上,直到parent.left = node,就停止,此时parent就是当初要找的结点的后继。

(1) 对于上面的第二种情况看上面的例子,首先a情况

这里写图片描述

(2) 然后再看第二种情况的b ,也就是往上找后继的过程

这里写图片描述

找前驱结点

这个和找后继是同理的:

  • 当一个结点有左子树的时候,就是最左子树的最右结点;
  • 没有左子树的时候,a. 看当前结点node 是不是它父亲(node.parent)的孩子,如果是,那么它父亲(node.parent)就是它的前驱;b. 如果当前结点是它父亲的左孩子(node.parent.left == node),那么就向上不停的寻找它的前驱结点,即当前结点为node,它的父亲为parent,如果node还是parent的左孩子,就令node= parent,parent = parent.parent,一直向上,直到parent.right = node,就停止,此时parent就是当初要找的结点的前驱。

完整的测试代码如下

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
/**
* 寻找结点的后继和前驱结点
*/
public class SuccessorNode {

static class Node {
public int value;
public Node left;
public Node right;
public Node parent;

public Node(int value) {
this.value = value;
}
}

//寻找某个结点的后继结点
static Node getSuccessorNode(Node node) {
if (node == null)
return null;
if (node.right != null)
return getMostLeft(node.right);//第一种情况  结点的右子树为null
else { //第二种情况
Node parent = node.parent;
while (parent != null && parent.left != node) {
node = parent;
parent = node.parent;
}
return parent;
}
}

//找到某个结点的最左边的结点
static Node getMostLeft(Node node) {
if (node == null)
return null;
while (node.left != null)
node = node.left;
return node;
}


//寻找某个结点的前驱结点
static Node getPrecursorNode(Node node) {
if (node == null)
return null;
if (node.left!= null)
return getMostRight(node.left);//第一种情况  结点的右子树为null
else { //第二种情况
Node parent = node.parent;
while (parent != null && parent.right != node) {
node = parent;
parent = node.parent;
}
return parent;
}
}

//找到某个结点的最右边的结点
static Node getMostRight(Node node) {
if (node == null)
return null;
while (node.right != null)
node = node.right;
return node;
}

public static void main(String[] args) {

//先创建上图的树
Node head = new Node(1);
head.left = new Node(2);
head.left.parent = head;
head.left.left = new Node(4);
head.left.left.parent = head.left;
head.left.right = new Node(5);
head.left.right.parent = head.left;
head.left.right.right = new Node(8);
head.left.right.right.parent = head.left.right;
head.right = new Node(3);
head.right.parent = head;
head.right.left = new Node(6);
head.right.left.parent = head.right;
head.right.left.left = new Node(9);
head.right.left.left.parent = head.right.left;
head.right.right = new Node(7);
head.right.right.parent = head.right;

System.out.println("----------test Successor----------");
Node node = head; //测试1
System.out.println(node.value + "'s next : " + getSuccessorNode(node).value);

node = head.left.left; //测试4
System.out.println(node.value + "'s next : " + getSuccessorNode(node).value);

node = head.left.right.right; // 测试8
System.out.println(node.value + "'s next : " + getSuccessorNode(node).value);


System.out.println("----------test Precursor----------");

node = head; //测试1
System.out.println(node.value + "'s next : " + getPrecursorNode(node).value);

node = head.right.left.left; // 测试9
System.out.println(node.value + "'s next : " + getPrecursorNode(node).value);

}
}

运行结果

这里写图片描述

0%