二叉樹具備自然的遞歸特性,凡是二叉樹相關題,首先應該聯想到遞歸html
struct BinTreeNode { BinTreeNode* left; BinTreeNode* right; int val; BinTreeNode(int value) : left(nullptr), right(nullptr), val(value) { } };
詳見筆者博文:二叉樹遍歷大總結node
#include <iostream> #include <vector> #include <stack> using namespace std; // 二叉樹遞歸定義 struct BinTreeNode { BinTreeNode* left; BinTreeNode* right; int val; BinTreeNode(int value) : left(NULL), right(NULL), val(value) { } }; // 根據結點值構建二叉樹 BinTreeNode* BuildBinTree(BinTreeNode* root, int value) { if (root == NULL) { root = new BinTreeNode(value); // 結點爲空,new一個節點 } else if (value <= root->val) { root->left = BuildBinTree(root->left, value); } else { root->right = BuildBinTree(root->right, value); } return root; } // 先序遍歷,遞歸 void PreOrder(BinTreeNode* root) { if (root == NULL) return; std::cout << root->val << "-->"; // 訪問節點 PreOrder(root->left); PreOrder(root->right); } // 先序遍歷,非遞歸,棧版本 void PreOrderStk(BinTreeNode* root) { if (root == NULL) return; std::stack<BinTreeNode*> stk; while (root != NULL || !stk.empty()) { while (root != NULL) { std::cout << root->val << "-->"; // 訪問節點 stk.push(root); root = root->left; // 深度優先搜索到最左節點,而後回溯 } BinTreeNode* cur = stk.top(); stk.pop(); root = cur->right; // 轉向右子樹 } } // 先序遍歷,非遞歸,非棧,Morris void PreOrderMorris(BinTreeNode* root) { if (root == NULL) return; BinTreeNode* prev = NULL; BinTreeNode* cur = root; // cur爲正在訪問的結點 while (cur != NULL) { if (cur->left == NULL) { std::cout << cur->val << "-->"; // 訪問節點 cur = cur->right; } else { prev = cur->left; // 前驅結點爲 左子樹最右下節點 while (prev->right != NULL && prev->right != cur) { prev = prev->right; } if (prev->right == NULL) { // 還沒線索化,則創建線索 std::cout << cur->val << "-->"; // 僅這一行與中序不一樣 prev->right = cur; // 創建線索 cur = cur->left; // 轉向處理左子樹 } else { cur = cur->right; // 轉向處理右子樹 prev->right = NULL; // 已經線索化,則刪除線索 } } } } // 中序遍歷,遞歸 void InOrder(BinTreeNode* root) { if (root == NULL) return; InOrder(root->left); std::cout << root->val << "-->"; // 訪問節點 InOrder(root->right); } // 中序遍歷,非遞歸,棧版本 void InOrderStk(BinTreeNode* root) { if (root == NULL) return; std::stack<BinTreeNode*> stk; while (root != NULL || !stk.empty()) { while (root != NULL) { stk.push(root); root = root->left; // 深度優先搜索到最左節點,而後回溯 } BinTreeNode* cur = stk.top(); stk.pop(); std::cout << cur->val << "-->"; // 訪問節點 root = cur->right; // 轉向右子樹 } } // 中序遍歷,非遞歸,非棧,Morris void InOrderMorris(BinTreeNode* root) { if (root == NULL) return; BinTreeNode* prev = NULL; BinTreeNode* cur = root; // cur爲正在訪問的結點 while (cur != NULL) { if (cur->left == NULL) { std::cout << cur->val << "-->"; // 訪問節點 cur = cur->right; } else { prev = cur->left; // 前驅結點爲 左子樹最右下節點 while (prev->right != NULL && prev->right != cur) { prev = prev->right; } if (prev->right == NULL) { // 還沒線索化,則創建線索 prev->right = cur; // 創建線索 cur = cur->left; // 轉向處理左子樹 } else { std::cout << cur->val << "-->"; // 已經線索化,則訪問節點,並刪除線索 cur = cur->right; // 轉向處理右子樹 prev->right = NULL; // 刪除線索 } } } } // 後序遍歷,遞歸 void PostOrder(BinTreeNode* root) { if (root == NULL) return; PostOrder(root->left); PostOrder(root->right); std::cout << root->val << "-->"; } // 後序遍歷,非遞歸,棧版本 void PostOrderStk(BinTreeNode* root) { if (root == NULL) return; std::stack<BinTreeNode*> stk; BinTreeNode* cur = root; BinTreeNode* prev = NULL; do { while (cur != NULL) { stk.push(cur); cur = cur->left; } prev = NULL; while (!stk.empty()) { cur = stk.top(); stk.pop(); if (cur->right == prev) { // 從右子樹返回,表示其右子樹已經訪問完畢 std::cout << cur->val << "-->"; prev = cur; } else { stk.push(cur); cur = cur->right; // 其右子樹還未訪問,轉向其右子樹訪問 break; } } } while (!stk.empty()); } // 層次遍歷,遞歸版 void LevelOrder(BinTreeNode* root, int level, std::vector<std::vector<int>>& res) { if (root == NULL) return; if (level > res.size()) { res.push_back(std::vector<int>()); } res.at(level - 1).push_back(root->val); LevelOrder(root->left, level + 1, res); LevelOrder(root->right, level + 1, res); } std::vector<std::vector<int>> LevelOrderHelp(BinTreeNode* root) { std::vector<std::vector<int>> res; LevelOrder(root, 1, res); return res; } // 層次遍歷,非遞歸,隊列版 void LevelOrderQueue(BinTreeNode* root) { if (root == NULL) return; std::deque<BinTreeNode*> dequeTreeNode; dequeTreeNode.push_back(root); while (!dequeTreeNode.empty()) { BinTreeNode* cur = dequeTreeNode.front(); dequeTreeNode.pop_front(); std::cout << cur->val << "-->"; // 訪問節點 if (cur->left != NULL) dequeTreeNode.push_back(cur->left); if (cur->right != NULL) dequeTreeNode.push_back(cur->right); } } int main() { // your code goes here std::vector<int> num = {6, 2, 7, 1, 4, 9, 3, 5, 8}; BinTreeNode* root = nullptr; for (auto val : num) { root = BuildBinTree(root, val); } std::cout << "1:PreOrder:" << std::endl; std::cout << "\t PreOrder:" ; PreOrder(root); std::cout << std::endl; std::cout << "\t PreOrderStk:"; PreOrderStk(root); std::cout << std::endl; std::cout << "\t PreOrderMorris:"; PreOrderMorris(root); std::cout << std::endl; std::cout << "2:InOrder:" << std::endl; std::cout << "\t InOrder:"; InOrder(root); std::cout << std::endl; std::cout << "\t InOrderStk:"; InOrderStk(root); std::cout << std::endl; std::cout << "\t InOrderMorris:"; InOrderMorris(root); std::cout << std::endl; std::cout << "3:PostOrder:" << std::endl; std::cout << "\t PostOrder:"; PostOrder(root); std::cout << std::endl; std::cout << "\t PostOrderStk:"; PostOrderStk(root); std::cout << std::endl; std::cout << "4:LevelOrder:" << std::endl; std::cout << "\t LevelOrder:"; LevelOrderQueue(root); std::cout << std::endl; return 0; }
1. 先序序列和中序序列構建一顆二叉樹 中序序列和後序序列構建一棵二叉樹ios
注:爲何先序和後序不能肯定一棵二叉樹?(例如:先序ABCD,後序CBDA)數組
給定先序遍歷序列和後序遍歷序列,求有多少種不一樣形態的二叉樹?post
考慮簡單的兩個節點A和B,前序遍歷爲AB,後序遍歷爲BA,則會存在兩種二叉樹: A->left=B 和 A->right=Bui
存在不一樣二叉樹的緣由在於某節點缺乏其中一個子樹,在遍歷序列中呈現出前序和後序遍歷中節點的值相鄰但順序相反(例如先序AB,後序BA),那麼總的二叉樹數量番倍spa
int BinTreeNum(const std::vector<int>& preOrder, const std::vector<int>& postOrder) { assert(preOrder.size() == postOrder.size()); int num = 1; for (int i = 0; i < preOrder.size(); ++i) { auto iter = std::find(postOrder.begin(), postOrder.end(), preOrder.at(i)); int index = std::distance(postOrder.begin(), iter); if (i < preOrder.size() - 1 && index > 0 && preOrder.at(i+1) == postOrder.at(index-1)) { num *= 2; } } return num; }
2. 有序數組/鏈表 構建一顆二叉查找樹BST.net
1. 判斷二叉查找樹BSTcode
2. 判斷平衡二叉樹htm
3. 判斷對稱二叉樹
4. 判斷相同二叉樹
5. 判斷二叉樹的子樹
1. 二叉樹路徑和問題
2. 二叉樹節點之間的最大距離(任意兩個節點之間的最大步數)
二叉樹中相距最遠的兩個節點之間的距離。
遞歸解法:
(1)若是二叉樹爲空,返回0,同時記錄左子樹和右子樹的深度,都爲0
(2)若是二叉樹不爲空,最大距離要麼是左子樹中的最大距離,要麼是右子樹中的最大距離,要麼是左子樹節點中到根節點的最大距離+右子樹節點中到根節點的最大距離,同時記錄左子樹和右子樹節點中到根節點的最大距離
int GetMaxDistance(BinTreeNode* root, int& maxLeft, int& maxRight) { // maxLeft, 左子樹中的節點距離根節點的最遠距離 // maxRight, 右子樹中的節點距離根節點的最遠距離 if (root == NULL) { maxLeft = 0; maxRight = 0; return 0; } int maxLL, maxLR, maxRL, maxRR; int maxDistLeft = 0; int maxDistRight = 0; if (root->left != NULL) { maxDistLeft = GetMaxDistance(root->left, maxLL, maxLR); maxLeft = std::max(maxLL, maxLR) + 1; } else { maxDistLeft = 0; maxLeft = 0; } if (root->right != NULL) { maxDistRight = GetMaxDistance(root->right, maxRL, maxRR); maxRight = std::max(maxRL, maxRR) + 1; } else { maxDistRight = 0; maxRight = 0; } return std::max(maxLeft + maxRight, std::max(maxDistLeft, maxDistRight)); }
思路:有點相似於 數組最大子段和問題,部分和大於0,表示貢獻值爲0,能夠相加起來
咱們對二叉樹進行 dfs,先算出 左右子樹的和值 leftSum 和 rightSum, 若是 leftSum 或者 rightSum 大於0,則表示此結果對 後續結果是有利的
int maxSum = INT_MIN; int dfs(BinTreeNode* root) { if (root == NULL) return 0; int leftSum = dfs(root->left); int rightSum = dfs(root->right); int sum = root->val; if (leftSum > 0) sum += leftSum; if (rightSum > 0) sum += rightSum; maxSum = std::max(maxSum, sum); if (std::max(leftSum, rightSum) > 0) { return std::max(leftSum, rightSum) + root->val; } else { return root->val; } } int maxPathSum(BinTreeNode* root) { if (root == NULL) return 0; dfs(root); return maxSum; }
4. 二叉樹最低公共祖先
思路:先求取 根節點到兩個結點的路徑序列,而後在這兩個路徑中查找最後一個公共結點便可
擴展:如何求 兩個結點之間的距離呢? 能夠先分別求得 根節點到這兩個結點的路徑,而後 最低公共祖先結點到 結點A的距離 + 最低公共祖先結點到 結點B的距離
struct BinTreeNode { BinTreeNode* left; BinTreeNode* right; int val; BinTreeNode(int value) : left(NULL), right(NULL), val(value) { } }; BinTreeNode* BuildBinTree(BinTreeNode* root, int value) { if (root == NULL) { root = new BinTreeNode(value); } else if (value <= root->val) { root->left = BuildBinTree(root->left, value); } else { root->right = BuildBinTree(root->right, value); } return root; } // 二叉樹中序 遞歸 void Inorder(BinTreeNode* root) { if (root == NULL) return; Inorder(root->left); std::cout << root->val << "-->"; Inorder(root->right); } // 二叉樹中序 非遞歸 棧 void InorderStk(BinTreeNode* root) { if (root == NULL) return; std::stack<BinTreeNode*> stk; while (root != NULL || !stk.empty()) { while (root != NULL) { stk.push(root); root = root->left; } BinTreeNode* cur = stk.top(); stk.pop(); std::cout << cur->val << "-->"; root = cur->right; } } // 二叉樹中序 非遞歸 非棧 void InorderMorris(BinTreeNode* root) { if (root == NULL) return; BinTreeNode* cur = root; BinTreeNode* prev = NULL; while (cur != NULL) { if (cur->left == NULL) { std::cout << cur->val << "-->"; prev = cur; cur = cur->right; } else { BinTreeNode* node = cur->left; while (node->right != NULL && node->right != cur) { node = node->right; } if (node->right == NULL) { node->right = cur; cur = cur->left; } else { std::cout << cur->val << "-->"; prev = cur; cur = cur->right; node->right = NULL; } } } } // 按值查找結點 BinTreeNode* GetNode(BinTreeNode* root, int value) { if (root == NULL) return NULL; if (root->val == value) { return root; } else if (value < root->val) { return GetNode(root->left, value); } else { return GetNode(root->right, value); } } // 獲取從根節點到某節點的路徑 bool GetNodePath(BinTreeNode* root, BinTreeNode* pNode, std::vector<BinTreeNode*>& path) { if (root == NULL || pNode == NULL) return false; bool found = false; if (root == pNode) { path.push_back(root); found = true; return found; } path.push_back(root); found = GetNodePath(root->left, pNode, path); if (!found) { // 左子樹未找到,繼續右子樹找 found = GetNodePath(root->right, pNode, path); } if (!found) { // 左右子樹均未找到,此時才pop path.pop_back(); } return found; } // 兩個結點的最低公共祖先 BinTreeNode* GetLastCommonParent(BinTreeNode* root, BinTreeNode* pNode1, BinTreeNode* pNode2) { if (root == NULL || pNode1 == NULL || pNode2 == NULL) { return NULL; } std::vector<BinTreeNode*> path1; std::vector<BinTreeNode*> path2; bool bFound1 = GetNodePath(root, pNode1, path1); bool bFound2 = GetNodePath(root, pNode2, path2); if (bFound1 == false || bFound2 == false) { return NULL; } std::vector<BinTreeNode*>::iterator iter1 = path1.begin(); std::vector<BinTreeNode*>::iterator iter2 = path2.begin(); for (; iter1 != path2.end() && iter2 != path2.end(); ++iter1, ++iter2) { if (*iter1 != *iter2) { break; } } --iter1; return *iter1; }