我们应该熟练掌握二叉树三大遍历的非递归算法实现,因为当树结点很多时,树的递归遍历就很低效了
下面程序都是先构建一个二叉搜索树,在二叉搜索树的基础上进行先序、中序、后序的非递归遍历
以下是二叉树后序遍历的非递归实现:
注意:二叉树遍历的非递归实现需要自己手动模拟以下它的遍历顺序,然后设计好出栈顺序
#include"stdafx.h"
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int maxn = 1e3;
struct node {//结点
int data;
node* leftchild;
node* rightchild;
int flag;//结点标记
};
void insert(node* &root, int x, int flag) {//非递归插入
//新建结点
node* N = new node;
N->data = x;
N->leftchild = NULL;
N->rightchild = NULL;
N->flag = flag;
//
if (root == NULL) {
root = N;
}
else {
node* p = root;//工作指针
node* pre = p;//p的前驱指针
while (p != NULL) {
pre = p;
if (x < p->data) p = p->leftchild;
else p = p->rightchild;
}
if (x < pre->data && pre->leftchild == NULL) pre->leftchild = N;
else pre->rightchild = N;
}
}
node* creat(int a[],int n) {//构建二叉搜索树
node* root = NULL;
for (int i = 0; i < n; i++) {
insert(root, a[i], i);
}
return root;
}
void postorder(node* root) {//后序遍历的非递归算法
stack<node*> s;
bool vis[maxn] = { false };//标记是否被访问
do {
while (root != NULL) {
s.push(root);
root = root->leftchild;
}
root = s.top();
if (root->rightchild != NULL) root = root->rightchild;
else {
while (root->rightchild == NULL || vis[root->rightchild->flag] == true) {
cout << root->data << " ";//访问元素
vis[root->flag] = true;//标记被访问
s.pop();
if (s.empty()) break;//pop后一定要检查栈是否为空,否则取不到栈顶元素
root = s.top();
}
root = root->rightchild;
}
} while (!s.empty());
}
int main() {
int n;
cin >> n;
int a[maxn];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
node* root = creat(a, n);
postorder(root);
return 0;
}
-----------------------------------------------------------------------------------------
也可以将以上的非递归插入改成以下的递归插入
void insert(node* &root, int x, int flag) {//递归插入
if (root == NULL) {
root = new node;
root->data = x;
root->leftchild = NULL;
root->rightchild = NULL;
root->flag = flag;
return;
}
else {
if (x < root->data) {
insert(root->leftchild, x,flag);
}
else {
insert(root->rightchild, x,flag);
}
}
}
上面代码实现了二叉树后序遍历非递归算法,二叉树后序遍历非递归算法有一个很重要的特性:就是当访问某个结点时,栈中所保存的元素正好是这个结点的所有祖先。那么知道了这个特性,我们就很容易解决下面如下问题:
(1).当给定一个叶子结点,要求输出该叶子结点的所有祖先
(2).输出根结点到所有叶子结点的路径
(3).如果二叉树结点的值是数值,那么求每条路径上值之和,也可以利用二叉树后序遍历的非递归算法这个特性
等等等等
下面是中序遍历和先序遍历的非递归算法:
void inorder(node* root) {//中序遍历的非递归算法
stack<node*> s;
while (!s.empty() || root != NULL) {
while (root != NULL) {
s.push(root);
root = root->leftchild;
}
root = s.top();
s.pop();
cout << root->data << " ";
root = root->rightchild;
}
}
-----------------------------------------------------------------------------------------
void preorder(node* root) {//先序遍历的非递归算法
stack<node*> s;
while (!s.empty() || root != NULL) {
while (root != NULL) {
cout << root->data << " ";
s.push(root);
root = root->leftchild;
}
root = s.top();
s.pop();
root = root->rightchild;
}
}