二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode == null){
return null;
}
if(pNode.right != null){
pNode = pNode.right;
while(pNode.left != null){
pNode = pNode.left;
}
return pNode;
}
while(pNode.next != null){
if(pNode.next.left == pNode){
return pNode.next;
}
pNode = pNode.next;
}
return null;
}
}
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* node)
{
if(node==NULL) return NULL;
if(node->right!=NULL){ //如果有右子树,则找右子树的最左节点
node = node->right;
while(node->left!=NULL) node = node->left;
return node;
}
while(node->next!=NULL){ //没右子树,则找第一个当前节点是父节点左孩子的节点
if(node->next->left==node) return node->next;
node = node->next;
}
return NULL; //退到了根节点仍没找到,则返回null
}
};
对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot == null) return true;
return isSame(pRoot.left,pRoot.right);
}
boolean isSame(TreeNode r1,TreeNode r2){
if(r1 == null && r2 == null)
return true;
if(r1 == null || r2 == null)
return false;
if(r1.val != r2.val)
return false;
return isSame(r1.left,r2.right) && isSame(r1.right,r2.left);
}
}
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
if(pRoot == NULL)
return true;
return isSame(pRoot->left,pRoot->right);
}
bool isSame(TreeNode* r1,TreeNode* r2){
if(r1 == NULL && r2 == NULL) return true;
if(r1 == NULL || r2 == NULL) return false;
if(r1->val != r2->val)
return false;
return isSame(r1->left,r2->right) && isSame(r1->right,r2->left);
}
};
之字型打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
*/
/**
* 大家的实现很多都是将每层的数据存进ArrayList中,偶数层时进行reverse操作,
* 在海量数据时,这样效率太低了。
* (我有一次面试,算法考的就是之字形打印二叉树,用了reverse,
* 直接被鄙视了,面试官说海量数据时效率根本就不行。)
*
* 下面的实现:不必将每层的数据存进ArrayList中,偶数层时进行reverse操作,直接按打印顺序存入
* 思路:利用Java中的LinkedList的底层实现是双向链表的特点。
* 1)可用做队列,实现树的层次遍历
* 2)可双向遍历,奇数层时从前向后遍历,偶数层时从后向前遍历
*/
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
if (pRoot == null) {
return ret;
}
ArrayList<Integer> list = new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>();
queue.addLast(null);//层分隔符
queue.addLast(pRoot);
boolean leftToRight = true;
while (queue.size() != 1) {
TreeNode node = queue.removeFirst();
if (node == null) {//到达层分隔符
Iterator<TreeNode> iter = null;
if (leftToRight) {
iter = queue.iterator();//从前往后遍历
} else {
iter = queue.descendingIterator();//从后往前遍历
}
leftToRight = !leftToRight;
while (iter.hasNext()) {
TreeNode temp = (TreeNode)iter.next();
list.add(temp.val);
}
ret.add(new ArrayList<Integer>(list));
list.clear();
queue.addLast(null);//添加层分隔符
continue;//一定要continue
}
if (node.left != null) {
queue.addLast(node.left);
}
if (node.right != null) {
queue.addLast(node.right);
}
}
return ret;
}
}
// public class Solution {
// private ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
// public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
// if(pRoot == null) return result;
// ArrayList<TreeNode> parent = new ArrayList<>();
// parent.add(pRoot);
// printline(parent, 0);
// return result;
// }
// // 树的的结构一般使用的都是递归算来实现的
// public void printline(ArrayList<TreeNode> nodes, int tim){
// if(nodes.size() == 0 || nodes == null) return;
// ArrayList<TreeNode> res = new ArrayList<>();
// ArrayList<Integer> list = new ArrayList<>();
// TreeNode temp;
// for(int i=nodes.size()-1; i>=0; i--){
// temp = nodes.get(i);
// list.add(temp.val);
// if(tim % 2 == 0){
// if(temp.left != null) res.add(temp.left);
// if(temp.right != null) res.add(temp.right);
// }else{
// if(temp.right != null) res.add(temp.right);
// if(temp.left != null) res.add(temp.left);
// }
// }
// result.add(list);
// printline(res, tim+1);
// }
// }
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>> res;
if(!pRoot)return res;
queue<TreeNode*> que; //建立个单向队列,用于存放节点
bool flag=false; //判断是否为偶数行,flag=false代表奇数行,flag=true代表偶数行
que.push(pRoot);
while(que.size()>0){
vector<int> vec; //行容器,用于存入当前行输出的结果
int len=que.size();
for(int i=0;i<len;i++){
TreeNode* tmp=que.front();
vec.push_back(tmp->val);
que.pop();
if(tmp->left)que.push(tmp->left);
if(tmp->right)que.push(tmp->right);
}
if(flag) reverse(vec.begin(),vec.end()); //是偶数行就反转顺序
flag=!flag; //改变flag的值
res.push_back(vec);
}
return res;
}
};
层次遍历
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
ArrayList<Integer> list = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
TreeNode temp;
if(pRoot == null){
return result;
}
queue.offer(pRoot);
int start = 0, end = 1;
while(!queue.isEmpty()){
temp = queue.poll();
list.add(temp.val);
start++;
if(temp.left != null){
queue.offer(temp.left);
}
if(temp.right != null){
queue.offer(temp.right);
}
if(start ==end){
start = 0;
end = queue.size();
result.add(list);
list = new ArrayList<>();
}
}
return result;
}
}
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > vec;
if(pRoot == NULL) return vec;
queue<TreeNode*> q;
q.push(pRoot);
while(!q.empty())
{
int lo = 0, hi = q.size();
vector<int> c;
while(lo++ < hi)
{
TreeNode *t = q.front();
q.pop();
c.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
vec.push_back(c);
}
return vec;
}
};
序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树
import java.lang.Integer;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
//使用前序遍历来序列化,遇到null就添加#!,遇到数值就添加!
String Serialize(TreeNode root) {
if(root==null)
return "";
return helpSerialize(root,new StringBuilder()).toString();
}
private StringBuilder helpSerialize(TreeNode node,StringBuilder sb){
if(node==null)
return sb;
sb.append(node.val).append("!");
if(node.left!=null){
helpSerialize(node.left,sb);
}
else{
sb.append("#!");
}
if(node.right!=null){
helpSerialize(node.right,sb);
}
else{
sb.append("#!");
}
return sb;
}
//1!2!4!#!#!5!#!#!3!6!#!#!7!#!#!
TreeNode Deserialize(String str) {
if(str==null || str.length()==0){
return null;
}
String[] strs=str.split("!");
return helpDeserialize(strs);
}
private int index=0;
//如果遇到了#表示,知道左边结束了,要开始建立右边了,如果再次遇到了#,表示当前整个左边要结束了要开始右子树
//124##5##36##7##
//先将1建立为根节点
//然后建立左子树,2是这个1的左子节点,4是2的左子节点,1左——》2左-》4
//然后建立4的左子节点的时候,遇到了#退出建立左子节点的递归,然后来到了建立4的右子树节点,又遇到了#号,退出了4的右子树节点递归
//这样的话,建立4节点的左右子树都退出了,也退出4的递归,到2的右子树建立,然后字符串到5,建立5节点,2的右-》5(左右退出,和4上面的退出是相同得)
//然后2的右子树递归退出,到1的右子树建立,建立3为1的右子树节点,然后建立3的左子树节点6,然后遇到##,同上面一样,退出6的左子树节点建立,退出6的右子树节点建立
//到3的右子树节点7,然后7建立左右子树遇到##,也同样退出
private TreeNode helpDeserialize(String[] str){
if(str[index].equals("#")){
index++;
return null;
}
TreeNode root = new TreeNode(Integer.valueOf(str[index]));
index++;
root.left=helpDeserialize(str);
root.right=helpDeserialize(str);
return root;
}
}
class Solution {
public:
//1.将二叉树转化为字符串序列
//例如:树:10,6,4,14,12,16
//序列化后:00!60!40!#!#!#!14!12!#!#!16!#!#!
vector<int>s;
void Serializevector(TreeNode *root)
{
if(root==nullptr)//如果根节点为空,直接存入#和!
{
s.push_back('#');//#表示空节点
s.push_back('!');//!表示一个节点存放完毕
return;
}
vector<int>temp;
//首先将根节点存入容器temp中,value组成的序列为除以10的模,
int value=root->val;
while(value!=0)
{
temp.push_back(value%10);
// temp.push_back(value);
value=value/10;
}
for (int i = temp.size() - 1; i >= 0 ; i--)
{
s.push_back( temp[i]);
}
s.push_back('!');//根节点存完之后输入!表示该节点存放完毕
Serialize(root->left) ;
Serialize(root->right);
}
char* Serialize(TreeNode *root) {
Serializevector(root);//分别递归左右节点,
char*result=new char[s.size()];//构建数的节点大小的空间
for (int i=0;i<s.size();i++)
{
result[i]= (char) s[i];//依次存入到最终结果中
}
return result;
}
//2.反序列化二叉树,将字符串转化成树
//序列化为://序列化后:00!60!40!#!#!#!14!12!#!#!16!#!#!
//反序列化:**str指向'00!'*str从0到‘\0’
TreeNode* Deserialize(char **str)
{
if(**str=='#') //如果字符串序列为#!,树某一节点为空
{
(*str) += 2;
return NULL;
}
int value=0;
while (**str!= '!')//若字符串未遍历到字符串末尾,
{
value *= 10;
value += (int)**str;
(*str)++;
}
TreeNode*root =new TreeNode(value);
//序列化后:'00!60!40!#!#!#!14!12!#!#!16!#!#!\0'
//当遍历到'\0'时,树的所有节点都遍历完了,返回根节点
if (**str=='\0')//
return root;
else
(*str)++;
root->left=Deserialize(str);//遍历左子树和右子树
root->right=Deserialize(str);
return root;
}
TreeNode* Deserialize(char *str) {
return Deserialize(&str);
}
};