1.求一颗二叉树是否平衡,
typedef struct node
{
struct node*left;
struct node*right;
int val;
}node;
int maxDepth(node*root)
{
if(root==NULL)
return 0;
return 1+max(maxDepth(root->left),maxDepth(root->right));
}
int minDepth(node*root)
{
if(root==NULL)
{
return 0;
}
return 1+min(minDepth(root->left),minDepth(root->right));
}
bool isBanlancde(node*root)
{
if(root==NULL)
return true;
return (maxDepth(root) -minDepth(root)<=1);
}
2.求二叉树的深度
1
2 3
第一次,遍历1,遍历2,遍历3
第二次 遍历2:2的左节点为NULL,返回0,遍历2的右节点为空 ,返回0,所以遍历2的函数中,2的左右都返回0,return 1;同理在遍历1的时候,2返回了返回1,接下来执行遍历1的右节点,遍历3,遍历3也返回1,所以,遍历1的函数中,遍历2和遍历3都返回了1,所以最后是2.也就是遍历root的结果
如果3的下面还有,比如3返回1,所以2返回0,3返回1,那就不一样了,最后要多加一个1。因为又多了一层返回。
int treeDepth(node*root )
{
if(root==NULL)
{
return 0;
}
int left=treeDepth(root->left);
int rigth=treeDepth(root->rigth);
return left>right?left+1:right+1;
}
1
2 3
4 5 6 根据这个结构,进行体会。
总之就是要把每一层的节点都加入到while(循环里)的一次循环中,也就是cur记录本层循环树,那么我这层的几个节点的孩子
就属于同一层,即使是3个的话,也会while(cur),此时的cur已经被加成3了。所以循环完毕,才会看队列中是否有下一层的东西。
1
2 3
4 5
#include <queue>
int treeDepth(node*root)
{
if(root==NULL)
return 0;
queue<node*> _queue;
int nodeNum=0;记录队列节点数
_queue.push(root);
int cur=1;
int level = 0;
while(!_queue.empty())
{
while(cur)//把这一层的都给循环完,再循环下一层,这应该是广度优先遍历。
{
node*tmp = _queue.front();
_queue.pop();
cur--;
if(tmp->left)
{
_queue.push(tmp->left);
nodeNum++;
}
if(tmp->right)
{
_queue.push(tmp->right);
nodeNum++;
}
}
cur=nodeNum;//记录每个节点下的孩子,然后循环全部孩子节点
nodeNum=0;
level++;
}
return level;
}
3.求二叉树叶子节点到根节点的最小高度
1
2 3
4
假如求最小高度,也就是1这个树
的最小高度,他一定是1+2和3的最小高度中的更小的一个,然后以此循环,代码就是上面的简单的代码
。这样很好理解。
1
2 3
4 5
6
4节点的深度为1
5节点的深度为2
所以2节点的深度为1+1(最小的)
3节点的深度为1
所以min(1,1+1) +1 ,就是2,也就是3这个节点。
if循环判断的逻辑应该这么思考:
1)6的左右子树都为空,算上本身6的节点,所以返回1
2)而5,左子树为空,高度为0,右子树6的高度为1,所以只有右子树,高度为(右子树的高度+1)=2,所以求得的最小高度是2(也是5的高度,谈不上最小高度)
同样右子树为空,左不为空,
3)而2这个节点,它的左右子树都有,也就是非叶子节点,所以就得比较了,求出最小的那个,(左右子树高度最小那个+2本身的高度1)
以上就是4个循环条件。
对于空节点,应该返回的是0,因为相当于本身这个节点的左右子树的高度都为0,而最后循环确实left==0&&right==0,考虑的就是本身这个节点的高度1,所以返回1
int depth(node*root)
{
if(root==NULL)
{
return 0;
}
int left=depth(root->left);
int right=depth(root->right);
if(left==0&&right==0)//说明是叶子节点,他的左右节点为空,算上叶子本身的高度,为1,所以返回1
{
return 1;
}
else if(left==0)//只有右子树,此时这个节点的高度就是这个节点root的root->right的right+1;
{
return 1+right;
}
else if(right==0)//只有左子树,那么这个节点的高度就是左节点的高度+1
{
return 1+left;
}
else //如果这个树的左右节点高度不相等,那么取最小值
{
return min(left,right)+1;
}
}
typedef struct tree
{
struct tree*left, *right;
int val;
}tree;
//判断一颗二叉树是否为平衡二叉树
bool isBanlancdeBinary(node*root)
{
if(root==NULL)
return true;
int leftDepth=treeDepth(root->left);
int rightDepth=treeDepth(root->right);
int diff=leftDepth-rightDepth;
if(diff>1||diff<-1)
{
return false;//只要有一个节点的左右高度差,不满足,直接返回
}
return isBanlancdeBinary(root->left)&&isBanlancdeBinary(root->right);
}//当最后一个节点判断完毕的时候,如果左子树平衡,
//方法2:
bool isBalanceBinaryTree(tree*root, int*depth)
{
if (root == NULL)
{
*depth = 0;
return true;
}
int left;
int right;
if (isBalanceBinaryTree(root->left, &left) && isBalanceBinaryTree(root->right, &right))
{
int diff = left - right;
if (diff <= 1 && diff >= -1)
{
//return left > right ? left + 1 : right + 1;
*depth = left > right ? left + 1 : right + 1;
return true;
}
}
return false;
}
//方法3
/*
1
2 3
4
5
1 2(-1) 3 1的左子树不平衡,diff=2;所以直接返回-1,调用1,返回-1,所以不是AVL
2 4(2) null(0) return -1(只要有一个return -1,就证明是不平衡的了.一直向函数调用最开始进行传递
4 5(1) null(0) return 2
5 null(0) null(0) return 1;//return返回的都是当前节点的深度
*/
int checkheight(tree*root)
{
if (root == NULL)
{
return 0;
}
int left = checkheight(root->left);
if (left == -1)
return -1;
int right = checkheight(root->right);
if (right == -1)
return -1;
int diff = left - right;
if (diff <= 1 && diff >= -1)
{
return max(left, right) + 1;
}
else
{
return -1;
}
}
bool isAVL(tree*root)
{
if (checkheight(root) == -1)
{
return false;
}
else
{
return true;
}
}
要学会思考和推演,用简单的例子来推演出全局的.
4 将一颗二叉树按照先序遍历顺序展开成一个单链表。(leetcode)
/*
1
2 3
4 5
1 2 4 5 3
*/
#include <stack>
class solu
{
public:
void flattern(tree*root)//root还是指向根
{
if (root == NULL)
return;
vector<tree*> vec;
preOrder(root, vec);
tree*tmp = root;//tmp也就是vec的第一个节点vec[0],也就是根节点
for (int i = 1; i < vec.size(); i++)
{
tmp->left = NULL;
tmp->right = vec[i];//第一次指向第二个节点
tmp = tmp->right;
}
tmp->left = tmp->right = NULL;//tmp指向了最后一个节点,让最后一个节点的left和right为空
}
void preOrder(tree*root, vector<tree*> &vec)
{
stack<tree*> s;
while (root!=NULL||s.size()>0)
{
while (root!=NULL)
{
s.push(root);
vec.push_back(root);
root = root->left;
}
if (s.size() > 0)
{
tree*tmp = s.top();
s.pop();
root = tmp->right;
}
}
}
void createTree(tree*root)
{
int i;
cin >> i;
if (i != 0)
{
root = new tree(i);
if (root == NULL)
return;
createTree(root->left);
createTree(root->right);
}
}
};
1 1left 1rigth
1left 2 2left 2rigth
2left 3 3left 3right
3left 0 return
3right 4 return
0 0
5
0 0
6
0 0
*/
//对的输入方式
//1 2 3 0 4 0 0 5 0 0 6 0 0 ,输入注意一下,有时候一个节点得需要输入2个0
将root的右子树中的链接到左子树的最后一个结点,然后将整个左子树作为根的右子树,此时,根只有一颗右子树,root->left=NULL。然后将root移到右子树第一个节点,此时是以右子树为根节点的子树,重复上面的过程。直到为NULL。
void flattern1(tree* root)
{
while (root)
{
if (root->left)//得加判断
{
tree*pre = root->left;
while (pre->right)
{
pre = pre->right;
}
pre->right = root->right;
root->right = root->left;
root->left = NULL;
}
root = root->right;
}
}
void main()
{
//printf("13344\n");
tree*root;
solu s;
vector<tree*> vec;
s.createTree(root);
#if 0
s.preOrder(root, vec);
s.flattern(root);
while (root)
{
printf("%d\n",root->val);
root = root->right;
}
#endif
#if 1
flattern1(root);
while (root)
{
printf("%d\n", root->val);
root = root->right;
}
#endif
}
//二叉树的后续遍历
struct node
{
struct node*left;
struct node*right;
int val;
node(int _val) :val(_val), left(NULL), right(NULL)
{
}
};
#include<stack>
void postOrder(node*root)
{
if (root == NULL)
return;
std::stack<node*>tmp;
std::stack<node*>output;
while (root!=NULL||!tmp.empty())
{
if (root != NULL)
{
tmp.push(root);
output.push(root);
root = root->right;
}
else
{
node*t = tmp.top();
tmp.pop();
root = t->left;
}
}
while (output.size()>0)
{
node*result = output.top();
printf("%d\n", result->val);
output.pop();
}
}
//判断是否为二叉树的子结构
//写对了,分析问题的方式,就是从头开始想,一个二叉树,和一个子二叉树,然后第一次开始判断,根是否为空,或者子树是否为空,如果为空,说明2个中的任意
//一个还没有在issub函数return true,而已经为空了,所以就return false.
//判断是否为二叉树的子结构
//当确定了root节点中的一个点跟sroot是一样的,就开始遍历root下每一个点
bool isSub(tree*root, tree*sroot)
{
if (sroot == NULL)
{
return true;
}
if (root == NULL)
{
return false;
}
if (root->val != root->val) //
{
return false;
}
return isSub(root->left, sroot) && isSub(root->right, sroot);
}
bool isSubTree(tree*root, tree*sroot)
{
if (root == NULL || sroot == NULL)
return false;
bool result = false;
if (root->val == sroot->val)//第一个判断根节点是否和子树根节点一样, 如果不一样的话,就继续判断root的左子树,看是否一样.而如果一样的话,等issub函数执行完,以此时的root为根的结果如果为false,就是不是子树,继续下一次,就是root的left,再找下一个
//和子树的val相等的下一个节点,如果不相等,继续,找子树的下一个节点,加入左子树都找完了,那么就开始右子树的查找,同样的循环,如果右子树中有一个根节点一样和sroot,那么就成功进入issbu
//函数,判断以此时的节点为root,来递归判断,二叉树sroot和此时root是否相等,issub就是,看root的左子树和srrot的左子树是否相等,不相等返回false,issub执行结束,相等的话,继续root->left->left和sroot->left->left判断.假如判断到了root和sroot都为空
//issub函数中先判断sroot是否为空,如果为空,就证明了sroot的左子树都判读完了,最开始根节点相等root和sroot那个相等的左子树判断完了,继续&&issub右子树),同样的道理,如果中间有不相等的,因为经过了判断root或者sroot为空,所以如果判断不相等,一定是不相等,因为还么有遍历完root或者sroot的节点
//所以issub返回,并且返回到issubtree中,result为false,则issubtrereturn false,继续issubtree刚才的函数调用栈
{
result =isSub(root, sroot);
}
if (!result)
{
result = isSubTree(root->left, sroot);
}
if (!result)
{
result = isSubTree(root->right, sroot);
}
return result;
}