二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
找出各种情况:
1、右孩子存在。寻找右子树的最左节点。
2、右孩子不存在,该节点为父节点的左子树,返回父节点。
3、右孩子不存在,该节点为父节点的右子树。若在右子树,则其父节点也是右孩子节点,跳出结束;若在左子树,则父节点为左孩子,追溯返回根节点。
4、右孩子不存在,该节点为根节点,返回nullptr。
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(!pNode) return pNode;
if(pNode->right){
pNode=pNode->right;
while(pNode->left){
pNode=pNode->left;
}
return pNode;
}
else{
//root without next
if(!pNode->next) return nullptr;
if(pNode->next->left==pNode){//left
return pNode->next;
}
else{//right
TreeLinkNode *temp=pNode->next;//father node
if(temp->next){//not root
pNode=temp->next;
if(pNode->left==temp){
while(pNode->next){
pNode=pNode->next;
}
return pNode;
}
}
}
}
return nullptr;
}
};
对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
非递归实现:
1、进入根节点左子树,先序遍历,从左到右;进入根节点右子树,先序遍历,从右到左。
2、中间及时判断对应节点是否相等,节点的孩子存在情况。
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
if(!pRoot) return true;
stack<TreeNode*> st1,st2;
if(pRoot->left&&pRoot->right){
st1.push(pRoot->left);
st2.push(pRoot->right);
//左子树left father right
//右子树right father left
while((!st1.empty())&&(!st2.empty())){
TreeNode *cur1=st1.top(),*cur2=st2.top();
st1.pop();
st2.pop();
if(cur1->val!=cur2->val){
return false;
}
if(cur1->right&&cur2->left){
st1.push(cur1->right);
st2.push(cur2->left);
}
else if(cur1->right||cur2->left){
return false;
}
if(cur1->left&&cur2->right){
st1.push(cur1->left);
st2.push(cur2->right);
}
else if(cur1->left||cur2->right){
return false;
}
}
}
else if(pRoot->left||pRoot->right){
return false;
}
return true;
}
};
按之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
1、从做开始的时候先保存左孩子,再保存右孩子。下一层将读取从右开始,此时先保存右孩子,再保存左孩子。
2、下一层将从做到右。
3、记得将v及时clear
class Solution {
public:
//BFS
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>> res{};
if(!pRoot) return res;
stack<TreeNode*> st1,st2;
st1.push(pRoot);
while((!st1.empty())||(!st2.empty())){//exit only all empty
vector<int> v;
while(!st1.empty()){//st1 is not empty:left to right
TreeNode *cur=st1.top();
st1.pop();
v.push_back(cur->val);
if(cur->left){
st2.push(cur->left);
}
if(cur->right){
st2.push(cur->right);
}
}
res.push_back(v);
v.clear();
while(!st2.empty()){//st2 is not empty:right to left
TreeNode *cur=st2.top();
st2.pop();
v.push_back(cur->val);
if(cur->right){
st1.push(cur->right);
}
if(cur->left){
st1.push(cur->left);
}
}
if(!v.empty()) res.push_back(v);
}
return res;
}
};
把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
1、队列:queue,front()取头,pop()删除头。
2、从左到右放入队列,队列FIFO,下一层将也是从左到右读取。
3、对于多行保存,设置三个变量即可。
4、学会的新的写法。之前我还几个栈换来换去,看来不一定要用栈解决问题的。next可以不要,直接q.size()。
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
//BFS
vector<vector<int>> res{};
if(!pRoot) return res;
queue<TreeNode*> q;
q.push(pRoot);
int has{1},i{0},next{0};//本层节点数,迭代,下层节点数
while(!q.empty()){
vector<int> v;
for(next=0,i=0;i<has;++i){
TreeNode *cur=q.front();
q.pop();//删除头元素
v.push_back(cur->val);
if(cur->left){
q.push(cur->left);
++next;
}
if(cur->right){
q.push(cur->right);
++next;
}
}
has=next;
res.push_back(v);
}
return res;
}
};
序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
BFS:
1、层序遍历,将每个节点的孩子表示出来。
2、对于编码,val的表示,字符串表示在字符流中,在解码的时候我们要根据需求编写解码函数,string to int函数编写或调用。
3、对于内存,传输确定即可。在下面第二个改变程序体现。
4、反序列化,我们的一层节点数必定是2的幂。
注:
1、c_str()函数,将string转换为char ,要注意如果该string是某个函数局部变量,而我们要获取其char,这样我们要strcpy!
2、append()函数使用。
class Solution {
public:
char* Serialize(TreeNode *root) {
if(!root) return nullptr;
queue<TreeNode*> qNode;
qNode.push(root);
int has{1},i{0};
string res{""};
while(!qNode.empty()){
for(i=0;i<has;++i){
TreeNode *cur=qNode.front();
qNode.pop();
if(cur){
res+=to_string(cur->val)+',';
qNode.push(cur->left);
qNode.push(cur->right);
}
else res.append("#");
}
has=qNode.size();
}
int len=res.length();
char *cres=new char[len+1];//'\0'
strcpy(cres,res.c_str());//能够保存
return cres;
}
TreeNode* Deserialize(char *str) {
if(!str) return nullptr;
queue<TreeNode*> qNode;
char *cp=str;
TreeNode *root=new TreeNode(decode(cp));
++cp;
qNode.push(root);
int has{1};
while(*cp!='\0'&&(!qNode.empty())){
for( int i=0;i<has;++i){
TreeNode *cur=qNode.front();
qNode.pop();
if(*cp!='#'){
cur->left=new TreeNode(decode(cp));
qNode.push(cur->left);
}
++cp;
if(*cp!='#'){
cur->right=new TreeNode(decode(cp));
qNode.push(cur->right);
}
++cp;
}
has=qNode.size();
}
delete [] str;
return root;
}
private:
int decode(char* &cp){
int num{0};
while(*cp!=','){
num=10*num+*cp-48;
++cp;
}
return num;
}
};
既然是要传输数据,我们肯定确定了每次包的大小,还有,既然是字符流,我们尽量用char*,以除去结果转换的耗时,及缓存的使用。反序列化与解码函数相同。
此处使用strcpy()函数不易出错,因为本来就有字符串转换函数。
#define N 1024
class Solution {
public:
char* Serialize(TreeNode *root) {
if(!root) return nullptr;
queue<TreeNode*> qNode;
qNode.push(root);
int has{1},i{0};
char *cres=new char[N],*cp=cres;
while(!qNode.empty()){
for(i=0;i<has;++i){
TreeNode *cur=qNode.front();
qNode.pop();
if(cur){
string temp=to_string(cur->val)+",";
strcpy(cp,temp.c_str());
cp+=temp.length();
qNode.push(cur->left);
qNode.push(cur->right);
}
else{
*cp='#';
++cp;
}
}
has=qNode.size();
}
*cp='#';
return cres;
}