二叉樹的非遞迴遍歷寫法
二叉樹的非遞迴遍歷寫法
前序遍歷
前序遍歷是按照“中-左-右”的遍歷方式對二叉樹進行訪問
第一種寫法
第一種寫法較為直觀,模擬遞迴棧的做法,先獲取到當前節點,進行列印,然後將該節點的右子樹和左子樹的根節點分別入棧,再將左子樹的根節點出棧,對該節點進行同樣處理。由於我們希望得到“中-左-右”順序,在列印完中節點之後,我們將右節點在左節點之前入棧,根據棧的後入先出的原則,我們先取到對應左節點進行處理。
vector<int> preOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
stack<TreeNode *> stk;
TreeNode *node = root;
stk.push(node);
while (!stk.empty()) {
node = stk.top();
stk.pop();
result.push_back(node->val);
if (node->left) stk.push(node->left);
if (node->right) stk.push(node->right);
}
return result;
}
觀察上面程式碼發現,左節點總是壓入棧中取到這個節點的孩子節點之後裡面會被出棧,利用這個性質,我們可以將程式碼優化為只壓入右節點以減少棧操作進行優化。
vector<int> preOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
stack<TreeNode *>stk;
TreeNode *node = root;
while (node != nullptr || !stk.empty()) {
if (node != nullptr) { // 還能繼續迭代獲取左節點
result.push_back(node->val);
if (node->right) {
stk.push(node->right);
}
node = node->left;
} else { // 左節點已經遍歷到葉節點
node = stk.top();
stk.pop();
}
}
return result;
}
第二種寫法
另一種是比較通用的模板方法,記住沿路的所有節點,先遍歷所有的左子節點,然後彈出最近的左子節點,取該節點的右子節點,繼續遍歷。
vector<int> preOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
stack<TreeNode *> stk;
TreeNode *node = root;
while (node != nullptr || !stk.empty()) {
while (node != nullptr) {
result.push_back(node->val);
stk.push(node);
node = node->left;
}
node = stk.top()->right;
stk.pop();
}
return result;
}
中序遍歷
中序遍歷遵循“左-中-右”的遍歷原則對二叉樹進行訪問。
中序遍歷先訪問的是二叉樹的頂部節點,然後一層層向下訪問,直到達到樹左邊的最底部,再開始處理節點,由於處理順序和訪問順序不一致,需要紀錄下整個訪問路徑,對應前序遍歷的第二種解法,在出棧的時候列印二叉樹的節點。
vector<int> inOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
stack<TreeNode *> stk;
TreeNode *node = root;
while (node != nullptr || !stk.empty()) {
while (node != nullptr) {
stk.push(node);
node = node->left;
}
node = stk.top();
stk.pop();
result.push_back(node->val);
node = node->right;
}
return result;
}
或者,將中間的while語句提升到外層
vector<int> inOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
stack<TreeNode *> stk;
TreeNode *node = root;
while (node != nullptr || !stk.empty()) {
if (node != nullptr) {
stk.push(node);
node = node->left;
} else {
node = stk.top();
stk.pop();
result.push_back(node->val);
node = node->right;
}
}
return result;
}
後序遍歷
後序遍歷的順序為“左-右-中”。
第一種寫法(雙棧寫法或者需要額外逆序操作)
按照後序遍歷的特點,我們可以先獲得“中-右-左”的序列,再進行逆序或者棧操作顛倒輸出順序得到結果(思路見前序遍歷的第一種寫法)。
vector<int> postOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
TreeNode *node = root;
stack<TreeNode *> stk;
stk.push(node);
while (!stk.empty()) {
node = stk.top();
stk.pop();
result.push_back(node->val);
if (node->left) stk.push(node->left);
if (node->right) stk.push(node->right);
}
reverse(result.begin(), result.end());
return result;
}
第二種寫法(單棧寫法)
後序遍歷在整個過程中需要將左子樹和右子樹都訪問完成才會繼續訪問根節點。在前序遍歷的第二種寫法和中序遍歷的迭代寫法中,我們記住了整個訪問路徑,在出棧時,我們還要拿到該節點的右節點資訊,訪問過右節點之後還會再拿到該節點的資訊,所以一個節點訪問兩次,我們需要記住在右節點已經訪問之後才訪問根節點。所以,我們設定 last,在訪問完節點之後賦值為當前節點。
vector<int> postOrder(TreeNode *root) {
vector<int> result;
if (root == nullptr) {
return result;
}
TreeNode *node = root;
TreeNode *last = nullptr;
stack<TreeNode *> stk;
while (node != nullptr || !stk.empty()) {
while (node != nullptr) {
stk.push(node);
node = node->left;
}
node = stk.top();
if (node->right == nullptr || node->right == last) {
result.push_back(node->val);
last = node; // 將last置為當前訪問節點
node = nullptr; // 對當前元素訪問完成之後,需要繼續彈出棧頂元素,所以將node置為nullptr
stk.pop();
} else {
node = node->right;
}
}
return result;
}
相關文章
- 遍歷二叉樹-------遞迴&非遞迴二叉樹遞迴
- 什麼是遍歷二叉樹,JavaScript實現二叉樹的遍歷(遞迴,非遞迴)二叉樹JavaScript遞迴
- 二叉樹的四種遍歷(遞迴與非遞迴)二叉樹遞迴
- 非遞迴先序遍歷二叉樹遞迴二叉樹
- 樹3-二叉樹非遞迴遍歷(棧)二叉樹遞迴
- 二叉樹的所有遍歷非遞迴實現二叉樹遞迴
- 遍歷二叉樹的遞迴與非遞迴程式碼實現二叉樹遞迴
- 二叉樹的前中後序遍歷(遞迴和非遞迴版本)二叉樹遞迴
- 二叉樹——後序遍歷的遞迴與非遞迴演算法二叉樹遞迴演算法
- python實現二叉樹及其七種遍歷方式(遞迴+非遞迴)Python二叉樹遞迴
- 二叉樹的遍歷 → 不用遞迴,還能遍歷嗎二叉樹遞迴
- 遍歷二叉樹的迭代和遞迴方法二叉樹遞迴
- Day14 | 二叉樹遞迴遍歷二叉樹遞迴
- 刷題系列 - Python用非遞迴實現二叉樹前序遍歷Python遞迴二叉樹
- 二叉樹的建立與遍歷(遞迴實現)二叉樹遞迴
- 刷題系列 - Python用非遞迴實現二叉樹後續遍歷Python遞迴二叉樹
- 刷題系列 - Python用非遞迴實現二叉樹中序遍歷Python遞迴二叉樹
- 二叉樹建立後,如何使用遞迴和棧遍歷二叉樹?二叉樹遞迴
- 迴圈遍歷二叉樹二叉樹
- 【C++】翻轉二叉樹(遞迴、非遞迴)C++二叉樹遞迴
- 非遞迴實現先序遍歷和中序遍歷遞迴
- 二叉樹的遍歷 (迭代法)二叉樹
- Android遍歷所有控制元件的遞迴和非遞迴實現Android控制元件遞迴
- Java中用遞迴和迭代實現二叉樹的中序( InOrder )遍歷Java遞迴二叉樹
- 資料結構-樹以及深度、廣度優先遍歷(遞迴和非遞迴,python實現)資料結構遞迴Python
- 【Java資料結構與演算法筆記(二)】樹的四種遍歷方式(遞迴&非遞迴)Java資料結構演算法筆記遞迴
- 二叉樹的遍歷二叉樹
- 【根據前序和中序遍歷構造二叉樹】棧+迭代 || 遞迴二叉樹遞迴
- 二叉樹遍歷二叉樹
- 二叉樹---遍歷二叉樹
- 資料結構初階--二叉樹(前中後序遍歷遞迴+非遞迴實現+相關求算結點實現)資料結構二叉樹遞迴
- 144.二叉樹的前序遍歷145.二叉樹的後序遍歷 94.二叉樹的中序遍歷二叉樹
- [資料結構]二叉樹的前中後序遍歷(遞迴+迭代實現)資料結構二叉樹遞迴
- 程式碼隨想錄演算法訓練營,9月9日 | 二叉樹遞迴遍歷,迭代遍歷,層序遍歷演算法二叉樹遞迴
- 完全二叉樹的遍歷二叉樹
- 二叉樹迭代器(中序遞迴、前序和後序遍歷)演算法二叉樹遞迴演算法
- 玩轉二叉樹(樹的遍歷)二叉樹
- 遞迴遍歷樹狀結構優雅實現遞迴