[总结] Binary tree traversal

一个binary tree有三种traversal的方式:preorder / inorder / postorder。我们分别来说:

1. Preorder

所谓preorder,就是处理任何children之前,先处理parent。比如leetcode上,Binary Tree Preorder Traversal 这道题中提供的例子:

For example:
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

return [1,2,3].

可以递归实现,这里给出代码:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void preorderTraversalHelper(TreeNode *root, vector<int> &result) {
        if (!root) return;
        result.push_back(root->val);
        preorderTraversalHelper(root->left, result);
        preorderTraversalHelper(root->right, result);
    }
    
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        preorderTraversalHelper(root, result);
        return result;
    }
};

这道题也可以不用递归实现,难度比用递归稍微大一点:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
		vector<int> result;
		if (!root) return result;
		std::stack<TreeNode*> qu;
		qu.push(root);
		while (!qu.empty()) {
			TreeNode * current = qu.top();
			qu.pop();
			result.push_back(current->val);
			if (current->right) qu.push(current->right);
			if (current->left) qu.push(current->left);
		}
		return result;
    }
};

用直觉就可以知道,应该会用到queue或者stack这种数据结构。


2. Inorder

所谓inorder,就是先左边,然后parent,然后右边这样的顺序。同样地,可以用非常相似的方法来进行递归:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void inorderTraversalHelper(TreeNode *root, vector<int> &result) {
        if (!root)
            return;
        inorderTraversalHelper(root->left, result);
        result.push_back(root->val);
        inorderTraversalHelper(root->right, result);
    }

    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> result;
        inorderTraversalHelper(root, result);
        return result;
    }
};

可以看到,就是把push_back和两个递归call的位置变了一下而已。


同样,这道题也可以用非递归的方法解决:

class Solution {
public:
	vector<int> inorderTraversal (TreeNode *root) {
		stack<TreeNode*> s;
		vector<int> result;
		if (!root) return result;
		TreeNode* current = root;
		bool done = false;
		while (!done) {
			if (current) {
				s.push(current);
				current = current->left;
			}

			else if (s.empty()) done = true;

			else {
				current = s.top();
				s.pop();
				result.push_back(current->val);
				current = current->right;
			}
		}
	}
};


3. Postorder

如果已经看到这里了,你应该能猜到postorder是什么意思了。所谓postorder,就是先左child;再右child;再parent。那么毫不意外地,可以用递归实现:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void postorderTraversalHelper(TreeNode *root, vector<int> &result) {
        if (!root)
            return;
        postorderTraversalHelper(root->left, result);
        postorderTraversalHelper(root->right, result);
        result.push_back(root->val);
    }

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> result;
        postorderTraversalHelper(root, result);
        return result;
    }
};

也同样毫不意外地,可以用非递归实现。不幸的是,这个iterative solution是三者中最难的一个。如图:



比如我们看D, C, E这三个nodes组成的subtree。如果是postorder,那也就是说,要先C, 再E,最后D。换句话说,当我traversal到D的时候,我发现它有两个children,所以我就要先进行children:这个过程是是从上到下的;而当C结束的时候,我们再回到D,发现还有E,那么从C结束到D的过程是从左下到上的;E结束之后,再回到D,发现已经没有children了,所以输出D,那么从E到D的过程是从右下到上的。所以一共有三种情况:从上到下;从左下到上;从右下到上。如何区分这三种情况呢?我们使用两个pointers,一个curr,一个prev。如果curr是prev的孩子,那么就说明是从上到下;如果prev是curr的left child,那么就说明是从左下到上;如果prev是curr的right child,那么就说明是从右下到上。代码如下:

void postOrderTraversalIterative(BinaryTree *root) {
  if (!root) return;
  stack<BinaryTree*> s;
  s.push(root);
  BinaryTree *prev = NULL;
  while (!s.empty()) {
    BinaryTree *curr = s.top();
    // we are traversing down the tree
    if (!prev || prev->left == curr || prev->right == curr) {
      if (curr->left) {
        s.push(curr->left);
      } else if (curr->right) {
        s.push(curr->right);
      } else {
        cout << curr->data << " ";
        s.pop();
      }
    } 
    // we are traversing up the tree from the left
    else if (curr->left == prev) {
      if (curr->right) {
        s.push(curr->right);
      } else {
        cout << curr->data << " ";
        s.pop();
      }
    }
    // we are traversing up the tree from the right
    else if (curr->right == prev) {
      cout << curr->data << " ";
      s.pop();
    }
    prev = curr;  // record previously traversed node
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值