二叉树的操作模板
- 使用递归进行遍历、查找、插入、删除、判断合法性
二叉树的遍历
先序遍历
void preorder(TreeNode* root){
if(!root) return ;
nums.push_back(root->val);
preorder(root->left);
preorder(root->right);
}
递归版本:
vector<int> preorder(TreeNode* root){
vector<int> result;
stack<TreeNode*> st;
TreeNode* node = root;
while(node || !st.empty()){
while(node){
st.push(node);
result.push_back(node->val);
node = node->left;
}
if(!st.empty()){
auto t = st.top();
st.pop();
node = t->right;
}
}
return result;
}
中序遍历
void inorder(TreeNode* root){
if(!root) return ;
inorder(root->left);
nums.push_back(root->val);
inorder(root->right);
}
递归版本:
vector<int> preorder(TreeNode* root){
vector<int> result;
stack<TreeNode*> st;
TreeNode* node = root;
while(node || !st.empty()){
while(node){
st.push(node);
node = node->left;
}
if(!st.empty()){
auto t = st.top();
st.pop();
result.push_back(node->val);
node = t->right;
}
}
return result;
}
后序遍历
void postorder(TreeNode* root){
if(!root) return;
postorder(root->left);
postorder(root->right);
nums.push_back(root->val);
}
递归版本:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<pair<TreeNode*,int>> st;
TreeNode* node = root;
if(!root) return result;
while(node || !st.empty()){
while(node){
st.push(make_pair(node,1));
node = node->left;
}
if(!st.empty()){
auto& t = st.top();
auto n = t.first;
if(t.second == 0){
st.pop();
result.push_back(n->val);
}else{
if(n->right)
node = n->right;
t.second = 0;
}
}
}
return result;
}
层次遍历
- 二叉树是无环的图,层次遍历使用BFS
- 可以使用 BFS+ Queue 来实现,也可以使用递归来实现
class Solution {
void levelOrder(TreeNode* node,vector<vector<int>>& res,int level){
if(!node) return ;
if(res.size() <= level) res.push_back({});
res[level].push_back(node->val);
levelOrder(node->left,res,level+1);
levelOrder(node->right,res,level+1);
}
typedef pair<TreeNode*,int> Pair;
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if(!root) return {};
vector<vector<int>> res;
levelOrder(root,res,0);
return res;
}
};
class Solution {
typedef pair<TreeNode*,int> Pair;
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if(!root) return {};
vector<vector<int>> res;
queue<Pair> vertex;
vertex.push({root,0});
while(vertex.size()){
auto cur = vertex.front();
vertex.pop();
auto node = cur.first;
if(!node) continue;
if(res.size()<=cur.second) res.push_back({});
res[cur.second].push_back(node->val);
vertex.push({node->left,cur.second+1});
vertex.push({node->right,cur.second+1});
}
return res;
}
};
宽度遍历
- 设节点的索引为i,则其左节点的索引为 i ∗ 2 i*2 i∗2,右节点的索引为 i ∗ 2 + 1 i*2+1 i∗2+1
- 所谓宽度遍历就是在层次遍历的时候,额外携带父节点的索引信息,则可以对每层的节点进行操作
class Solution {
vector<vector<double>> table;
int Height(TreeNode* root){
if(!root) return 0;
return max(Height(root->left),Height(root->right)) + 1;
}
void helper(TreeNode* root,int level,double index){
if(!root) return;
//记录每层中最左和最右节点的索引
if(table[level][0] == -1) table[level][0] = index;
else{
table[level][1] = index;
}
double m = index*2;
helper(root->left,level + 1,m);
helper(root->right,level + 1,m+1);
}
public:
int widthOfBinaryTree(TreeNode* root) {
int h = Height(root);
int size = pow(2,h);
table = vector<vector<double>>(h,vector<double>(2,-1));
helper(root,0,0);
double ans = 0;
//统计
for(auto& it : table){
if(it[1] == -1){
ans = max<double>(ans,1);
}else{
ans = max(ans,it[1] - it[0] + 1);
}
}
return ans;
}
};
- 可以发现,先/中/后序遍历其实就是什么时候对当前节点进行操作
- 先序: 先记录当前节点,在遍历左子树、右子树
- 中序: 先遍历左子树,再记录当前节点,再遍历右子树
- 后续: 先遍历左子树,再遍历右子树,最后记录当前节点
查找给定数字是否存在二叉树中
普通的二叉树
bool isExist(TreeNode* root,int target){
if(!root) return false;
if(root->val == target) return true;
return isExist(root->left,target) || isExist(root->right,target);
}
二叉搜索树
- 使用BST的性质,搜索时候进行二分
bool isExist(TreeNode* root,int target){
if(!root) return false;
if(root->va == target) return true;
else if(root->val < target)
return isExist(root->right,target);
else return isExist(root->left,left);
}
二叉搜索树中第K小元素
class Solution {
// cnt 来记录当前遍历的节点数目
int cnt = 0;
//val保存第k小的结果
int val;
void inorder(TreeNode* root,int k){
if(!root) return ;
inorder(root->left,k);
cnt++;
if(cnt == k){
val = root->val;
return;
}
inorder(root->right,k);
}
public:
int kthSmallest(TreeNode* root, int k) {
inorder(root,k);
return val;
}
};
BST的最小/最大值
TreeNode* Mininum(TreeNode* root){
if(!root) return nullptr;
if(!root->left) return root;
return Mininum(root->left);
}
TreeNode* Maxinum(TreeNode* root){
if(!root) return nullptr;
if(!root->right) return root;
return Maxinum(root->right);
}
BST 前驱/后继
TreeNode* Successor(TreeNode* root,int val){
if(!root) return nullptr;
auto* l = Successor(root->left,val);
if(l) return l;
if(root->val > val) return root;
auto* r = Successor(root->right,val);
if(r) return r;
return nullptr;
}
TreeNode* Precursor(TreeNode* root,int val){
if(!root) return nullptr;
auto* r = Precursor(root->right,val);
if(r) return r;
if(root->val < val) return root;
auto* l = Precursor(root->left,val);
if(l) return l;
return nullptr;
}
相同的树
- 使用先序遍历模板
- 如果当前节点都是null 或者值相同,则当前节点相同,继续比较左右子树节点
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(!p && !q) return true;
if(!p || !q || p->val != q->val) return false;
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
};
对称二叉树
class Solution {
public:
bool ismirror(TreeNode* p,TreeNode* q){
if(!p && !q) return true;
if(!p || !q || p->val != q->val) return false;
return ismirror(p->left,q->right) && ismirror(p->right,q->left);
}
bool isSymmetric(TreeNode* root) {
return ismirror(root,root);
}
};
合并二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
// 使用先序遍历框架,返回当前节点
if(!t1 && !t2) return nullptr;
TreeNode* root = new TreeNode(0);
TreeNode* l1 = nullptr,*l2 = nullptr,*r1 = nullptr,*r2 = nullptr;
if(t1){
root->val += t1->val;
l1 = t1->left;r1 = t1->right;
}
if(t2){
root->val += t2->val;
l2 = t2->left;r2 = t2->right;
}
root->left = mergeTrees(l1,l2);
root->right = mergeTrees(r1,r2);
return root;
}
};
反转二叉树
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(!root) return nullptr;
auto* l = invertTree(root->left);
root->left = invertTree(root->right);
root->right = l;
return root;
}
};
判断合法性
判断是否是二叉搜索树
- 节点的左子树只包含小于当前节点的数
- 节点的右子树只包含大于当前节点的数
- 所有左子树和右子树自身必须也是二叉搜索树
class Solution {
// 携带额外信息,从上层节点传入的最大值和最小值
bool isValidBST(TreeNode* root,TreeNode* min,TreeNode* max){
if(!root) return true;
if(min && root->val <= min->val){
return false;
}
if(max && root->val >= max->val){
return false;
}
return isValidBST(root->left,min,root) && isValidBST(root->right,root,max);
}
public:
bool isValidBST(TreeNode* root) {
return isValidBST(root,nullptr,nullptr);
}
};
判断是否是平衡二叉树
class Solution {
int depth(TreeNode* root){
if(!root) return 0;
int l = depth(root->left);
if(l < 0) return -1;
int r = depth(root->right);
if(r < 0) return -1;
if(abs(l-r) > 1) return -1;
return max(l,r) + 1;
}
public:
bool isBalanced(TreeNode* root) {
return depth(root) != -1;
}
};
验证二叉树
class Solution {
public:
bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
// a.不能有环,b.不能逆向,c.不能有多棵树
//每一个节点只能有一个父节点,使用一个unordered_map来记录每个节点的信息,每次插入新节点前,先查询父节点是否存在(解决c),再查询map中是否有新节点(解决a和b)
unordered_map<int,int> map;
int i = 0;
while(i < n &&leftChild[i] == -1 && rightChild[i] == -1) i++;
map[i] = i;
while(i < n){
// 该行验证父节点是否存在
if(map.count(i) == 0) return false;
int l = leftChild[i],r = rightChild[i];
if(l != -1){
//该行验证节点是否已经被使用,如果被使用过,可能会形成逆向和有环
if(map.count(l) != 0) return false;
map[l] = i;
}
if(r != -1){
if(map.count(r) != 0) return false;
map[r] = i;
}
i++;
}
return true;
}
};
插入
二叉搜索树的插入操作
- 递归插入
- 使用后续遍历的模板,找到新值的位置插入
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(!root) return new TreeNode(val);
if(root->val > val){
root->left = insertIntoBST(root->left,val);
}else{
root->right = insertIntoBST(root->right,val);
}
return root;
}
};
- 非递归插入
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
auto* node = new TreeNode(val);
TreeNode* x=nullptr,*y = root;
while(y){
x = y;
if(y->val > val) y = y->left;
else y = y->right;
}
if(!x) root = node;
else if(x->val > val) x->left = node;
else x->right = node;
return root;
}
};
BST 删除节点
- 设要删除的节点为Z
- 如果 Z 没有孩子节点,则直接删除Z
- 如果Z只有一个孩子节点,用孩子节点替代Z
- 如果Z有2个孩子节点,则需要找到Z的后继节点X和X的父节点
用X的right节点替代X,再用X替代Z
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(!root) return nullptr;
//找到该节点
if(root->val == key){
// 无孩子节点和只有一个孩子节点的情况
if(!root->left) return root->right;
if(!root->right) return root->left;
// 2个孩子节点
TreeNode* x = root,*y = root->right;
// 找到后继节点和后继节点的父节点
while(y->left){
x = y;
y = y->left;
}
// 后继节点y不是root->right节点时,需要先把y->right替代y,再把y替代root->right;
if(x != root){
x->left = y->right;
y->right = root->right;
}
y->left = root->left;
delete root;
return y;
}
if(root->val > key)
root->left = deleteNode(root->left,key);
else if(root->val < key)
root->right = deleteNode(root->right,key);
return root;
}
};
二叉树剪枝
分析
- 要求: 返回移除了所有不包含 1 的子树的原二叉树
- 重点在于删除 所有不包含1的子树
- 不包含1的子树:所有节点都是0,
- 那么从叶子节点开始往上走,只要节点值为0且该节点无左右节点,则本节点需要删除。
- 总体查找的时候需要按照后序遍历思路
class Solution {
public:
TreeNode* pruneTree(TreeNode* root) {
if(!root) return nullptr;
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
if(root->val == 0 && !root->left && ! root->right)
return nullptr;
else return root;
}
};
一个比较完整的BST 类
- BST.hxx
#pragma once
#include <vector>
#include <string>
#include <stdexcept>
struct TreeNode{
int val;
TreeNode* left = nullptr;
TreeNode* right = nullptr;
TreeNode(int v):val(v){}
};
class BST{
private:
TreeNode* root = nullptr;
TreeNode* DeleteTree(TreeNode* node);
void InsertNode(TreeNode* node);
TreeNode* SearchNode(int v);
void Depth(TreeNode* r,int&depth,int temp);
int Depth(TreeNode* r);
TreeNode* MaxNode(TreeNode* r){
if(!r) return nullptr;
while(r->right)
r = r->right;
return r;
}
TreeNode* MaxNode(){
return MaxNode(root);
}
TreeNode* MinNode(TreeNode* r){
if(!r) return nullptr;
while(r->left)
r = r->left;
return r;
}
TreeNode* MinNode(){
return MinNode(root);
}
void PreOrder(TreeNode* r,std::vector<int>& res);
void InOrder(TreeNode* r,std::vector<int>& res);
void PostOrder(TreeNode* r,std::vector<int>& res);
public:
BST(){}
~BST(){
DeleteTree(root);
}
void Put(int v){
TreeNode* node = new TreeNode(v);
InsertNode(node);
}
TreeNode* Get(int v){
return SearchNode(v);
}
// 递归操作
void PreOrder(std::vector<int>& res);
void InOrder(std::vector<int>& res);
void PostOrder(std::vector<int>& res);
// 非递归
std::vector<int> PreOrder();
std::vector<int> InOrder();
std::vector<int> PostOrder();
std::vector<std::vector<int>> LevelOrder();
TreeNode* DeleteNode(int v);
TreeNode* Successor(int v);
TreeNode* Predecessor(int v);
int MaxVal(){
TreeNode* m = MaxNode();
if(!m){
throw std::runtime_error("bst is empty");
}
return m->val;
}
int MinVal(){
TreeNode* m = MinNode();
if(!m)
throw std::runtime_error("bst is empty");
return m->val;
}
int Depth(){
if(!root)
return 0;
return Depth(root);
}
};
- BST.cpp
#include "BST.hxx"
#include <stack>
#include <queue>
#include <utility>
#include <cmath>
#include <unordered_map>
TreeNode* BST::DeleteTree(TreeNode* node){
if(!node){
return nullptr;
}
DeleteTree(node->left);
DeleteTree(node->right);
delete node;
return nullptr;
}
void BST::InsertNode(TreeNode* node){
TreeNode* r = root;
TreeNode* p = nullptr;
while(r){
p = r;
if(r->val < node->val){
r = r ->right;
}else if(r->val > node->val){
r = r->left;
}else{
return;
}
}
if(!p){
root = node;
return;
}
if(p->val < node->val)
p->right = node;
else
p->left = node;
}
TreeNode* BST::SearchNode(int v){
if(!root){
return nullptr;
}
TreeNode* r = root;
while(r){
if(r->val == v)
return r;
else if(r->val > v)
r = r->left;
else
r = r->right;
}
return nullptr;
}
// DFS
void BST::Depth(TreeNode*r,int&depth,int temp){
if(!r){
depth = std::max(depth,temp);
return;
}
Depth(r->left,depth,temp+1);
Depth(r->right,depth,temp+1);
}
int BST::Depth(TreeNode* r){
if(!r)
return 0;
int depth = 1;
Depth(r,depth,0);
return depth;
}
TreeNode* BST::Predecessor(int v){
// 1. find v node
// 2. if v node has left node,then the predecessor
// is the max node of left subtree of the v node
// 3. otherwise, the predecessor must be its ancestor node,
// which is the right node of parent
std::unordered_map<TreeNode*,TreeNode*> path;
TreeNode* r = root;
TreeNode* p = nullptr;
while(r){
path[r] = p;
if(r->val == v){
break;
}
p = r;
if (r->val < v){
r = r->right;
}else {
r = r->left;
}
}
TreeNode* vnode = r;
// not find v node;
if(!vnode){
return nullptr;
}
if(vnode->left){
return MaxNode(vnode->left);
}
while(p && p->left == vnode){
vnode = p;
p = path[vnode];
}
return p ? p : nullptr;
}
TreeNode* BST::Successor(int v){
/**
* 1. find vnode
* 2. if vnode has right node,the successor is the min node of its right subtree
* 3. otherwise,the successor must be its ancestor,which is the left node of its parent
*/
TreeNode* r = root;
TreeNode* p = nullptr;
std::unordered_map<TreeNode*,TreeNode*> path;
while(r){
path[r] = p;
if(r->val == v)
break;
p = r;
if(r->val < v){
r = r->right;
}else
{
r = r->left;
}
}
TreeNode* vnode = r;
if(!vnode)
return nullptr;
if(vnode->right)
return MinNode(vnode->right);
while(p && p->right == vnode){
vnode = p;
p = path[vnode];
}
return p ? p : nullptr;
}
TreeNode* BST::DeleteNode(int v){
/**
* 1. find v node
* 2. if v node is leaf, set left or right of its parent is nullptr
* 3. if v node only has left node , let its left node replace vnode
* 4. if v node only has right node, find minnode of its right subtree,
* let minnode replace vnode
* 5. if v node has left and right node, find minnode of its right subtree,
* let minnode replace vnode
*
*/
if(!root) return nullptr;
TreeNode* r = root;
TreeNode* p = nullptr;
TreeNode* pp = nullptr;
while(r){
if(r->val == v)
break;
pp = p;
p = r;
if(r->val < v)
r = r->right;
else
r = r->left;
}
// if vnode is root,its parent node is nullptr
if(!p){
root = nullptr;
return r;
}
TreeNode* vnode = p;
TreeNode** pp_child = pp->left == vnode ? &(pp->left) : &(pp->right);
// 1 and 2 case
if(!vnode->right){
*pp_child = vnode->left;
return vnode;
}
TreeNode* minnode = vnode->right;
while(minnode->left){
p = minnode;
minnode = minnode->left;
}
if(p != vnode){
p->left = minnode->right;
minnode->right = vnode->right;
}
minnode->left = vnode->left;
vnode->left = nullptr;
vnode->right = nullptr;
*pp_child = minnode;
return vnode;
}
void BST::PreOrder(TreeNode* r,std::vector<int>& res){
if(!r) return;
res.push_back(r->val);
PreOrder(r->left,res);
PreOrder(r->right,res);
}
void BST::PreOrder(std::vector<int>& res){
if(!root) return;
res.push_back(root->val);
PreOrder(root->left,res);
PreOrder(root->right,res);
}
std::vector<int> BST::PreOrder(){
std::vector<int> res;
std::stack<TreeNode*> stack;
TreeNode* r = root;
while(r || !stack.empty() ){
while(r){
res.push_back(r->val);
stack.push(r);
r = r->left;
}
if(!stack.empty()){
auto n = stack.top();
stack.pop();
r = n->right;
}
}
return res;
}
void BST::InOrder(TreeNode* r,std::vector<int>& res){
if(!r) return;
InOrder(r->left,res);
res.push_back(r->val);
InOrder(r->right,res);
}
void BST::InOrder(std::vector<int>& res){
if(!root) return;
InOrder(root->left,res);
res.push_back(root->val);
InOrder(root->right,res);
}
std::vector<int> BST::InOrder(){
std::vector<int> res;
std::stack<TreeNode*> stack;
TreeNode* r = root;
while(r || !stack.empty() ){
while(r){
stack.push(r);
r = r->left;
}
if(!stack.empty()){
auto n = stack.top();
stack.pop();
res.push_back(n->val);
r = n->right;
}
}
return res;
}
void BST::PostOrder(TreeNode* r,std::vector<int>& res){
if(!r) return;
PostOrder(r->left,res);
PostOrder(r->right,res);
res.push_back(r->val);
}
void BST::PostOrder(std::vector<int>& res){
if(!root) return;
PostOrder(root->left,res);
PostOrder(root->right,res);
res.push_back(root->val);
}
std::vector<int> BST::PostOrder(){
std::vector<int> res;
std::stack<std::pair<TreeNode*,bool>> stack;
TreeNode* r = root;
while(r || !stack.empty() ){
while(r){
stack.push(std::make_pair(r,false));
r = r->left;
}
if(!stack.empty()){
auto& n = stack.top();
if(n.second || !n.first->right){
stack.pop();
res.push_back(n.first->val);
}else{
n.second = true;
r = n.first->right;
}
}
}
return res;
}
std::vector<std::vector<int>> BST::LevelOrder(){
std::vector<std::vector<int>> res;
if(!root)return res;
std::queue<std::pair<TreeNode*,int>> que;
que.push(std::make_pair(root,0));
std::vector<int> one_level;
int last = 0;
while(!que.empty()){
auto& node = que.front();
if(node.second != last){
res.emplace_back(std::move(one_level));
last = node.second;
}
one_level.push_back(node.first->val);
if(node.first->left)
que.push(std::make_pair(node.first->left,node.second+1));
if(node.first->right)
que.push(std::make_pair(node.first->right,node.second+1));
que.pop();
}
res.emplace_back(std::move(one_level));
return res;
}