文章目录
二叉树:
一、查询二叉树第K层的数据元素
假设根结点所在的层数为第一层,则左右孩子所在的层为第二层,层数依次向下递归增长。
实现给定二叉树层数,打印此层的所有数据元素。
递归实现
void PrintK_r(struct BtNode* p, int k)
{
if (k == 0 && p != NULL)
{
std::cout << p->data << " ";
}
else if (p != NULL)
{
PrintK_r(p->leftchild, k - 1);
PrintK_r(p->rightchild, k - 1);
}
}
void Print_KLevel_Item_R(struct BtNode* p, int k)
{
if (NULL == p || k <= 0) return;
PrintK_r(p, k - 1);
std::cout << std::endl;
}
非递归实现
void PrintK(struct BtNode* p, int k)
{
std::queue<struct BtNode*> qua, qub;
qua.push(p); // 第一层(根结点)存入a队列
int i = 1; // 记录当前层与待输出层的层差
while (!qua.empty() || !qub.empty())
{
while (!qua.empty()) // a队列中元素的下一层 存入b队列
{
p = qua.front(); qua.pop();
if (i == k)
{
std::cout << p->data << " ";
}
else
{
if (p->leftchild != NULL)
{
qub.push(p->leftchild);
}
if (p->rightchild != NULL)
{
qub.push(p->rightchild);
}
}
}
i++;
while (!qub.empty()) // b队列中元素的下一层 存入a队列
{
p = qub.front(); qub.pop();
if (i == k)
{
std::cout << p->data << " ";
}
else
{
if (p->leftchild != NULL)
{
qua.push(p->leftchild);
}
if (p->rightchild != NULL)
{
qua.push(p->rightchild);
}
}
}
i++;
}
std::cout << std::endl;
}
void Print_KLevel_Item(struct BtNode* p,int k)
{
if (NULL == p || k <= 0) return;
PrintK(p, k);
}
输出测试
int main() {
const char* pstr = "ABC##DE##F##G#H##";
BinaryTree root = NULL;
root = CreateTree1(&pstr);
strPreOrder(root); printf("\n"); // 先序创建字符串
std::cout << "---------------" << std::endl;
/* 层序遍历 */
LeveOrder(root);
int i = 0;
while (std::cin >> i, i != -1) // 输入 -1 结束测试
{
Print_KLevel_Item(root, i); // 非递归
Print_KLevel_Item_R(root, i); // 递归
}
std::cout << std::endl;
return 0;
}
运行结果:
ABC##DE##F##G#H##
---------------
A B G C D H E F
0 // 输入
1 // 输入
A
A
2 // 输入
B G
B G
3 // 输入
C D H
C D H
4 // 输入
E F
E F
5 // 输入
6 // 输入
-1 // 输入 -1
二、查询二叉树的深度和结点数
假设树的根结点深度为0,处于第一层。它的孩子深度为1,处于第二层。那么我们求这个树的深度和结点个数。
2.1 树的深度
/* 二叉树深度 */
int TreeDepth(struct BtNode* p)
{
if (p == NULL) return -1; // NULL 的父节点为叶子结点
else
{
int l = TreeDepth(p->leftchild);
int r = TreeDepth(p->rightchild);
return (l > r ? l : r) + 1;
}
}
int GetDepth(struct BtNode* p)
{
if (NULL == p) return -1;
return TreeDepth(p);
}
简化:
int GetDepth2(struct BtNode* p)
{
if (p == NULL) return -1;
else return std::max(GetDepth2(p->leftchild), GetDepth2(p->rightchild)) + 1;
}
说明:当传入根节点指针为NULL时,输出 -1 。
2.2 树的结点数
/* 二叉树结点个数 */
int TreeSize(struct BtNode* p)
{
if (p->leftchild == NULL && p->rightchild == NULL) return 1;
else
{
int sum = 1;
if (p->leftchild != NULL)
{
sum += TreeSize(p->leftchild);
}
if (p->rightchild != 0)
{
sum += TreeSize(p->rightchild);
}
return sum;
}
}
int GetSize(struct BtNode* p)
{
if (NULL == p) return 0;
return TreeSize(p);
}
简化:
int GetSize2(struct BtNode* p)
{
if (p == NULL) return 0;
else return GetSize2(p->leftchild) + GetSize2(p->rightchild) + 1;
}
说明:传入空的根节点(NULL),输出结点个数为 0 。
三、查询二叉树中元素位置
在二叉树中查询value值,如果存在返回节点的地址,否则返回NULL 。
二叉树中查找元素可以理解为二叉树遍历中的特殊情况,因此查找的算法有很多,这里以深度优先遍历的先序遍历为例 。
递归算法:
struct BtNode* FindValue(struct BtNode* p, ElemType val)
{
if (p == NULL || p->data == val) return p;
else
{
struct BtNode* pos = NULL;
pos = FindValue(p->leftchild, val);
if (pos == NULL)
{
pos = FindValue(p->rightchild, val);
}
return pos;
}
}
非递归算法:
struct BtNode* NiceFindValue(struct BtNode* p, ElemType val)
{
if (p == NULL || p->data == val) return p;
std::stack<struct BtNode*> st;
while (!st.empty() || p != NULL) // 最终的退出条件
{
while (p != NULL) // 一直向左遍历左子树
{
if (p->data == val) return p; // 在遍历时,每一步访问的都是根,可以输出
st.push(p);
p = p->leftchild;
} /* while 结束 表示,此结点没有左孩子 */
p = st.top(); st.pop(); // 回退至父节点
p = p->rightchild; // 试探右结点
}
return p;
}
四、查询结点的双亲
给定一个二叉树,找到该树中某个指定节点的双亲。
/* 二叉树 指定孩子结点 */
struct BtNode* Parent1(struct BtNode* p, struct BtNode* child)
{
if (p == NULL || p == child) return p; // 把查询到的子节点返回上层调用进行判断
else
{
struct BtNode* pos = NULL;
pos = Parent1(p->leftchild, child);
if (pos == NULL) /* 左子树没找到孩子 */
{
pos = Parent1(p->rightchild, child);
if (pos == child) pos = p; /* 右子树找到孩子 */
}
else if(p->leftchild == child) pos = p; /* 左子树找到孩子 */
return pos; /* pos如果找到就返回pos,没有找到就为NULL */
}
}
struct BtNode* Parent2(struct BtNode* p, struct BtNode* child)
{ // 直接在当前结点判断子节点是否找到
if (p == NULL || p->leftchild == child || p->rightchild == child) return p;
else
{
struct BtNode* pos = NULL;
pos = Parent2(p->leftchild, child);
if (pos == NULL)
{
pos = Parent2(p->rightchild, child);
}
return pos;
}
}
struct BtNode* FindParent(struct BtNode* p, struct BtNode* child)
{
if (NULL == p || NULL == child || p == child)
{
return NULL;
}
else return Parent1(p, child);
//else return Parent2(p, child);
}
五、查询两结点的公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
力扣原题:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
注意:
- 如果所给两结点在二叉树中不存在,返回NULL 。
- 如果所给两结点,其中一个结点为NULL,则返回另一个结点 。
- 如果所给两结点,是同一个结点,则返回该结点本身。
- 如果所给两结点,一个结点本身就是另一个结点的祖先结点,则返回该祖先结点本身。
struct BtNode* FindAncestor(struct BtNode* root, struct BtNode* p, struct BtNode* q)
{
if (root == NULL || root == p || root == q) return root;
struct BtNode* left = FindAncestor(root->leftchild, p, q);
struct BtNode* right = FindAncestor(root->rightchild, p, q);
if (left != NULL && right != NULL) return root; // 在左右子树中找到p、q
if (left != NULL) return left; // 只有左子树找到
if (right != NULL) return right; // 只有右子树找到
return NULL; // 没有找到
}
struct BtNode* lowestCommonAncestor(struct BtNode* root, struct BtNode* p, struct BtNode* q)
{
if (NULL == p) return q;
if (NULL == q) return p;
return FindAncestor(root, p, q);
}
六、查询二叉树的路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
力扣原题:https://leetcode-cn.com/problems/path-sum/comments/
bool hasPathSum(struct BtNode* root, int sum)
{
if (root == NULL) return false;
if (root->leftchild == NULL && root->rightchild == NULL) // 叶子结点
{
if (root->data == sum) return true;
else return false;
}
bool res = false;
/*
* //位运算符 ‘|’ ,有一个为真,结果为真。
* //真: true|true 、false|true、true|false
* //假: false|false
* res = res | PathSum(root->leftchild, sum - root->data);
* res = res | PathSum(root->rightchild, sum - root->data);
*/
res = res | hasPathSum(root->leftchild, sum - root->data); // 左子树查询
res ? res : res |= hasPathSum(root->rightchild, sum - root->data); // 如果左子树查询到,就不需要再查找右子树。
return res;
}