Skip to content

Commit

Permalink
修改
Browse files Browse the repository at this point in the history
  • Loading branch information
arkingc committed Jul 16, 2018
1 parent d83a2ed commit a2f9bc8
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 241 deletions.
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@

## 数据结构与算法

* [1.查找](数据结构与算法/查找.md)
* [2.排序](数据结构与算法/排序.md)
* [3.二叉树](数据结构与算法/二叉树.md)
* [4.堆](数据结构与算法/堆.md)
* [5.平衡查找树](数据结构与算法/平衡查找树.md)
* [6.哈希表](数据结构与算法/哈希表.md)
* [7.图](数据结构与算法/图.md)
* [1.排序](数据结构与算法/排序.md)
* [2.二叉树](数据结构与算法/二叉树.md)
* [3.堆](数据结构与算法/堆.md)
* [4.平衡查找树](数据结构与算法/平衡查找树.md)
* [5.哈希表](数据结构与算法/哈希表.md)
* [6.图](数据结构与算法/图.md)
* [算法题总结](数据结构与算法/算法题总结.md)

> 理论知识参考:
Expand Down
204 changes: 50 additions & 154 deletions 数据结构与算法/二叉树.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@

<!-- GFM-TOC -->
* [(前中后序)遍历](#前中后序遍历)
* [两种特殊二叉树](#两种特殊二叉树)
* [二叉树定理](#二叉树定理)
* [前中后序遍历](#前中后序遍历)
* [递归版](#递归版)
* [迭代版](#迭代版)
* [二叉树重建](#二叉树重建)
* [根据前序、中序序列重建二叉树](#根据前序中序序列重建二叉树)
* [根据前序、后序序列重建二叉树(不可行)](#根据前序后序序列重建二叉树不可行)
* [根据中序、后序序列重建二叉树](#根据中序后序序列重建二叉树)
* [二叉树序列化](#二叉树序列化)
* [(广度优先)遍历](#广度优先遍历)
* [路径](#路径)
* [深度](#深度)
* [理论知识](#理论知识)
- [两种特殊二叉树](#两种特殊二叉树)
- [二叉树定理](#二叉树定理)
<!-- GFM-TOC -->

# 两种特殊二叉树

* **满二叉树**:除叶子节点外的所有分支节点都含有2个非空子节点的二叉树
* **完全二叉树**:除了最后一层,其余层都是“满”的,这样的二叉树是完全二叉树

![](../pic/al-tree-1.png)

<br>
<br>

# 二叉树定理

### 1)任意二叉树度数为2节点的个数等于叶节点个数减1

当只有1个节点时,度为0。每派生出1度,就会多出1个节点。派生出的度和派生出的节点数一定相等。那么就得出了总度数和节点总数的关系:

`节点总数 = 总度数 + 1`

设度数为2的节点数为`X2`,度数为1的节点数为`X1`,度数为0的节点数为`X0`。可以得出如下关系式:

`X2+X1+X0=2X2+X1+1;`

推出

`X2=X0-1`;

因此,**度数为2的节点个数等于叶节点数减1**

### 2)满二叉树定理:非空满二叉树的叶节点数等于其分支节点数加1

如果已知前一个结论,那么这个定理显然成立。下面分析如果不知道前一个结论,怎么证明

对于只有1个节点的树,该定理成立。从这开始思考,每产生1个分支节点(度数为2)。叶子节点数也会加1。因为要产生一个分支节点,那么这个新的分支节点必然是原来的叶子节点,而新的分支节点又生成了2个新的叶子节点。因此叶子节点的总数先是减1然后加2,因此总数加1。因此,产生n个分支节点时,也产生了n个叶子节点,由于最初只有1个叶子节点,所以该定理成立

### 3)一颗非空二叉树空子树的数目等于其节点数目加1

考虑只有1个根节点的二叉树:它有2个空子树,1个节点,因此结论成立。从这里开始考虑,每产生1个节点。空子树便会先减1然后加2。就和上面结论中每多出1个分支节点,叶子节点的变化一样。因此在原来结论的基础上,由于空子树和节点等量增长。所以结论成立

<br>
<br>

# 前中后序遍历

* **前序**遍历:根->左->右
* **中序**遍历:左->根->右
* **后序**遍历:左->右->根

假设树节点的定义如下:

Expand All @@ -29,12 +65,6 @@ struct TreeNode {
};
```
# (前中后序)遍历
* 前序遍历:根->左->右
* 中序遍历:左->根->右
* 后序遍历:左->右->根
## 递归版
```c++
Expand Down Expand Up @@ -147,139 +177,5 @@ void postorderTraversalIteration(TreeNode *root)
对于后序遍历,由于其访问序列为:左->右->根。因此还有一种方法,可以按类似前序遍历的方式:根->右->左,然后对得到的结果反序
> 相关题目:
> * 剑指offer(8):二叉树的下一个节点
> * 剑指offer(28):对称的二叉树
## 二叉树重建
### 根据前序、中序序列重建二叉树
前序序列的特点:{首元素,左子树节点,右子树节点}
中序序列的特点:{左子树节点,首元素,右子树节点}
因此,可以根据前序序列的首元素创建根节点,然后遍历中序序列,找到首元素,递归处理左子树和右子树。函数返回(树或子树的)根节点,每个新创建节点分别将左右子节点设置为递归处理的返回节点
**如何处理前序序列和中序序列不匹配等非法输入的情况?(throw std::exception("Invalid input"))**
> 相关题目:剑指offer(7):重建二叉树
### 根据前序、后序序列重建二叉树(不可行)
后序序列中,根节点在末尾,前序序列中,根节点在首部,无法确定左右子树节点的范围,因此无法重建
### 根据中序、后序序列重建二叉树
和根据前序、中序序列重建的思想一样
### 二叉树序列化
序列中存储**空节点信息**(如使用‘$’)可以使用前序序列重建二叉树
> 相关题目:
> * 剑指offer(37):序列化二叉树
# (广度优先)遍历
**使用队列**
```c++
void depthTraversal(TreeNode *root)
{
deque<TreeNode*> d;
if(root)
d.push_back(root);
TreeNode *curr;
while(!d.empty()){
curr = d.front();
d.pop_front();
cout << curr << " ";
if(curr->left)
d.push_back(curr->left);
if(curr->right)
d.push_back(curr->right);
}
}
```

> 相关题目:
> * 剑指offer(32):不分行从上到下打印二叉树(题目一)
> * 剑指offer(32):分行从上到下打印二叉树(题目二)
> * 剑指offer(32):之字形打印二叉树(题目三)
# 路径

使用**辅助空间**保存路径(如vector)

```c++
/*
* 函数获取到达节点dest的路径
* dest是否为nullptr的检查应该在外层,因为该函数是一个递归的过程,一旦dest不为空,后续的递归都不会为空
* 如果查找的节点不存在树中,可以通过path中的元素或者函数返回值判断
*/
bool getPathCore(TreeNode *root,TreeNode *dest,vector<TreeNode*> &path)
{
if(!root)
return false;

//首先假设当前节点是所要查找路径中的一个节点,插入
path.push_back(root);

if(root == dest) //先判断当前节点是否是查找的节点(前序遍历)
return true;

bool find = false;

//如果左子树中找到,则不会继续对右子树进行查找
find = getPathCore(root->left,dest,path) || getPathCore(root->right,dest,path);

//左子树或右子树中找到则直接返回(因为路径中肯定包含了当前节点,不返回会弹出)
if(find)
return find;

//如果(左右)子树中都没找到,说明所要查找的路径不经过这个节点,弹出
path.pop_back();

return false;
}
```
> 相关题目:
> * 剑指offer(34):二叉树中和为某一值的(所有)路径
# 深度
```c++
int TreeDepth(TreeNode* pRoot)
{
if(!pRoot)
return 0;
int depth1 = 1 + TreeDepth(pRoot->left);
int depth2 = 1 + TreeDepth(pRoot->right);
return depth1 > depth2 ? depth1 : depth2;
}
```

> 相关题目:
> * 剑指offer(55):二叉树的深度(题目一)
> * 剑指offer(55):平衡二叉树AVL(题目二)
# 理论知识

## 两种特殊二叉树

* **满二叉树**:除叶子节点外的所有分支节点都含有2个非空子节点的二叉树
* **完全二叉树**:除了最后一层,其余层都是“满”的,这样的二叉树是完全二叉树

![](../pic/al-tree-1.png)

## 二叉树定理

1. **满二叉树定理**:非空满二叉树的叶节点数等于其分支节点数加1
2. 一颗非空二叉树空子树的数目等于其节点数目加1
3. 任意二叉树度数为2节点的个数等于叶节点个数减1
<br>
<br>
80 changes: 0 additions & 80 deletions 数据结构与算法/查找.md

This file was deleted.

0 comments on commit a2f9bc8

Please sign in to comment.