KM的博客.

二叉树今生

字数统计: 961阅读时长: 4 min
2019/06/06

二叉树今生

为什么会有二叉树这种数据结构?

思考一个问题:如果一个集合中有42亿个元素,让你从这42亿个元素中搜索某一个元素,你需要多少次操作?

如果使用数组链表的话最多可能需要42亿次比较,而如果使用二叉树我们只需要32次比较即可,这就是二叉树存在的价值。Java中的HashSet使用的就是二叉树

前驱与后继

前驱节点

  1. 若一个节点有左子树,那么该节点的前驱节点是其左子树中val值最大的节点(也就是左子树中所谓的rightMostNode)

  2. 若一个节点没有左子树,那么判断该节点和其父节点的关系

    2.1 若该节点是其父节点的右边孩子,那么该节点的前驱结点即为其父节点。

    2.2 若该节点是其父节点的左边孩子,那么需要沿着其父亲节点一直向树的顶端寻找,直到找到一个节点P,P节点是其父节点Q的右边孩子(可参考例子2的前驱结点是1),那么Q就是该节点的后继节点

后继节点

  1. 若一个节点有右子树,那么该节点的后继节点是其右子树中val值最小的节点(也就是右子树中所谓的leftMostNode)
  2. 若一个节点没有右子树,那么判断该节点和其父节点的关系
    2.1 若该节点是其父节点的左边孩子,那么该节点的后继结点即为其父节点
    2.2 若该节点是其父节点的右边孩子,那么需要沿着其父亲节点一直向树的顶端寻找,直到找到一个节点P,P节点是其父节点Q的左边孩子(可参考例子2的前驱结点是1),那么Q就是该节点的后继节点

如何判断两个二叉树是否相同?

递归法

1
2
3
4
5
6
7
8
9
10
11
12
static public bool IsSameTree(TreeNode root1, TreeNode root2) {
if (root1 == null && root2 == null) {
return true;
}
if ((root1 == null && root2 != null) || (root1 != null && root2 == null)) {
return false;
}
if (root1.val != root2.val) {//判断每个节点的值是否相等,如果去除此判断,则判断两个二叉树是否结构相等
return false;
}
return IsSameTree(root1.left, root2.left) && IsSameTree(root1.right, root2.right);
}

非递归法

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
bool  BTreeCompare(BTreeNode_t *pRoot1, BTreeNode_t *pRoot2)  
{
if( pRoot1 == NULL && pRoot2 == NULL )
return false;


queue <BTreeNode_t *> que1;
queue <BTreeNode_t *> que2;


que1.push(pRoot1);
que2.push(pRoot2);


int curLevelNodeTotal1 = 0;
int curLevelNodeTotal2 = 0;


bool flag = true; //作为比较不一致时跳出标识
while( ( !que1.empty()) && ( !que2.empty())) //当两个队列均不为空时,才进行比较
{
curLevelNodeTotal1 = que1.size(); //获取树1的当前层节点总数
curLevelNodeTotal2 = que2.size(); //获取树2的当前层节点总数
if( curLevelNodeTotal1 != curLevelNodeTotal2){
flag = false;//当前层节点总数都不一致,不需要比较了,直接跳出
break;
}
int cnt1 = 0;//遍历本层节点时的计数器
int cnt2 = 0;
while( cnt1 < curLevelNodeTotal1 && cnt2 < curLevelNodeTotal2){
++cnt1;
++cnt2;
pRoot1 = que1.front();
que1.pop();
pRoot2 = que2.front();
que2.pop();

//比较当前节点中数据是否一致
if( pRoot1->m_pElemt != pRoot2->m_pElemt ){
flag = false;
break;
}
//判断pRoot1和pRoot2左右节点结构是否相同
if( ( pRoot1->m_pLeft != NULL && pRoot2->m_pLeft == NULL ) ||
( pRoot1->m_pLeft == NULL && pRoot2->m_pLeft != NULL ) ||
( pRoot1->m_pRight != NULL && pRoot2->m_pRight == NULL ) ||
( pRoot1->m_pRight == NULL && pRoot2->m_pRight != NULL )
){
flag = false;
break;
}

//将左右节点入队
if( pRoot1->m_pLeft != NULL )
que1.push( pRoot1->m_pLeft);
if( pRoot1->m_pRight != NULL )
que1.push( pRoot1->m_pRight);
if( pRoot2->m_pLeft != NULL )
que2.push( pRoot2->m_pLeft);
if( pRoot2->m_pRight != NULL )
que2.push( pRoot2->m_pRight);
}


if( flag == false )
break;
}

//如果比较标志为false,则不相同
if( flag == false ){
while( !que1.empty() )
que1.pop();
while( !que2.empty())
que2.pop();


return false;
}


return true;
}
CATALOG
  1. 1. 二叉树今生
    1. 1.1. 前驱与后继
      1. 1.1.1. 前驱节点
      2. 1.1.2. 后继节点