二叉树
1.二叉树结构体定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
类定义
class BinaryTree
{
public:
static TreeNode* head;
}
2.反序列化与序列化
2.1 反序列化
void decode(string& str)//反序列化
{
if (data[0] == 'n')
{
head=NULL;
return;
}
//切片压入容器
vector<string> nums;
int i = -1, j = -1;
while (true)
{
i = data.find(",", i + 1);
if (i == string::npos)
{
nums.push_back(data.substr(j + 1, data.size() - j));
break;
}
nums.push_back(data.substr(j + 1, i - j));
j = i;
}
TreeNode* root = new TreeNode(stoi(nums[0]));
if (nums.size() == 1)
{
head = root;
return;
}
i = 1;//从第二个开始算起
queue<TreeNode*> myqueue = {};
myqueue.push(root);
while (!myqueue.empty())
{
TreeNode* cur = myqueue.front();
myqueue.pop();
if (nums[i][0] != 'n')
{
cur->left = new TreeNode(stoi(nums[i]));
myqueue.push(root->left);
}
if (++i == nums.size()) break;
if (nums[i][0] != 'n')
{
cur->right = new TreeNode(stoi(nums[i]));
myqueue.push(root->right);
}
if (++i == nums.size()) break;
}
head = root;
return;
}
2.2 序列化
string& serialize()
{
vector<int> vec = {};
if (head == NULL)
{
return "null";
}
string str = {};
queue<TreeNode*> myqueue = {};
myqueue.push(head);
while (!myqueue.empty())
{
TreeNode* cur = myqueue.front();
myqueue.pop();
if (cur)
{
str += to_string(cur->val) + ',';
myqueue.push(cur->left);
myqueue.push(cur->right);
}
else
{
str += "null,";
}
}
str.pop_back();
int pos = str.find_last_of("0123456789");
str = str.substr(0, pos + 1);
return str;
}
2.3 层序遍历
void Pirnt()
{
if (head == NULL) return;
queue<TreeNode*> myqueue;
TreeNode* cur = head;
myqueue.push(cur);
while (!myqueue.empty())
{
int size = myqueue.size();
for (int i = 0; i < size; i++)
{
cur = myqueue.front();
myqueue.pop();
cout << cur->val<<"\t";
if (cur->left)myqueue.push(cur->left);
if (cur->right)myqueue.push(cur->right);
}
cout << endl;
}
}
2.4 测试
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
//反序列初始化测试
bt.decode("5,2,3,null,null,2,4,3,1");
//按行打印
bt.Pirnt();
//序列化测试
string str = bt.serialize();
cout << str << endl;
system("pause");
}
结果
3. 遍历
3.1 前序及测试
递归
void preRecerse(TreeNode* cur = head)
{
if (NULL == cur)
{
return;
}
cout << cur->val << "\t";
preRecerse(cur->left);
preRecerse(cur->right);
}
迭代
void PreTraverse()
{
if (head == NULL) return;
stack<TreeNode*> mystack;
TreeNode* p = head;
mystack.push(p);
while (!mystack.empty()) {
p = mystack.top();
mystack.pop();
cout << p->val << "\t";
if (p->right) mystack.push(p->right);
if (p->left) mystack.push(p->left);
}
cout << endl;
return;
}
测试
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
bt.decode("5,2,3,null,null,2,4,3,1");
bt.preRecerse();
cout << endl;
bt.PreTraverse();
system("pause");
}
3.2 中序及测试
递归
void miRecurse(TreeNode* cur = head)
{
if (NULL == cur)
{
return;
}
miRecurse(cur->left);
cout << cur->val << "\t";
miRecurse(cur->right);
}
迭代
void midTraverse()
{
if (NULL == head)return;
TreeNode* p = head;
stack<TreeNode*> mystack;
while (!mystack.empty() || NULL != p)
//如果没遍历完或者本身有数
{
if (NULL != p) //如果有数,那么继续往左边找
{
mystack.push(p);
p = p->left;
}
else //如果没数了,就往上取根对根操作,取完指针指向右边
//如果接下来右边有数,那么继续往左边取
//如果没数了,那么再往上取,取根的根,以此类推
{
p = mystack.top();
mystack.pop();
cout << p->val << "\t";
p = p->right;
}
}
}
测试
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
bt.decode("1,2,3,null,null,4,5,6,7");
bt.miRecurse();
cout << endl;
bt.midTraverse();
system("pause");
}
3.3 后序及测试
递归
void backRecurse(TreeNode* cur = head)
{
if (NULL == cur)
{
return;
}
backRecurse(cur->left);
backRecurse(cur->right);
cout << cur->val << "\t";
}
迭代
void backTraverse()
{
vector<int> myvec;
if (head == NULL) return;
stack<TreeNode*> mystack;
TreeNode* p = head;
mystack.push(p);
while (!mystack.empty()) {
p = mystack.top();
mystack.pop();
myvec.push_back(p->val);
if (p->right) mystack.push(p->left);
if (p->left) mystack.push(p->right);
}
for (auto it = myvec.rbegin(); it != myvec.rend(); it++)
{
cout << *it << "\t";
}
cout << endl;
}
测试
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
bt.decode("1,2,3,null,null,4,5,6,7");
bt.backRecurse();
cout << endl;
bt.backTraverse();
system("pause");
}
4.反向构造
4.1 由中序和前序反向构造
void constractByPreAndMid(vector<int>& preorder, vector<int>& inorder)
{
head = myOrder(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size());
}
private:
TreeNode* myOrder(vector<int>& preorder, int l1, int r1, vector<int>inorder, int l2, int r2)
{
if (r1 < l1) return NULL;
TreeNode* root = new TreeNode(preorder[l1]);
int mid = l2;
while (inorder[mid] != root->val) ++mid;
root->left = myOrder(preorder, l1 + 1, l1 + mid - l2, inorder, l2, mid - 1);
root->right = myOrder(preorder, l1 + mid - l2 + 1, r1, inorder, mid + 1, r2);
return root;
}
测试
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
vector<int> preorder = { 3,9,20,15,7 };
vector<int> inorder = { 9,3,15,20,7 };
bt.constractByPreAndMid(preorder, inorder);
bt.Pirnt();
system("pause");
}
4.2 由中序和后序反向构造
void constractByPostAndMid(vector<int>& postorder, vector<int>& inorder)
{
head = myOrder2(postorder, 0, postorder.size() - 1, inorder, 0, inorder.size()-1);
}
private:
TreeNode* myOrder2(vector<int>& postorder, int l1, int r1, vector<int>inorder, int l2, int r2)
{
if (r1 < l1) return NULL;
TreeNode* root = new TreeNode(postorder[r1]);
int mid = l2;
while (inorder[mid] != root->val) ++mid;
root->left = myOrder2(postorder, l1, l1 + mid - l2-1, inorder, l2, mid - 1);
root->right = myOrder2(postorder, l1 + mid - l2 , r1-1, inorder, mid + 1, r2);
return root;
}
测试代码
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
vector<int> preorder = { 3,9,20,15,7 };
vector<int> inorder = { 9,3,15,20,7 };
vector<int> postorder = { 9,15,7,20,3 };
bt.constractByPostAndMid(postorder, inorder);
bt.Pirnt();
bt.constractByPreAndMid(preorder, inorder);
bt.Pirnt();
system("pause");
}
5.其他常见算法
5.1 求最大深度
int maxDepth(TreeNode* root=head) {
if (root == NULL)
{
return 0;
}
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
测试
#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main()
{
BinaryTree bt = {};
bt.decode("1,2,3,null,null,4,5,6,7");
bt.Pirnt();
cout << bt.maxDepth() << endl;
system("pause");
}
这里也可以用层序遍历的方式求最大值
5.3 判断是否对称
递归
bool isSymmetric(TreeNode* root)
{
if (root == NULL)
{
return true;
}
return check(root->left, root->right);
}
private:
bool check(TreeNode* left, TreeNode* right)
{
if (left == NULL && right == NULL)
{
return true;
}
else if (left == NULL || right == NULL || left->val != right->val)
{
return false;
}
else //只剩下左右值相等,于是继续向下找
{
return check(left->left, right->right) && check(left->right, right->left);
}
}
迭代
bool isSymmetric2(TreeNode* root)
{
if (root == NULL || (root->left == NULL && root->right == NULL))
{
return true;
}
queue<TreeNode*> myqueue = {};//每次都初始化为空
myqueue.push(root->left);
myqueue.push(root->right);
while (!myqueue.empty())
{
TreeNode* aa = myqueue.front();
myqueue.pop();
TreeNode* bb = myqueue.front();
myqueue.pop();
if (aa == NULL && bb == NULL) continue;
else if (aa == NULL || bb == NULL || aa->val != bb->val)
{
return false;
}
myqueue.push(aa->left);
myqueue.push(bb->right);
myqueue.push(aa->right);
myqueue.push(bb->left);
}
return true;
}
5.4 判断是否存在路径和
递归
bool hasPathSum(int targetSum, TreeNode* root = head) {
if (root == NULL)
{
return false;
}
else if (root->left == NULL && root->right == NULL && targetSum == root->val)
{
return true;
}
else
{
return hasPathSum(targetSum - root->val, root->left) || hasPathSum(targetSum - root->val, root->right);
}
}
迭代
bool hasPathSum2(int targetSum,TreeNode* root = head) {
if (root == NULL)
{
return false;
}
root->val = targetSum - root->val;
queue<TreeNode*> q = {};
q.push(root);
while (!q.empty())
{
TreeNode* Node = q.front();
q.pop();
if (Node->left == NULL && Node->right == NULL && Node->val == 0)
{
return true;
}
if (Node->left)
{
Node->left->val = Node->val - Node->left->val;
q.push(Node->left);
}
if (Node->right)
{
Node->right->val = Node->val - Node->right->val;
q.push(Node->right);
}
}
return false;
}
5.5 寻找最小公共祖先
TreeNode* lowestCommonAncestor(TreeNode* p, TreeNode* q, TreeNode* root=head) {
if (root == NULL)
{
return root;//空的找个屁,既然有那肯定是根
}
if (root == p || root == q)
{
return root;//既然肯定有,而且有一个就是根,那么直接返回根,
}
//如果上面都不是,那么肯定在左右两边
//根节点往下一层挪,直到根两个中一个相等为止
TreeNode* left = lowestCommonAncestor( p, q, root->left);
TreeNode* right = lowestCommonAncestor( p, q, root->right);
//有三种情况,如果同在左边,那么肯定left不是空,右边为空
//如果同在右边,那么right不是空,左边为空
//如果两边都不为空。那么肯定是根节点
if (left && right) return root;
return left ? left : right;
}