二叉树
wiki上二叉树的介绍
二叉树的详细介绍
参阅:http://yameing.blog.163.com/blog/static/1120259402010088233927/
概念:二叉树就是每个结点最多有两个子树的树形存储结构。
满二叉树:在一棵二叉树中,所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上。
完全二叉树:完全二叉树是每个结点都与深度为k的满二叉树中编号从1到n一一对应。
二叉树的表示方式
- 顺序(用数组存储),简单但浪费空间
- 链式
二叉树的实现
二叉搜索树
1 | //main.c |
二叉树的遍历
非递归实现1
Morris遍历
http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html
递归
1 | //递归的方法 |
中序遍历的非递归方法
中序遍历,非递归的方法
对于任一结点P,
1)若其不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束。
1 | //非递归的方法,中序遍历 |
前序遍历的非递归方法
1 | //非递归前序遍历 |
后续遍历的非递归方法
因为后序遍历的顺序是:左子树->右子树->根节点,于是我们在前序遍历的代码中,当访问完当前节点后,先把当前节点的左子树入栈,再把右子树入栈,这样最终得到的顺序为:根节点->右子树->左子树,刚好是后序遍历倒过来的版本,于是把这个结果做一次翻转即为真正的后序遍历。而翻转可以通过使用另外一个栈简单完成,这样的代价是需要两个栈,但就复杂度而言,空间复杂度仍然是O(h)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22vector<int> postorderTraversal(tnode *r) {
vector<int> result;
if(r == NULL){
return result;
}
stack<tnode*> s;
s.push(r);
tnode *node;
while(!s.empty()){
node = s.top(); s.pop();
result.insert(result.begin(),node->val);
// 左子树
if(node->left){
s.push(node->left);
}
// 右子树
if(node->right){
s.push(node->right);
}
}
return result;
}
二叉树的相关问题
LCA,最低公共祖先
给定一棵树,同时给出树中的两个结点(n1和n2),求它们的最低公共祖先。也就是常见的LCA(Lowest Common Ancestor )问题。
解法一:
(1)找到从根节点到$n_1$的路径,
(2)找到从根节点到$n_2$的路径;
(3)找出两条路径中第一个不相同的点,则它的父节点即是所求。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
using namespace std;
struct tnode{
int val;
struct tnode *left, *right;
};
tnode* newNode(int k)
{
tnode* p = new tnode;
p->val = k;
p->left = p->right=NULL;
return p;
}
bool findPath(tnode *r, int key, vector<int>& path)
{
if (r == NULL) return false;
path.push_back(r->val);
if (r->val == key) return true;
bool exsite = (findPath(r->left, key, path) || findPath(r->right, key, path));
if (exsite) return true;
path.pop_back();
return false;
}
int findLCA(tnode *r, int key1, int key2)
{
vector<int> path1, path2;
int ret = -1;
bool find1 = findPath(r, key1, path1);
bool find2 = findPath(r, key2, path2);
vector<int>::iterator iter1 = path1.begin();
vector<int>::iterator iter2 = path2.begin();
if (find1 && find2){
while( iter1 != path1.end() && iter2 != path2.end()){
if (*iter1 == *iter2){
ret = *iter1;
++iter1;
++iter2;
}else
break;
}
return ret;
}
return -1;
}
int main()
{
tnode * root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
cout << "LCA(4, 5) = " << findLCA(root, 4, 5);
cout << "\nLCA(4, 6) = " << findLCA(root, 4, 6);
cout << "\nLCA(3, 4) = " << findLCA(root, 3, 4);
cout << "\nLCA(4, 2) = " << findLCA(root, 2, 4);
cout << "\nLCA(6, 3) = " << findLCA(root, 3, 6);
return 0;
}
解法2:递归的方法
(1)从一个根节点r开始找,如果r中的val是其中的一个,那么r就是所求的节点
(2)否则的话,遍历r->left和r->right,如果在r->left中找到两个节点,就返回1
2
3
4
5
6
7
8
9
10
11
12
13
14
15tnode *findLCA(tnode *r, int num1, int num2)
{
if (r == NULL) return NULL;
if (r->val == num1 || r->val == num2)
return r;
tnode *leftLCA = findLCA(r->left, num1, num2);
tnode *rightLCA = findLCA(r->right, num1, num2);
if (leftLCA && rightLCA)
return r;
else
return (leftLCA==NULL)?rightLCA:leftLCA;
}
二叉树中两个节点的距离
公式计算
Dist(n1, n2) = Dist(root, n1) + Dist(root, n2) - 2*Dist(root, LCA)
二叉树的面试题
http://www.acmerblog.com/?s=%E4%BA%8C%E5%8F%89%E6%A0%91