摘要
总结二叉树的遍历方法,包括广度优先遍历、深度优先遍历以及前序、中序、后序遍历。
然后给出各种方法的递归和非递归C++代码实现。
二叉树的遍历方法(广度优先遍历、深度优先遍历以及前序、中序、后序遍历)
术语定义:
D
(The current node) 表示当前结点L
(left child) 表示左孩子结点R
(right child) 表示右孩子结点深度优先搜索(DFS, Depth First Search)
可分为前序遍历(Preorder traversal)
,中序遍历(Inorder Traversal)
和后序遍历(Postorder Traversal)
对于上图所示二叉树,不同的遍历结果为如下:
深度优先搜索(DFS, Depth First Search)
通常指的是前序遍历(Preorder traversal)
?:遍历顺序规则为【DLR | 即当前结点, 左孩子, 右孩子】| 遍历结果:ABDGHCEIF中序遍历(Inorder Traversal)
| 遍历顺序规则为【LDR】| 遍历结果:GDHBAEICF后序遍历(Postorder Traversal)
| 遍历顺序规则为【LRD】| 遍历结果:GHDBIEFCA广度优先搜索(BFS, Breadth First Search)
(又叫层次遍历
)| 遍历顺序为【从上到下按层遍历,每层从左到右遍历】 | 遍历结果:ABCDEFGHI
tips:记忆前、中、后序遍历
的小技巧。在前、中、后序遍历
都是先L后R,只是D的位置不同。D放在第一个为DLR,就是前序遍历;D放在中间为LDR,就是中序便利;D放在后面为LRD,就是后序便利。
二叉树常用的4种遍历方式,总结如下表(如果图片太小可以点击放大):
遍历方式 | 前序遍历 | 中序遍历 | 后序遍历 | 层次遍历 |
---|---|---|---|---|
遍历规则 | DLR,即当前结点, 左孩子, 右孩子 | LDR | LRD | 从上到下按层遍历,每层从左到右遍历 |
遍历结果 | ABDGHCEIF | GDHBAEICF | GHDBIEFCA | ABCDEFGHI |
遍历示意图 | ![]() | ![]() | ![]() | ![]() |
其它遍历方法
对称遍历
(自己起的名字) | 遍历结果:A BC DG HM IL EF JK | 实现方式:其实是对A节点的左子树进行前序遍历【DLR】,对A节点的右子树进行【DRL】遍历。另外为了保证同时对称的遍历,一次要同时访问2个结点。例如 Leetcode 101. 对称二叉树 就需要这么访问。
TODO:各种方法的递归和非递归C++代码实现
各种遍历的代码实现。包括递归版本和非递归版本。做成模板方便刷题。
可能参考:
参考1
首先定义二叉树结构:
//Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
根据输入的前序遍历数组,创建二叉树:
注意:这里虽然只是前序遍历,但是按照完全二叉树来构建,所以生成的二叉树是唯一的
// 根据输入的前序遍历数组,创建二叉树
volatile int index = 0;
void CreateBiTree(TreeNode *&p_root, vector<int> &v_preOrder ){
if(index >= v_preOrder.size())
return;
//按先序输入二叉树中结点的值(一个字符),空格字符代表空树,
int val = v_preOrder[index++];
if('#' != val){
p_root = new TreeNode(val);//产生新的子树
CreateBiTree(p_root->left, v_preOrder);//递归创建左子树
CreateBiTree(p_root->right, v_preOrder);//递归创建右子树
}
else{
p_root = nullptr;
}
}//CreateTree
/* binary tree
A
/ \
B C
\ \
D E
/ / \
F G H
*/
int main()
{
// generate binary tree.
TreeNode *p_root = nullptr;
// # denote nullptr
vector<int> v_preOrder = {'A', 'B', '#', 'D', 'F', '#', '#', '#', 'C', '#', 'E', 'G', '#', '#', 'H', '#', '#'};
CreateBiTree(p_root, v_preOrder);
// preorder traversal
PreOrderTraversal_recursive(p_root);
cout << endl;
return 0;
}
前序遍历
递归实现:
void PreOrderTraversal_recursive(TreeNode *p_root){
if(nullptr == p_root)
return;
printf("%c", p_root->val); // current node
PreOrderTraversal_recursive(p_root->left);
PreOrderTraversal_recursive(p_root->right);
}
非递归实现:
中序遍历
递归实现:
void InOrderTraversal_recursive(TreeNode *p_root){
if(nullptr == p_root)
return;
InOrderTraversal_recursive(p_root->left);
printf("%c", p_root->val); // current node
InOrderTraversal_recursive(p_root->right);
}
非递归实现:
后序遍历
递归实现:
void PostOrderTraversal_recursive(TreeNode *p_root){
if(nullptr == p_root)
return;
PostOrderTraversal_recursive(p_root->left);
PostOrderTraversal_recursive(p_root->right);
printf("%c", p_root->val); // current node
}
非递归实现:
广度优先搜索(BFS, Breadth First Search)
广度优先搜索(BFS, Breadth First Search)
又叫层次遍历
。
队列实现:
// BFS
#include <queue>
void BreadthFirstSearch(TreeNode *p_root){
if(nullptr == p_root)
return;
queue<TreeNode*> traversal_order;
traversal_order.push(p_root);
while(!traversal_order.empty()){
TreeNode *p_curr = traversal_order.front();
traversal_order.pop();
printf("%c", p_curr->val); // current node
if(nullptr != p_curr->left){
traversal_order.push(p_curr->left);
}
if(nullptr != p_curr->right){
traversal_order.push(p_curr->right);
}
}
}
相关/参考链接
- 看懂二叉树的三种遍历
- 《大话数据结构》