二叉树理论基础
一个节点指向左右两个孩子节点构成的树状结构。
二叉树的种类
一棵二叉树只有度为0和度为2的节点,且度为0的节点都在同一层上时,该二叉树为满二叉树。深度为k的满二叉树,节点一定有\(2 ^k - 1\)个。
满二叉树,图源代码随想录
除了最底层节点可能没填满以外,每层节点都达到了最大值,且最底层节点都集中在左侧。
完全二叉树
二叉搜索树是个有序树,其左子树上的节点的值均小于根节点的值,右子树上的值均大于根节点的值,且左右子树也是二叉搜索树。
二叉搜索树
平衡二叉搜索树实在二叉搜索树的基础上,添加以下要求:
- 为空树或者左右子树高度差不大于1
- 左右子树都是平衡二叉搜索树
平衡二叉搜索树
C++中map, set, multimap,
multiset的底层实现都是平衡二叉搜索树,所以map,
set的增删操作时间都是\(O(logn)\)。unordered_set、unordered_map
的实现是哈希表。
二叉树的存储方式
可以链式存储,也可以顺序存储
使用链表的形式,通过左右孩子指针完成链接。
链式存储二叉树
就是使用数组来存储二叉树。若父节点的索引为\(i\),其左孩子节点索引为\(2 * i + 1\),右孩子节点索引为\(2 * i + 2\)。
二叉树的遍历方式
优先向深度递增的方向访问。可分为前序遍历、中序遍历、后序遍历。
优先访问同一深度的节点。有层次遍历。
二叉树的定义
1 2 3 4 5
| struct TreeNode { int data; TreeNode *left; TreeNode *right; };
|
二叉树递归遍历
例题:
递归遍历的写法比较简单,按照前中后三种遍历方式的定义来写即可。
前序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { private: void preOrderTravel(TreeNode *root, vector<int> &result) { if (root == NULL) return; result.push_back(root -> val); preOrderTravel(root -> left, result); preOrderTravel(root -> right, result); } public: vector<int> preorderTraversal(TreeNode* root) { vector<int> result; if (root == NULL) return result; preOrderTravel(root, result); return result; } };
|
中序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { private: void inOrderTravel(TreeNode *root, vector<int> &result) { if (!root) return; inOrderTravel(root -> left, result); result.push_back(root -> val); inOrderTravel(root -> right, result); } public: vector<int> inorderTraversal(TreeNode* root) { vector<int> result; if (!root) return result; inOrderTravel(root, result); return result; } };
|
后序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { private: void postOrderTravel(TreeNode *root, vector<int> &result) { if (root == NULL) return; postOrderTravel(root -> left, result); postOrderTravel(root -> right, result); result.push_back(root -> val); } public: vector<int> postorderTraversal(TreeNode* root) { vector<int> result; if (!root) return result; postOrderTravel(root, result); return result; } };
|
二叉树迭代遍历
使用迭代来完成二叉树的遍历也是一个重点.二叉树的迭代遍历中,最主要的部分是对栈的调用.
前序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<int> result; if (root == NULL) return result; stack<TreeNode*> st; st.push(root); while (!st.empty()) { TreeNode *node = st.top(); st.pop(); result.push_back(node -> val); if (node -> right) st.push(node -> right); if (node -> left) st.push(node -> left); } return result; } };
|
中序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public: vector<int> inorderTraversal(TreeNode* root) { vector<int> result; if (!root) return result; stack<TreeNode*> st; TreeNode* cur = root; while (cur != NULL || !st.empty()) { if (cur) { st.push(cur); cur = cur -> left; } else { cur = st.top(); st.pop(); result.push_back(cur -> val); cur = cur -> right; } } return result; } };
|
后序遍历:
后序遍历的顺序是左右中,可以通过中右左的顺序逆转来完成.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public: vector<int> postorderTraversal(TreeNode* root) { vector<int> result; if (!root) return result; stack<TreeNode*> st; st.push(root); while (!st.empty()) { TreeNode *cur = st.top(); st.pop(); result.push_back(cur -> val); if (cur -> left) st.push(cur -> left); if (cur -> right) st.push(cur -> right); } reverse(result.begin(), result.end()); return result; } };
|
二叉树统一迭代法
上面的迭代法写的方式不够统一. 下面是三种遍历比较统一的写法.
前序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<int> result; if (root == NULL) return result; stack<TreeNode*> st; st.push(root); while (!st.empty()) { TreeNode *node = st.top(); if (node) { st.pop(); if (node -> right) st.push(node -> right); if (node -> left) st.push(node -> left); st.push(node); st.push(NULL); } else { st.pop(); node = st.top(); st.pop(); result.push_back(node -> val); } } return result; } };
|
中序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<int> result; if (root == NULL) return result; stack<TreeNode*> st; st.push(root); while (!st.empty()) { TreeNode *node = st.top(); if (node) { st.pop(); if (node -> right) st.push(node -> right); st.push(node); st.push(NULL); if (node -> left) st.push(node -> left); } else { st.pop(); node = st.top(); st.pop(); result.push_back(node -> val); } } return result; } };
|
后序遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<int> result; if (root == NULL) return result; stack<TreeNode*> st; st.push(root); while (!st.empty()) { TreeNode *node = st.top(); if (node) { st.pop(); st.push(node); st.push(NULL); if (node -> right) st.push(node -> right); if (node -> left) st.push(node -> left); } else { st.pop(); node = st.top(); st.pop(); result.push_back(node -> val); } } return result; } };
|