梗概1:
树的相关概念:
空树:
- 定义: 0个结点
子树
- 定义: 子树的根只有一个直接前驱
森林
child::森林
结点的度
- 定义: 结点的分叉数量
结点的分类:
根结点:
- 定义: 树最底层的结点
双亲结点:
- 该结点所连接的上一层结点
叶结点/终结结点:
- 定义: 度为0的结点
分支结点:
- 定义: 度不为0的结点
结点的层次
- 从根结点开始数1, 每个结点步进1
结点的层序编号:
- 编号顺序:
- 从左到右, 再到下一层
树的度
- 用树中最大的结点度作为树的度
树的高度(深度)
- 树中最大层次
特殊的树:
树,森林,二叉树的相互转换
child::树,森林,二叉树的相互转换
操作:
child::
树的操作
遍历:
删除节点
child::
删除树节点
方法之一
- 遍历树的时候,缓存其当前节点的父节点
- 从父节点中移除当前节点
方法之一
指向原始笔记的链接
- 遍历树的同时复制一棵树,对于需要删除的节点,则不复制
- 缺点:需要两倍的空间
- 优点:方便快捷
克隆
child::
指向原始笔记的链接克隆树
指向原始笔记的链接
- child::
广度优先克隆树
在 JavaScript 中,可以使用广度优先搜索(BFS)来实现树的深拷贝。下面是一个实现的示例:
指向原始笔记的链接 class TreeNode { constructor(value) { this.value = value; this.children = []; } addChild(child) { this.children.push(child); } } function deepCopyTree(root) { if (!root) { return null; // 如果根节点为空,返回 null } // 创建一个队列用于广度优先遍历 const queue = []; const clonedRoot = new TreeNode(root.value); // 复制根节点 queue.push({ original: root, clone: clonedRoot }); // 将原始节点和克隆节点放入队列 while (queue.length > 0) { const { original, clone } = queue.shift(); // 弹出队列中的第一个元素 // 遍历当前节点的子节点 for (const child of original.children) { const clonedChild = new TreeNode(child.value); // 复制子节点 clone.children.push(clonedChild); // 将复制的子节点添加到克隆节点的子节点中 queue.push({ original: child, clone: clonedChild }); // 将子节点的原始和克隆放入队列 } } return clonedRoot; // 返回深拷贝的树的根节点 } // 示例用法 const root = new TreeNode(1); const child1 = new TreeNode(2); const child2 = new TreeNode(3); const child3 = new TreeNode(4); root.addChild(child1); root.addChild(child2); child1.addChild(child3); const clonedTree = deepCopyTree(root); // 打印结果以验证深拷贝 console.log(clonedTree); // 输出克隆的树结构
- child::
深度优先克隆树
伪代码
指向原始笔记的链接 function cloneTree(tree){ function dfs(node){ let cloneNode = clone(node) cloneNode.children= tree.children.map(v=>dfs(v)) return cloneNode } return dfs(tree) }
树的存储结构
数据维度
- 至少需要二维: id和子结点
主要有三种:
- 双亲表示法
- 孩子表示法
- 孩子兄弟表示法
普通树在c语言中的实现
双亲表示法
梗概:
- 用线性表存储树的结点
- 每个结点存储三部分信息
- 该结点在线性表中的位置(下标)
- 表示某一个结点
- 数据域 2. 存储该结点的数据
- 双亲域 3. 存储双亲结点的位置(下标)
- 该结点在线性表中的位置(下标)
实现:
#define TNode_MAXNUM 128
typedef struct{
TdataType data;
int parent;
}TNode;
typedef struct{
TNode tree[TNode_MAXNUM];
int nodenum;
}ParentTree;
孩子表示法
梗概:
- 用一个线性表存储每个结点
- 每个结点存储三个信息
- 当前结点在线性表中的位置
- 表示对应结点
- 数据域
- 存储当前结点的数据
- 孩子链表头指针域
- 存储一个单链表的头指针
- 该单链表每个链表结点存储两个信息
- 树结点在线性表中的位置
- 表示对应树结点
- 下一个链表结点指针域
- 树结点在线性表中的位置
- 该单链表每个链表结点存储两个信息
- 存储一个单链表的头指针
- 当前结点在线性表中的位置
实现:
typedef struct ChildNode{
int Child;
struct ChildNode *next;
}ChildNode;
typedef struct{
TdataType data;
ChildNode *FirstChild;
}TNode;
typedef struct{
TNode nodes[TNode_MAXNUM];
int root;
int num;
}ChildTree;
孩子兄弟表示法
梗概:
- 用二叉链表存储每个树结点
- 每个链结点存储三部分信息
- 首孩子域(名为FirstChild)
- 存储首孩子(从左往右)树结点在二叉链表中的位置
- 数据域
- 兄弟域(名为NextSibling)
- 存储右兄弟树结点在二叉链表中的位置
- 首孩子域(名为FirstChild)
实现:
typedef struct CSNode{
TDataType data;
struct CSNode* FirstChild;
struct CSNode* NextSibling;
}CSNode, *CSTree;