1.求二叉树中最远的两个节点的距离
在这我们首先来分析思路,对于最远的两个节点,在这会有两种情况。
1)如果root为NULL,那么这是一颗空树。空树的最远子节点距离和高度均为零。
2),如果root非空,最大距离要么是左子树中的最大距离,要么是右子树中的最大距离,要么是左子树节点中到根节点的最大距离+右子树节点中到根节点的最大距离,同时记录左子树和右子树节点中到根节点的最大距离。
示例代码:
//求得二叉树中最远两个节点之间的距离
size_t MaxDistance()
{
size_t maxdistance = 0;
_MaxDistance(_root,maxdistance);
return maxdistance;
}
//求二叉树中最远的两个节点的距离
size_t _MaxDistance(Node *root,size_t &Max)
{
if (root == NULL)
{
Max = 0;
return 0;
}
if (root->_left == NULL&&root->_right == NULL)
{
return 0;
}
size_t leftdepth= _MaxDistance(root->_left, Max)+1;
size_t rightdepth = _MaxDistance(root->_right, Max)+1;
//用来得到最远距离
Max = (Max < (leftdepth + rightdepth) ? (leftdepth + rightdepth) : Max) ;
//顺带返回深度
return (leftdepth>rightdepth?leftdepth:rightdepth);
}
2.判断一棵树是否为完全二叉树
判断一棵树是否为完全二叉树,首先要理解完全二叉树的定义,完全二叉树就是 只有最下面的两层结点度能够小于2,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。
1)所以根据特点,我们可以思考,如果对于完全二叉树,我们进行层序遍历,那么一直就可以走到头,而对于非完全二叉树,我们进行层序遍历,那么我们可能还会遇到空。因为最后一层节点的分布导致。
所以我们就可以利用层序遍历进行判断,先把每层的节点进行入队。然后出队,一直到碰到NULL,这个时候看队中是否还剩下了非空结点,如果存在,那么就不是完全二叉树。如果不存在,那么就是完全二叉树。
2)可以给一个flag,当到左树的时候,利用这个flag,如果左为空,右边还右节点,那么这棵树必定不是完全二叉树。
3)也还可以从上利用队列,放入队列当中,当遇到一个空节点后不再入队,然后向后看是否还有非空节点,有则不是完全二叉树,没有则是完全二叉树。
示例代码:
bool IsComplateBinaryTree()
{
std::queue<Node * > q;
Node* cur = _root;
q.push(cur);
//首先进行层序,把每一层的节点都入队,这个时候不存在的节点就按照NULL入队
while ((cur = q.front()) != NULL)
{
q.pop();
q.push(cur->_left);
q.push(cur->_right);
}
//这个时候如果是完全二叉树,那么队中就全部为空,如果为非完全二叉树的话,那么队中就会存在不为空的元素。
while (!q.empty())
{
cur = q.front();
q.pop();
if (cur != NULL)
{
return false;
}
}
return true;
}
3.由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列: 3 2 4 1 6 5 )
重建二叉树,就是利用前序遍历第一个节点是根节点的特性确定根节点,然后通过中序遍历中根节点在中间,这样我们也可以得到左子树序列和右子树序列,然后转化为递归问题,就可以解决。
Node* _RebuildBinaryTree (T* preorder, T* infixorder , int lengh)
{
if ( lengh == 0 || preorder == NULL || infixorder == NULL)
{
return NULL ;
}
T tmp = preorder[0 ];
Node * root = new Node(tmp );
int i = 0;
for ( i = 0; i < lengh &&infixorder[ i] != tmp ; i ++)
;
int leftlen = i;
int rightlen = lengh - i - 1 ;
if ( leftlen>0 )
root->_left = _RebuildBinaryTree (preorder+ 1, infixorder, leftlen);
if ( rightlen > 0)
root->_right = _RebuildBinaryTree (preorder+ leftlen + 1, infixorder +leftlen + 1 , rightlen );
return root ;
}
4.寻找两个节点的最近公共节点
当我们在这里查找节点的时候,可以通过一些条件来限定:
1)如果是BST
如果二叉树是个二叉查找树,且root和两个节点的值(a, b)已知。两个节点的key去和root的key进行比较。
如果两个节点值都大于root的key,那么这两个节点就是在root的右边,如果两个节点的值都小于root的key,那么这两个节点都在root的左边。如果一大一小,那么root就是最近祖先节点。
Node *FindTwoCommonNode(Node* p1,Node* p2)
{
K minkey = 0;
K maxkey = 0;
if (p1->_key > p2->_key)
{
maxkey = p1->_key;
minkey = p2->_key;
}
else
{
maxkey = p2->_key;
minkey = p1->_key;
}
Node* cur = _root;
while (cur)
{
//考虑两类情况,一种是在符合的节点
if (cur->_key >= minkey&&cur->_key <= maxkey)
{
return cur;
}
//此时cur所指向节点比两个节点都大。所以两个节点都在左子树
else if (cur->_key > minkey&&cur->_key > maxkey)
{
cur = cur->_left;
}
//对比上一步
else
{
cur = cur->_right;
}
}
return NULL;
}
2)是二叉树有parent
此时可以分别从两个节点开始,沿着parent指针走向根节点,得到两个链表,然后求两个链表的第一个公共节点。这种方法,其实就是从二叉树演变成了链表求公共节点的问题,这个以前博客有些,就不再多介绍了。
3)思路:有两种情况,一是要找的这两个节点(a, b),在要遍历的节点(root)的两侧,那么这个节点就是这两个节点的最近公共父节点;
二是两个节点在同一侧,则 root->left 或者 root->right 为 NULL,另一边返回a或者b。那么另一边返回的就是他们的最小公共父节点。
递归有两个出口,一是没有找到a或者b,则返回NULL;二是只要碰到a或者b,就立刻返回。
示例代码:
//查找最近的两个公共节点
Node* _FindTwoCommonNode(Node* root, Node* p1, Node *p2)
{
//当节点为空,这个时候返回
if (root == NULL)
{
return NULL;
}
//判断节点是否为要找的节点,是则直接返回节点
if (root == p1 || root == p2)
{
return root;
}
//递归右树和左树,寻找两个节点
Node* left = _FindTwoCommonNode(root->_left, p1, p2);
Node* right = _FindTwoCommonNode(root->_right, p1, p2);
//判断是否在左子树和右子树中找到,如果在左右子树当中都找到了,那就说明当前的root就是最近祖先
if (left&&right)
//左右子树都存在就返回root,此时的root就是最近公共节点
return root;
//否则返回找到的节点非空结点。
return left ? left : right;
}
5.BST转排序双向链表
思路就是利用prenode进行连接。进行一个类似的中序的一个线索化过程。
所以如果有需要,可以先去看我前面的线索化的文章。
我们的思想就是,我们在这个工程中我们使用prenode作为记录上一个节点,
Node* _CovertSortList(Node *root,Node *&prenode)
{
if (root==NULL)
return NULL;
Node* cur = root;
//先要找到BST的最小键值点,也就是最左节点。寻找最左节点的时候切记prenode是不能变的。
if (root->_left)
_CovertSortList(cur->_left, prenode);
//找到以后,这个最左节点的左边链上prenode
//当前节点我们用来连接左指针到上一个节点
cur->_left = prenode;
//这个时候考虑给前一个节点的右链上节点
//在当前节点的时候,我们连接上一个节点的右指针到当前节点
if (prenode != NULL)
prenode->_right = cur;
//改变前一个节点为当前节点
prenode = cur;
//考虑右子树的问题
if (cur->_right)
_CovertSortList(cur->_right,prenode);
return root;
}