今天學習到二叉樹的時候,看到了二叉樹的先序,后序,中序遍歷方法。然而二叉樹遍歷方法遞歸實現十分簡單,迭代版本實現起來些許復雜,就又上手試試二叉樹的各種遍歷方法以及實現版本,當是溫習一遍之前了解到的實現方法。
三種遍歷方法中遞歸實現難度相當,代碼相當簡略。
三種遍歷方法中利用棧實現的迭代版本中,先序和中序實現難度相對簡單,但是后序遍歷方法實現起來比較復雜,這里實現思路也不同於之前先序和中序的版本。
另外一種O(1)空間復雜度實現先序,中序實現難度也相對簡單,后序相對復雜。
以下貼出完整測試代碼,main函數中輸入生成二叉樹的方法:
輸入節點數量,然后輸入二叉樹樹形結構1,2,3,#,4其中#代表空,則1,2,3,#,4代表以下結構:
1
/ \
2 3
\
4
再舉一個例子,輸入7個節點數量,輸入1,2,3,4,5,6,7代表樹形結構如下:
1
/ \
2 3
/ \ / \
4 5 6 7
代碼:
其中_r后綴的為遞歸實現,_s后綴的為利用棧迭代實現,_m后綴的為O(1)空間復雜度迭代實現。
其中_m迭代實現線程不安全,因為臨時的改變了樹的結構。
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
struct TreeNode {
int label;
TreeNode *right;
TreeNode *left;
TreeNode(int temp):label(temp) {
}
};
class Solution {
public:
void inordertraversal_r(TreeNode *root) {
if(root == NULL) {
return;
}
inordertraversal_r(root->left);
cout<<root->label<<" ";
inordertraversal_r(root->right);
}
void preordertraversal_r(TreeNode *root) {
if(root == NULL) {
return;
}
cout<<root->label<<" ";
preordertraversal_r(root->left);
preordertraversal_r(root->right);
}
void postordertraversal_r(TreeNode *root) {
if(root == NULL) {
return;
}
postordertraversal_r(root->left);
postordertraversal_r(root->right);
cout<<root->label<<" ";
}
void inordertraversal_s(TreeNode *root) {
stack<TreeNode*> s;
TreeNode *cur = root;
while(!s.empty() || cur != NULL) {
while(cur != NULL) {
s.push(cur);
cur = cur->left;
}
cur = s.top();
s.pop();
cout<<cur->label<<" ";
cur = cur->right;
}
}
void preordertraversal_s(TreeNode *root) {
stack<TreeNode*> s;
TreeNode *cur = root;
while(!s.empty() || cur != NULL) {
while(cur != NULL) {
cout<<cur->label<<" ";
s.push(cur);
cur = cur->left;
}
cur = s.top();
s.pop();
cur = cur->right;
}
}
//change thinking , it's too hard
void postordertraversal_s(TreeNode *root) {
//the original method
/*
We use a prev variable to keep track of the previously-traversed node. Let’s assume curr is the current node that’s on top of the stack. When prev is curr‘s parent, we are traversing down the tree. In this case, we try to traverse to curr‘s left child if available (ie, push left child to the stack). If it is not available, we look at curr‘s right child. If both left and right child do not exist (ie, curr is a leaf node), we print curr‘s value and pop it off the stack.
If prev is curr‘s left child, we are traversing up the tree from the left. We look at curr‘s right child. If it is available, then traverse down the right child (ie, push right child to the stack), otherwise print curr‘s value and pop it off the stack.
If prev is curr‘s right child, we are traversing up the tree from the right. In this case, we print curr‘s value and pop it off the stack.
*/
if(root == NULL) {
return;
}
stack<TreeNode*> s;
s.push(root);
TreeNode *cur = NULL;
TreeNode *pre = NULL;
while( !s.empty() ) {
cur = s.top();
//left down or right down
if( pre == NULL || pre->left == cur || pre->right == cur) {
if(cur->left != NULL) {
s.push(cur->left);
}
else if(cur->right != NULL) {
s.push(cur->right);
}
else {
cout<<cur->label<<" ";
s.pop();
}
}
//left up
else if(cur->left == pre) {
if(cur->right != NULL) {
s.push(cur->right);
}
else {
cout<<cur->label<<" ";
s.pop();
}
}
//right up
else if(cur->right == pre) {
cout<<cur->label<<" ";
s.pop();
}
pre = cur;
}
/* the easy method
stack<TreeNode*> s;
s.push(root);
TreeNode *cur = NULL;
TreeNode *pre = NULL;
while( !s.empty() ) {
cur = s.top();
if(pre == NULL || pre->left == cur || pre->right == cur) {
if(cur->left != NULL) {
s.push(cur->left);
}
else if(cur->right != NULL) {
s.push(cur->right);
}
}
else if(cur->left == pre) {
if(cur->right != NULL) {
s.push(cur->right);
}
}
else {
cout<<cur->label<<" ";
s.pop();
}
pre = cur;
}
*/
}
void inordertraversal_m(TreeNode *root) {
TreeNode *cur = root;
TreeNode *pre = NULL;
while(cur != NULL) {
if(cur->left == NULL) {
cout<<cur->label<<" ";
cur = cur->right;
}
else {
pre = cur->left;
while( pre->right != NULL && pre->right != cur ) {
pre = pre->right;
}
if(pre->right == NULL) {
pre->right = cur;
cur = cur->left;
}
else {
pre->right = NULL;
cout<<cur->label<<" ";
cur = cur->right;
}
}
}
}
void preordertraversal_m(TreeNode *root) {
TreeNode *cur = root;
TreeNode *pre = NULL;
while(cur != NULL) {
if(cur->left == NULL) {
cout<<cur->label<<" ";
cur = cur->right;
}
else {
pre = cur->left;
while( pre->right != NULL && pre->right != cur ) {
pre = pre->right;
}
if(pre->right == NULL) {
pre->right = cur;
cout<<cur->label<<" ";
cur = cur->left;
}
else {
pre->right = NULL;
cur = cur->right;
}
}
}
}
//this is the most difficult algorithm
void reverse_out(TreeNode *from,TreeNode *to) {
//first reverse from->to
//reverse
TreeNode *cur = from;
TreeNode *post = cur->right;
while(cur != to) {
TreeNode *tmp = post->right;
post->right = cur;
cur = post;
post = tmp;
}
//already reverse,output list
TreeNode *traversal = cur;
while( cur != from ) {
cout<<cur->label<<" ";
cur = cur->right;
}
cout<<cur->label<<" ";
//reverse original
cur = to;
post = cur->right;
while(cur != from) {
TreeNode *tmp = post->right;
post->right = cur;
cur = post;
post = tmp;
}
//restore to's right
to->right = NULL;
}
void postordertraversal_m(TreeNode *root) {
TreeNode *newroot = new TreeNode(0);
newroot->left = root;
newroot->right = NULL;
TreeNode *cur = newroot;
TreeNode *pre = NULL;
while(cur != NULL) {
if(cur->left == NULL) {
cur = cur->right;
}
else {
pre = cur->left;
while(pre->right != NULL && pre->right != cur) {
pre = pre->right;
}
if(pre->right == NULL) {
pre->right = cur;
cur = cur->left;
}
else {
pre->right = NULL;
reverse_out(cur->left,pre);
cur = cur->right;
}
}
}
}
};
int main(void) {
int nodecount;
while( cin>>nodecount && nodecount != 0 ) {
vector<TreeNode*> treenodes;
while(nodecount) {
nodecount--;
int nodelabel;
cin>>nodelabel;
if( ((char)nodelabel) == '#' ) {
treenodes.push_back( NULL );
}
else {
treenodes.push_back( new TreeNode(nodelabel) );
}
}
//construct the tree
for(int i = 0;i < treenodes.size();i++) {
if( treenodes[i] == NULL ) {
continue;
}
else {
//left child node 2n+1,right child node 2n+2
if( 2*i + 1 < treenodes.size() ) {
treenodes[i]->left = treenodes[2*i + 1];
}
else {
treenodes[i]->left = NULL;
}
if( 2*i + 2 < treenodes.size() ) {
treenodes[i]->right = treenodes[2*i + 2];
}
else {
treenodes[i]->right = NULL;
}
}
}
Solution s;
cout<<"inorder recursion :";
s.inordertraversal_m(treenodes[0]);
cout<<endl;
cout<<"inorder stack :";
s.inordertraversal_s(treenodes[0]);
cout<<endl;
cout<<"inorder morris :";
s.inordertraversal_r(treenodes[0]);
cout<<endl;
cout<<"preorder recursion :";
s.preordertraversal_m(treenodes[0]);
cout<<endl;
cout<<"preorder stack :";
s.preordertraversal_s(treenodes[0]);
cout<<endl;
cout<<"preorder morris :";
s.preordertraversal_r(treenodes[0]);
cout<<endl;
cout<<"postorder recursion:";
s.postordertraversal_m(treenodes[0]);
cout<<endl;
cout<<"postorder stack :";
s.postordertraversal_s(treenodes[0]);
cout<<endl;
cout<<"postorder morris :";
s.postordertraversal_r(treenodes[0]);
cout<<endl;
for(int i = 0;i < treenodes.size();i++) {
delete treenodes[i];
}
}
}
關於morris的先序,中序思路圖解:

關於moriis的后序思路圖解:

