描述:
请判断一个二叉树是否是对称的(以根节点的中线为轴), 例如,如下的则是对称的:
方案1:
基于循环法进行树的广度优先遍历,左右子树分别单独遍历,并将节点保存到vector中. 对于左子树的各个层,我们总是先访问左侧的节点, 对于右子树的各个层,我们总是先访问右侧的节点。最后比较左右子树的vector中的元素是否对应相等.如果树是对称的,则必定相等。
缺点是: 需要额外的空间较多。首先,树的广度优先遍历使用了queue, 然后为了保存节点,使用了vector。
引申:对于左子树进行 深度优先遍历中的(根节点-左节点-右节点),
对于右子树进行 深度优先遍历中的(根节点-右节点-左节点)也可以。
方案2:
对上面方法改进一下:不借助额外的vector, 对根节点的左右子树同步进行广度优先遍历!一边遍历 一遍比较。
方案3:
基于递归的方法. 能否想到的关键是递归函数右两个入参,pLeft 和pRight。 juege_recusive(Node* leftNode, Node* rightNode)。
相似:
二叉树的镜像:https://blog.csdn.net/qq_35865125/article/details/79339200
代码:
#pragma once
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
class SysmetricTreeJudge
{
public:
struct Node {
Node(int v=0, Node* pLeft=nullptr, Node* pRight = nullptr):
val(v),
pL(pLeft),
pR(pRight){
}
int val;
Node* pL;
Node* pR;
};
//方案1: ---------------------------------------------------------------------
//基于循环法进行树的广度优先遍历,左右子树分别单独遍历,并将节点保存到vector中. 对于左子树的各个层,我们
//总是先访问左侧的节点, 对于右子树的各个层,我们总是先访问右侧的节点。最后比较左右子树的vector中
//的元素是否对应相等.如果树是对称的,则必定相等。
//缺点是: 需要额外的空间较多。首先,树的广度优先遍历使用了queue, 然后为了保存节点,使用了vector。
//引申: 对于左子树进行 深度优先遍历中的(根节点-左节点-右节点),
// 对于右子树进行 深度优先遍历中的(根节点-右节点-左节点)也可以。
bool judge_while(Node* root) {
if (!root)
return false;
Node* leftTree = root->pL;
Node* rightTree = root->pR;
vector<int> leftTreeVec;
vector<int> rightTreeVec;
queue<Node*> leftTreeQue;
queue<Node*> rightTreeQue;
leftTreeQue.push(leftTree);
while (!leftTreeQue.empty()) {
Node* p = leftTreeQue.front();
leftTreeQue.pop();
leftTreeVec.push_back(p->val);
if (p->pL) //从左向右访问同一层的节点
leftTreeQue.push(p->pL);
if (p->pR)
leftTreeQue.push(p->pR);
}
rightTreeQue.push(rightTree);
while (!rightTreeQue.empty()) {
Node* p = rightTreeQue.front();
rightTreeQue.front();
rightTreeQue.pop();
rightTreeVec.push_back(p->val);
if (p->pR) // 从右向左访问同一层的节点
rightTreeQue.push(p->pR);
if (p->pL)
rightTreeQue.push(p->pL);
}
int leftTreeSize = leftTreeVec.size();
int rightTreeSize = rightTreeVec.size();
if (leftTreeSize != rightTreeSize) {
return false;
}
for (int idx = 0; idx < leftTreeSize; ++idx) {
if (leftTreeVec[idx] != rightTreeVec[idx])
return false;
}
return true;
}
//方案2: ---------------------------------------------------------------------
//对上面方法改进一下:不借助额外的vector, 对根节点的左右子树同步进行广度优先遍历!
//一边遍历 一遍比较。
bool judge_while_syn(Node* root) {
if (!root)
return false;
Node* leftTree = root->pL;
Node* rightTree = root->pR;
vector<int> leftTreeVec;
vector<int> rightTreeVec;
queue<Node*> leftTreeQue;
queue<Node*> rightTreeQue;
leftTreeQue.push(leftTree);
rightTreeQue.push(rightTree);
while (!leftTreeQue.empty() || !rightTreeQue.empty()) {
if (leftTreeQue.size() != rightTreeQue.size())
return false;
Node* pLeftTree = leftTreeQue.front();
leftTreeQue.pop();
Node* pRightTree = rightTreeQue.front();
rightTreeQue.pop();
if (pLeftTree->val != pRightTree->val)
return false;
if (pLeftTree->pL) //对于左子树 从左向右访问同一层的节点
leftTreeQue.push(pLeftTree->pL);
if (pLeftTree->pR)
leftTreeQue.push(pLeftTree->pR);
if (pRightTree->pR) //对于右子树 从右向左访问同一层的节点
rightTreeQue.push(pRightTree->pR);
if (pRightTree->pL)
rightTreeQue.push(pRightTree->pL);
}
while (!rightTreeQue.empty()) {
Node* p = rightTreeQue.front();
rightTreeQue.front();
rightTreeQue.pop();
rightTreeVec.push_back(p->val);
if (p->pR) // 从右向左访问同一层的节点
rightTreeQue.push(p->pR);
if (p->pL)
rightTreeQue.push(p->pL);
}
int leftTreeSize = leftTreeVec.size();
int rightTreeSize = rightTreeVec.size();
if (leftTreeSize != rightTreeSize) {
return false;
}
for (int idx = 0; idx < leftTreeSize; ++idx) {
if (leftTreeVec[idx] != rightTreeVec[idx])
return false;
}
return true;
}
//方案3: ---------------------------------------------------------------------
//基于递归的方法.
bool juege_recusive_wrapper(Node* root) {
if (!root)
return false;
return juege_recusive(root->pL, root->pR);
}
bool juege_recusive(Node* leftNode, Node* rightNode) {
if (!leftNode && !rightNode) {
return true;
}
if (leftNode && rightNode) {
if (leftNode->val != rightNode->val) {
return false;
}
//leftNode的左子树与rightNode的右子树进行比较
//leftNode的右子树与rightNode的左子树进行比较:
return juege_recusive(leftNode->pL, rightNode->pR) && juege_recusive(leftNode->pR, rightNode->pL);
}
else {
return false;
}
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void Test_judge_while() {
Node* root = new Node(0);
root->pL = new Node(1);
root->pR = new Node(1);
root->pL->pL = new Node(11);
root->pL->pR = new Node(12);
root->pR->pL = new Node(12);
root->pR->pR = new Node(11);
root->pR->pL->pL = new Node(33);
bool result = judge_while(root);
return;
}
void Test_judge_while_syn() {
Node* root = new Node(0);
root->pL = new Node(1);
root->pR = new Node(1);
root->pL->pL = new Node(11);
root->pL->pR = new Node(12);
root->pR->pL = new Node(12);
root->pR->pR = new Node(11);
//root->pR->pL->pL = new Node(33);
bool result = judge_while_syn(root);
return;
}
void Test_juege_recusive() {
Node* root = new Node(0);
root->pL = new Node(1);
root->pR = new Node(1);
root->pL->pL = new Node(11);
root->pL->pR = new Node(12);
root->pR->pL = new Node(12);
root->pR->pR = new Node(11);
//root->pR->pL->pL = new Node(33);
bool res = juege_recusive_wrapper(root);
return;
}
};
void main() {
SysmetricTreeJudge obj;
obj.Test_judge_while();
obj.Test_judge_while_syn();
obj.Test_juege_recusive();
}
风中的蒲公英:https://music.163.com/#/song?id=28160231&market=baiduqk