LeetCode有如下traversal的題目,這里只說普通遍歷:
Binary Tree Inorder Traversal
Binary Tree Level Order Traversal
Binary Tree Zigzag Level Order Traversal
Binary Tree Level Order Traversal II
Binary Tree Preorder Traversal
Binary Tree Postorder Traversal
Construct Binary Tree from Preorder and Inorder Traversal
Construct Binary Tree from Inorder and Postorder Traversal
基本思路有三種,第一種是trivial的遞歸,第二種是用stack,第三種是Morris。
- 用stack的方法分兩種,一種直觀的dfs像(1),一種用lastpop(2)或prev(3)記錄上一個節點以判斷遍歷路徑。
- 方法(1)的思路是順著往left走直到遇見NULL,從stack彈出一個往right挪動,繼續往left走。
- 方法(2)的思路是,每次循環分push left(left不為NULL并且從上往下遍歷),push right(right不為NULL并且right不是上次遍歷的店并且從左邊遍歷過來或者左邊為NULL),pop(其他情況)三種情況。
- 方法(3)的思路是,每次循環分為from up(如果left不為NULL,push left否則right不為NULL,push right), from left(若right不為空push right),from right(其他情況)三種情況。
1.Discuss區的summary:
https://leetcode.com/discuss/71943/preorder-inorder-and-postorder-iteratively-summarization
-
preorder
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode p = root;
while(!stack.isEmpty() || p != null) {
if(p != null) {
stack.push(p);
result.add(p.val); // Add before going to children
p = p.left;
} else {
TreeNode node = stack.pop();
p = node.right;
}
}
return result;
} -
inorder
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode p = root;
while(!stack.isEmpty() || p != null) {
if(p != null) {
stack.push(p);
p = p.left;
} else {
TreeNode node = stack.pop();
result.add(node.val); // Add after all left children
p = node.right;
}
}
return result;
}
3) postorder
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> result = new LinkedList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode p = root;
while(!stack.isEmpty() || p != null) {
if(p != null) {
stack.push(p);
result.addFirst(p.val); // Reverse the process of preorder
p = p.right; // Reverse the process of preorder
} else {
TreeNode node = stack.pop();
p = node.left; // Reverse the process of preorder
}
}
return result;
}
這個postorder用了取巧的方法,不如下面這種后序遍歷的實現,這個很舒服:
//后序遍歷的非遞歸實現
void BT_PostOrderNoRec(pBintree root)
{
stack<pBintree> s;
pBintree pre = NULL;
pBintree top = NULL;
while((root != NULL) || (!s.empty()))
{
if(root != NULL)
{
s.push(root);
root = root->left;
}
else
{
top = s.top();
if(top->right != NULL && top->right != pre)
root = top->right;
else
{
visit(top);
pre = top;
s.pop();
}
}
}
}
2.lastpop方法
https://leetcode.com/discuss/9736/accepted-code-with-explaination-does-anyone-have-better-idea
-
preorder
void preorder_traversal_iteratively(TreeNode* root)
{
if (root == 0)
return;
stack<TreeNode> s;
s.push(root);
cout << root->val << ' '; // visit root
TreeNode last_pop = root;
while (!s.empty())
{
TreeNode* top = s.top();
if (top->left != 0 && top->left != last_pop && top->right != last_pop) // push_left
{
s.push(top->left);
cout << top->left->val << ' '; // visit top->left
}
else if (top->right != 0 && top->right != last_pop && (top->left == 0 || top->left == last_pop)) // push_right
{
s.push(top->right);
cout << top->right->val << ' '; // visit top->right
}
else // pop
{
s.pop();
last_pop = top;
}
}
} -
inorder
void inorder_traversal_iteratively(TreeNode* root)
{
if (root == 0)
return;
stack<TreeNode> s;
s.push(root);
TreeNode last_pop = root;
while (!s.empty())
{
TreeNode* top = s.top();
if (top->left != 0 && top->left != last_pop && top->right != last_pop) // push_left
{
s.push(top->left);
}
else if (top->right != 0 && top->right != last_pop && (top->left == 0 || top->left == last_pop)) // push_right
{
s.push(top->right);
cout << top->val << ' '; // visit top
}
else // pop
{
s.pop();
last_pop = top;
if (top->right == 0)
cout << top->val << ' '; // visit top
}
}
} -
postorder
void postorder_traversal_iteratively(TreeNode* root)
{
if (root == 0)
return;
stack<TreeNode> s;
s.push(root);
TreeNode last_pop = root;
while (!s.empty())
{
TreeNode* top = s.top();
if (top->left != 0 && top->left != last_pop && top->right != last_pop) // push_left
{
s.push(top->left);
}
else if (top->right != 0 && top->right != last_pop && (top->left == 0 || top->left == last_pop)) // push_right
{
s.push(top->right);
}
else // pop
{
s.pop();
last_pop = top;
cout << top->val << ' '; // visit top
}
}
}
3.prev記錄方法 - 九章算法里的postorder做法:
//Iterative
public ArrayList<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> result = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode prev = null; // previously traversed node
TreeNode curr = root;
if (root == null) {
return result;
}
stack.push(root);
while (!stack.empty()) {
curr = stack.peek();
if (prev == null || prev.left == curr || prev.right == curr) { // traverse down the tree
if (curr.left != null) {
stack.push(curr.left);
} else if (curr.right != null) {
stack.push(curr.right);
}
} else if (curr.left == prev) { // traverse up the tree from the left
if (curr.right != null) {
stack.push(curr.right);
}
} else { // traverse up the tree from the right
result.add(curr.val);
stack.pop();
}
prev = curr;
}
return result;
}
4.用兩個棧實現后序遍歷的方法:
設置兩個棧stk, stk2;
將根結點壓入第一個棧stk;
彈出stk棧頂的結點,并把該結點壓入第二個棧stk2;
將當前結點的左孩子和右孩子先后分別入棧stk;
當所有元素都壓入stk2后,依次彈出stk2的棧頂結點,并訪問之。
第一個棧的入棧順序是:根結點,左孩子和右孩子;于是,壓入第二個棧的順序是:根結點,右孩子和左孩子。因此,彈出的順序就是:左孩子,右孩子和根結點。
void postOrder2(TreeNode *root) {
if(root == NULL)
return;
stack<TreeNode *> stk, stk2;
stk.push(root);
while(!stk.empty()) {
TreeNode *pNode = stk.top();
stk.pop();
stk2.push(pNode);
if(pNode->left != NULL)
stk.push(pNode->left);
if(pNode->right != NULL)
stk.push(pNode->right);
}
while(!stk2.empty()) {
cout << stk2.top()->val << endl;
stk2.pop();
}
}