这个学期一直在忙着准备面试,复习,都没有看新的书,也很久没有写Blog了。
之前写过二叉树的遍历,但是现在回去看实在是不忍直视,不仅写的复杂,而且还不一定正确。现在把二叉树的三种非递归遍历重写一遍。
二叉树的遍历是一个递归的过程,天然具备递归的属性,而非递归遍历的关键是栈的运用。其实任何一种递归算法都有一个对应的非递归算法。
先放上二叉树类的定义
class Tree {
public:
Tree(char d) {
leftChild = nullptr;
rightChild = nullptr;
data = d;
tag = 0;
}
Tree() {
leftChild = nullptr;
rightChild = nullptr;
tag = 0;//后序遍历标志位
}
void initTree(char* &str, Tree* &t);//使用字符串初始化二叉树,#表示空节点
void fVisit();//先序遍历
void mVisit();//中序遍历
void bVisit();//后序遍历
private:
Tree *leftChild;
Tree *rightChild;
char data;
int tag;
};
树的初始化为了方便使用了递归算法,可以看出,树的递归算法是十分简洁优美的
void Tree::initTree(char* &str, Tree* &t){//先序构建二叉树
if (*str != '#') {
t = new Tree(*str);
initTree(++str, t->leftChild);
initTree(++str, t->rightChild);
}
}
先序遍历:我认为是最简单的一种遍历
void Tree:: fVisit(){
stack<Tree *> s;
Tree *t = this;
while (t != nullptr || !s.empty()) {
if (t != nullptr) {
cout << t->data << "\t";
if (t->rightChild != nullptr) {
s.push(t->rightChild);
}
t = t->leftChild;
}else{
t = s.top();
s.pop();
}
}
}
中序遍历:和先序遍历类似
void Tree::mVisit(){
stack<Tree *> s;
Tree *t = this;
while (t != nullptr || !s.empty()) {
if (t != nullptr) {
s.push(t);
t = t->leftChild;
}else {
cout << s.top()->data << "\t";
t = s.top()->rightChild;
s.pop();
}
}
}
后序遍历:后序遍历比之前两种遍历方法稍稍复杂一些,主要是访问标志tag的引入。因为后序遍历节点入栈之后会被访问两次,第一次访问是进入其的右孩子,第二次访问才将其弹出,输出。所以我们在栈中第一次访问某个节点时将其tag置1。若访问的栈中元素tag值为1则将其弹出,并输出
void Tree::bVisit(){
stack<Tree *> s;
Tree *t = this;
while (t != nullptr || !s.empty()) {
if (t != nullptr) {
s.push(t);
t = t->leftChild;
}else {
if (s.top()->tag == 0) {
t = s.top()->rightChild;
s.top()->tag = 1;
}else {
cout << s.top()->data << "\t";
s.pop();
}
}
}
}
主函数调用
int main() {
Tree *t = new Tree;
char *str = "1378###6##59###";
t->initTree(str, t);
cout << "先序遍历" << endl;
t->fVisit();
cout << endl;
cout << "中序遍历" << endl;
t->mVisit();
cout << endl;
cout << "后序遍历" << endl;
t->bVisit();
cout << endl;
system("pause");
return 0;
}
输出结果
先序遍历
1 3 7 8 6 5 9
中序遍历
8 7 3 6 1 9 5
后序遍历
8 7 6 3 9 5 1
感觉还行。
最后希望我的同学—-将来的doctor们发达了不要忘了我