📅  最后修改于: 2023-12-03 15:40:27.280000             🧑  作者: Mango
树的左儿子右兄弟表示法,也称链表表示法,是一种用链表实现树的一种方式。在这种实现方法中,每个节点都包含两个指针:左儿子指针和右兄弟指针。
每个节点包含以下元素:
typedef struct TreeNode {
int data; // 存储节点的数据
struct TreeNode *firstChild; // 左儿子指针
struct TreeNode *nextSibling; // 右兄弟指针
} TreeNode, *Tree;
根据定义,每个节点都可以有任意多个子节点,左儿子指针指向第一个子节点,右兄弟指针指向下一个兄弟节点。如果一个节点没有子节点,则其左儿子指针为 NULL;如果一个节点是其父节点的最后一个子节点,则其右兄弟指针为 NULL。
插入节点需要分两种情况:
void insertNode(Tree *root, int parentValue, int value)
{
if (*root == NULL) {
// 根节点为空,插入节点作为根节点
*root = (TreeNode*) malloc(sizeof(TreeNode));
(*root)->data = value;
(*root)->firstChild = NULL;
(*root)->nextSibling = NULL;
return;
}
TreeNode *parent = findNode(*root, parentValue);
if (parent == NULL) {
// 没有找到父节点,插入失败
return;
}
if (parent->firstChild == NULL) {
// 父节点没有子节点,插入节点作为第一个子节点
parent->firstChild = (TreeNode*) malloc(sizeof(TreeNode));
parent->firstChild->data = value;
parent->firstChild->firstChild = NULL;
parent->firstChild->nextSibling = NULL;
} else {
// 父节点有子节点,找到最后一个子节点的右兄弟,插入节点作为右兄弟
TreeNode *sibling = parent->firstChild;
while (sibling->nextSibling != NULL) {
sibling = sibling->nextSibling;
}
sibling->nextSibling = (TreeNode*) malloc(sizeof(TreeNode));
sibling->nextSibling->data = value;
sibling->nextSibling->firstChild = NULL;
sibling->nextSibling->nextSibling = NULL;
}
}
为了插入新节点,我们需要先查找其父节点。遍历树的方法有很多种,这里我们使用深度优先搜索(DFS)。
TreeNode* findNode(TreeNode *node, int value)
{
if (node == NULL) {
// 树为空,或者节点不存在,返回 NULL
return NULL;
}
if (node->data == value) {
// 找到节点,返回
return node;
}
TreeNode *result = findNode(node->firstChild, value);
if (result == NULL) {
result = findNode(node->nextSibling, value);
}
return result;
}
由于树的结构比较复杂,遍历树的方法也比较多。这里我们介绍两种方法:先序遍历和层序遍历。
先序遍历按照“根节点-左子树-右子树”的顺序遍历树。
void preOrderTraversal(TreeNode *node)
{
if (node == NULL) {
return;
}
printf("%d ", node->data);
preOrderTraversal(node->firstChild);
preOrderTraversal(node->nextSibling);
}
层序遍历按照树的层次遍历树。
void levelOrderTraversal(TreeNode *root)
{
if (root == NULL) {
return;
}
Queue *q = newQueue();
push(q, root);
while (!isEmpty(q)) {
TreeNode *node = (TreeNode*)pop(q);
printf("%d ", node->data);
if (node->firstChild != NULL) {
push(q, node->firstChild);
}
if (node->nextSibling != NULL) {
push(q, node->nextSibling);
}
}
}
与其他树的表示方式相比,树的左儿子右兄弟表示法具有以下优缺点:
树的左儿子右兄弟表示法是一种实现树的方法,它使用链表来存储树。它适用于插入和删除节点比较频繁的场景。该表示法的缺点是查找节点比较慢,不支持深度遍历。