二叉树有先序遍历(根左右)、中序遍历(左根右)和后序遍历(左右根)和层次遍历几种遍历方式。这几种遍历方式是其他二叉树解题的基础,所以必须先掌握。
因为二叉树本身就是用递归定义的,因此采用递归的方法实现三种遍历代码简洁且容易理解,但其开销比较大。
二叉树的先序、中序和后序遍历:
先序遍历:任何子树的处理顺序都是:先根结点,再左子树,然后右子树 (根左右)
中序遍历:任何子树的处理顺序都是:先左子树,再根节点,然后右子树 (左根右)
后序遍历:任何子树的处理顺序都是:先左子树,再右子树,然后根结点 (左右根)
二叉树的节点定义如下:
struct Node{
int val;
Node* left;
Node* right;
Node() {
val = 0;
left = nullptr;
right = nullptr;
}
Node(int v){
val = v;
left = nullptr;
right = nullptr;
}
};
void preOrderTraversalRecursion(Node* x){
if(x == nullptr) return;
cout<val<left);
preOrderTraversalRecursion(x->right);
}
void inOrderTraversalRecursion(Node* x){
if(x == nullptr) return;
inOrderTraversalRecursion(x->left);
cout<val<right);
}
void postOrderTraversalRecursion(Node* x){
if(x == nullptr) return;
postOrderTraversalRecursion(x->left);
postOrderTraversalRecursion(x->right);
cout<val<
二叉树的递归遍历实际上是对二叉树的递归序(二叉树每个节点都会遍历三次),在第i次到达的时候打印根节点。(第1次到达就是先序遍历,第2次到达就是中序遍历,第3次到达就是后序遍历)
非递归遍历二叉树就是用自己实现的栈替代系统栈。注:任何递归函数都可以改成非递归。
先序遍历:
注意因为栈是先进后出的,所以是先压右子树再压左子树,这样就能保证出栈是左边先出右边后出。
void preOrderTraversalIteration(Node* x){//先序遍历二叉树迭代法:
if(x == nullptr ) return;
cout<<"preOrderTraversalIteration"< s;//用栈模拟递归
s.push(x);//先把头节点压栈
while (!s.empty()){ //栈非空就继续循环
Node* cur = s.top(); //栈中弹出节点
s.pop();
cout<val<right){
s.push(cur->right);
}
if(cur->left){
s.push(cur->left);
}
}
}
后序遍历:
上面已经实现了非递归先序遍历(根左右),那么只要稍微加工就可以得到非递归后序遍历。将非递归先序遍历的压栈顺序改一下,改成先压左子树再压右子树,那么最终的遍历顺序是<根右左>,然后在每次弹出打印时候改成不打印,进入另外一个temp栈,当整个操作完成后。从temp栈中弹出元素,那么<根右左>就变成了<左右根>,这就是后序遍历。
void postOrderTraversalIteration(Node* x){
if(x == nullptr) return;
cout<<"postOrderTraversalIteration"< s,tmp;//s是类似于辅助先序遍历的栈;tmp是保存遍历元素,最后输出就是后序遍历
s.push(x);
while (!s.empty()){
Node* cur = s.top();
s.pop();
tmp.push(cur);
if(cur->left){
s.push(cur->left);
}
if(cur->right){
s.push(cur->right);
}
}
while (!tmp.empty()){
Node* t = tmp.top();
cout<val<
中序遍历:
void inOrderTraversalIteration(Node* x){//二叉树中序遍历迭代法实现
if(x == nullptr) return;
cout<<"inOrderTraversalIteration"< s;
Node* cur = x;
Node* tmp = nullptr;
//栈不为空或者cur不为空,那么循环继续
while (!s.empty() || cur){
if(cur){ //以cur为头节点的树,整条左边进栈(包括cur这个根节点),直到遇到cur的左边为nullptr结束
s.push(cur);
cur = cur->left;
}else {
cur = s.top(); //从栈中弹出cur,经过上面if判断cur的左边是nullptr,访问cur后,让cur=cur->right;
s.pop();
cout<val<right;
}
}
}
层次遍历二叉树需要用队列实现,就是宽度优先遍历,每层入队然后出队让左右孩子分别入队。
vector > levelOrder(Node* root) {
// write code here
vector > v;
if(root == nullptr) return v;
Node* cur = root;
queue q;
q.push(cur);
while(!q.empty()){
int size = q.size(); //先获取当前层的节点数
vector ans;
for(int i = 0;ival);
if(cur->left){
q.push(cur->left);
}
if(cur->right){
q.push(cur->right);
}
}
v.push_back(ans);
//二叉树层次遍历正序收集节点;如果要倒序收集,那么每次在首部位置插入即可
}
return v;
}