【题目】
用递归和非递归方式,分别按照二叉树先序、中序和后序打印所有的节点。我们约定:先序遍历顺序为根、左、右;中序遍历顺序为左、根、右;后序遍历顺序为左、右、根。
1 #include <iostream> 2 #include <queue> 3 #include <vector> 4 #include <stack> 5 using namespace std; 6 struct Node 7 { 8 int v; 9 Node *r, *l; 10 Node(int a = -1) :v(a), r(nullptr), l(nullptr) {} 11 }; 12 Node* root = nullptr; 13 vector<int>res; 14 void creatTree() 15 { 16 root = new Node(1); 17 root->l = new Node(2); 18 root->r = new Node(3); 19 root->l->l = new Node(4); 20 root->l->r = new Node(5); 21 root->r->l = new Node(6); 22 root->r->r = new Node(7); 23 } 24 /////////////递归方式/////////////// 25 void preOrder(Node* root)//前序遍历 26 { 27 if (root == nullptr) 28 return; 29 res.push_back(root->v); 30 preOrder(root->l); 31 preOrder(root->r); 32 } 33 void inOrder(Node* root)//中序遍历 34 { 35 if (root == nullptr) 36 return; 37 preOrder(root->l); 38 res.push_back(root->v); 39 preOrder(root->r); 40 } 41 void lastOrder(Node* root)//后序遍历 42 { 43 if (root == nullptr) 44 return; 45 lastOrder(root->l); 46 lastOrder(root->r); 47 res.push_back(root->v); 48 } 49 /////////////非递归方式/////////// 50 void NpreOrder(Node* root)//前序遍历 51 //1.申请一个新的栈,记为stack。然后将头节点head压入stack中。 52 //2.从stack中弹出栈顶节点,记为cur,然后打印cur节点的值,再将节点cur的右孩子(不为空的话)先压入stack中,最后将cur的左孩子(不为空的话)压入stack中。 53 //3.不断重复步骤2,直到stack为空,全部过程结束。 54 { 55 if (root == nullptr) 56 return; 57 stack<Node*>s; 58 s.push(root); 59 while (!s.empty()) 60 { 61 Node* p = s.top(); 62 s.pop(); 63 res.push_back(p->v); 64 if (p->r != nullptr) 65 s.push(p->r); 66 if (p->l != nullptr) 67 s.push(p->l); 68 } 69 } 70 71 void NinOrder(Node* root)//中序遍历 72 //1.申请一个新的栈,记为stack。初始时,令变量cur = head。 73 //2.先把cur节点压入栈中,对以cur节点为头的整棵子树来说,依次把左边界压入栈中,即不停地令cur = cur.left,然后重复步骤2。 74 //3.不断重复步骤2,直到发现cur为空,此时从stack中弹出一个节点,记为node。 75 //打印node的值,并且让cur = node.right,然后继续重复步骤2。 76 //4.当stack为空且cur为空时,整个过程停止。 77 { 78 if (root == nullptr) 79 return; 80 stack<Node*>s; 81 Node* p = root; 82 while (p != nullptr || !s.empty()) 83 { 84 if (p != nullptr) 85 { 86 s.push(p); 87 p = p->l; 88 } 89 else 90 { 91 p = s.top(); 92 s.pop(); 93 res.push_back(p->v); 94 p = p->r; 95 } 96 } 97 } 98 void NlastOrder1(Node* root)//后序遍历 99 //先介绍用两个栈实现后序遍历的过程,具体过程如下: 100 //1.申请一个栈,记为sl,然后将头节点head压入sl中。 101 //2.从sl中弹出的节点记为cur,然后依次将cur的左孩子和右孩子压入sl中。 102 //3.在整个过程中,每一个从s1中弹出的节点都放进s2中。 103 //4.不断重复步骤2和步骤3,直到s1为空,过程停止。 104 //5.从s2中依次弹出节点并打印,打印的顺序就是后序遍历的顺序。 105 { 106 if (root == nullptr) 107 return; 108 stack<Node*>s1, s2; 109 s1.push(root); 110 Node* p; 111 while (!s1.empty()) 112 { 113 p = s1.top(); 114 s1.pop(); 115 s2.push(p); 116 if (p->l != nullptr) 117 s1.push(p->l); 118 if (p->r != nullptr) 119 s1.push(p->r); 120 } 121 while (!s2.empty()) 122 { 123 p = s2.top(); 124 s2.pop(); 125 res.push_back(p->v); 126 } 127 } 128 void NlastOrder2(Node* root)//后序遍历 129 //最后介绍只用一个栈实现后序遍历的过程,具体过程如下: 130 //1.申请一个栈,记为stack,将头节点压入stack,同时设置两个变量h和c。在整个流程中,h代表最近一次弹出并打印的节点,c代表stack的栈顶节点,初始时h为头节点,c为null。 131 //2.每次令c等于当前stack的栈顶节点但是不从stack中弹出此时分以下三种情况。 132 //①如果c的左孩子不为null,并且h不等于c的左孩子,也不等于c的右孩子,则把c的左孩子压入stack中。具体解释一下这么做的原因,首先h的意义是最近一次弹出并打印的节点,所以如果h等于c的左孩子或者右孩子,说明c的左子树与右子树已经打印完毕,此时不应该再将c的左孩子放入stack中。否则,说明左子树还没处理过,那么此时将c的左孩子压入stack中。 133 //②如果条件①不成立,并且c的右孩子不为null,h不等于c的右孩子,则把c的右孩子压入stack中。含义是如果h等于c的右孩子,说明c的右子树已经打印完毕,此时不应该再将c的右孩子放入stack中。否则,说明右子树还没处理过,此时将c的右孩子压入stack中。 134 //③如果条件①和条件②都不成立,说明c的左子树和右子树都已经打印完毕,那么从stack中弹出c并打印,然后令h = c。 135 //3.一直重复步骤2,直到stack为空,过程停止。 136 { 137 if (root == nullptr) 138 return; 139 stack<Node*>s; 140 s.push(root); 141 Node* p;//root==h p==c 142 while (!s.empty()) 143 { 144 p = s.top(); 145 if (p->l != nullptr && root != p->l && root != p->r) 146 s.push(p->l); 147 else if (p->r != nullptr && root != p->r) 148 s.push(p->r); 149 else 150 { 151 res.push_back(p->v); 152 s.pop(); 153 root = p; 154 } 155 } 156 } 157 158 int main() 159 { 160 161 }