您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# JavaScript数据结构之多叉树怎么实现
## 1. 多叉树基础概念
### 1.1 什么是多叉树
多叉树(N-ary Tree)是树形数据结构的一种扩展形式,与二叉树不同,多叉树的每个节点可以有任意数量的子节点(通常称为子节点列表)。这种数据结构能够更自然地表示许多现实场景,比如:
- 文件系统的目录结构
- 公司组织架构图
- 游戏中的技能树
- XML/HTML文档对象模型(DOM)
### 1.2 多叉树与二叉树的区别
| 特性 | 多叉树 | 二叉树 |
|-------------|-------------------------|----------------------|
| 子节点数量 | 0到N个 | 最多2个(左/右) |
| 存储结构 | 通常使用数组/链表存储子节点 | 明确分为左右节点 |
| 应用场景 | 层级关系复杂的数据 | 搜索/排序等算法 |
| 遍历复杂度 | 相对较高 | 相对较低 |
### 1.3 多叉树的基本术语
- **节点(Node)**:树的基本构成单位
- **根节点(Root)**:没有父节点的顶层节点
- **叶子节点(Leaf)**:没有子节点的末端节点
- **度(Degree)**:节点直接子节点的数量
- **深度(Depth)**:从根到该节点的边数
- **高度(Height)**:从节点到最深叶子节点的边数
## 2. JavaScript实现多叉树
### 2.1 基本节点结构
```javascript
class TreeNode {
constructor(value) {
this.value = value; // 节点存储的值
this.children = []; // 子节点数组
this.parent = null; // 父节点引用(可选)
}
// 添加子节点
addChild(childNode) {
childNode.parent = this; // 设置父节点引用
this.children.push(childNode);
return this; // 支持链式调用
}
// 移除子节点
removeChild(childNode) {
this.children = this.children.filter(
child => child !== childNode
);
return this;
}
}
class NaryTree {
constructor(rootValue) {
this.root = new TreeNode(rootValue);
this.size = 1; // 节点计数器
}
// 查找节点(广度优先)
findBFS(value) {
const queue = [this.root];
while(queue.length) {
const currentNode = queue.shift();
if(currentNode.value === value) {
return currentNode;
}
queue.push(...currentNode.children);
}
return null;
}
// 添加节点到指定父节点
addNode(value, parentValue) {
const parentNode = this.findBFS(parentValue);
if(!parentNode) {
throw new Error('Parent node not found');
}
const newNode = new TreeNode(value);
parentNode.addChild(newNode);
this.size++;
return newNode;
}
// 获取树的高度
getHeight(node = this.root) {
if(!node.children.length) return 0;
let maxHeight = 0;
for(const child of node.children) {
maxHeight = Math.max(maxHeight, this.getHeight(child));
}
return maxHeight + 1;
}
}
// 递归实现
function traverseDFS(node, callback) {
callback(node);
node.children.forEach(child => {
traverseDFS(child, callback);
});
}
// 迭代实现(使用栈)
function traverseDFSIterative(root, callback) {
const stack = [root];
while(stack.length) {
const node = stack.pop();
callback(node);
// 注意子节点要反向压栈以保证顺序
for(let i = node.children.length - 1; i >= 0; i--) {
stack.push(node.children[i]);
}
}
}
function traverseBFS(root, callback) {
const queue = [root];
while(queue.length) {
const node = queue.shift();
callback(node);
queue.push(...node.children);
}
}
// 前序遍历(父节点在子节点之前处理)
function preOrder(node, callback) {
callback(node);
node.children.forEach(child => {
preOrder(child, callback);
});
}
// 后序遍历(父节点在子节点之后处理)
function postOrder(node, callback) {
node.children.forEach(child => {
postOrder(child, callback);
});
callback(node);
}
function findPath(targetValue) {
const path = [];
function search(node) {
path.push(node.value);
if(node.value === targetValue) {
return true;
}
for(const child of node.children) {
if(search(child)) {
return true;
}
}
path.pop();
return false;
}
search(this.root);
return path;
}
// 序列化为JSON字符串
function serialize() {
function serializeNode(node) {
return {
value: node.value,
children: node.children.map(serializeNode)
};
}
return JSON.stringify(serializeNode(this.root));
}
// 从JSON字符串反序列化
function deserialize(jsonStr) {
const data = JSON.parse(jsonStr);
function buildNode(obj) {
const node = new TreeNode(obj.value);
obj.children.forEach(childObj => {
node.addChild(buildNode(childObj));
});
return node;
}
this.root = buildNode(data);
}
对于子节点数量可能很大的情况:
class OptimizedTreeNode {
constructor(value) {
this.value = value;
this.firstChild = null; // 第一个子节点
this.nextSibling = null; // 下一个兄弟节点
}
// 添加子节点
addChild(value) {
const newNode = new OptimizedTreeNode(value);
if(!this.firstChild) {
this.firstChild = newNode;
} else {
let current = this.firstChild;
while(current.nextSibling) {
current = current.nextSibling;
}
current.nextSibling = newNode;
}
return newNode;
}
}
class CachedTree extends NaryTree {
constructor(rootValue) {
super(rootValue);
this._height = 0;
this._size = 1;
}
getHeight() {
if(this._heightDirty) {
this._height = super.getHeight();
this._heightDirty = false;
}
return this._height;
}
addNode(value, parentValue) {
const node = super.addNode(value, parentValue);
this._heightDirty = true;
return node;
}
}
class FileSystem {
constructor() {
this.tree = new NaryTree('/');
}
mkdir(path) {
const parts = path.split('/').filter(Boolean);
let current = this.tree.root;
for(const part of parts) {
let found = current.children.find(c => c.value === part);
if(!found) {
found = current.addChild(new TreeNode(part));
}
current = found;
}
}
ls(path = '/') {
const parts = path.split('/').filter(Boolean);
let current = this.tree.root;
for(const part of parts) {
current = current.children.find(c => c.value === part);
if(!current) throw new Error('Path not found');
}
return current.children.map(c => c.value);
}
}
class OrganizationChart {
constructor(ceoName) {
this.tree = new NaryTree(ceoName);
}
hire(employeeName, managerName) {
return this.tree.addNode(employeeName, managerName);
}
getTeam(managerName) {
const manager = this.tree.findBFS(managerName);
if(!manager) return [];
return manager.children.map(c => c.value);
}
getManagementChain(employeeName) {
let node = this.tree.findBFS(employeeName);
const chain = [];
while(node && node.parent) {
chain.unshift(node.parent.value);
node = node.parent;
}
return chain;
}
}
function hasCycle(root) {
const visited = new Set();
function detect(node) {
if(visited.has(node)) return true;
visited.add(node);
for(const child of node.children) {
if(detect(child)) return true;
}
visited.delete(node);
return false;
}
return detect(root);
}
class SafeTree {
constructor(rootValue) {
this.root = new WeakRef(new TreeNode(rootValue));
}
// 使用WeakRef避免强引用
addChild(parentRef, value) {
const parent = parentRef.deref();
if(!parent) throw new Error('Parent node garbage collected');
const child = new TreeNode(value);
parent.addChild(child);
return new WeakRef(child);
}
}
describe('NaryTree', () => {
let tree;
beforeEach(() => {
tree = new NaryTree('root');
tree.addNode('child1', 'root');
tree.addNode('child2', 'root');
tree.addNode('grandchild1', 'child1');
});
test('should find nodes', () => {
expect(tree.findBFS('child1')).not.toBeNull();
expect(tree.findBFS('notexist')).toBeNull();
});
test('should calculate height', () => {
expect(tree.getHeight()).toBe(2);
});
test('should traverse correctly', () => {
const values = [];
tree.traverseBFS(tree.root, node => values.push(node.value));
expect(values).toEqual(['root','child1','child2','grandchild1']);
});
});
console.time()
测量大规模数据操作class TrieNode {
constructor() {
this.children = new Map(); // 字符到子节点的映射
this.isEndOfWord = false;
}
}
class Trie {
constructor() {
this.root = new TrieNode();
}
insert(word) {
let current = this.root;
for(const char of word) {
if(!current.children.has(char)) {
current.children.set(char, new TrieNode());
}
current = current.children.get(char);
}
current.isEndOfWord = true;
}
}
class BTreeNode {
constructor(order) {
this.order = order; // 阶数
this.keys = []; // 键数组
this.children = []; // 子节点数组
this.isLeaf = false; // 是否为叶子节点
}
// 插入键的辅助方法
insertKey(key) {
let i = this.keys.length - 1;
while(i >= 0 && key < this.keys[i]) {
this.keys[i+1] = this.keys[i];
i--;
}
this.keys[i+1] = key;
}
}
选择适当的结构:
遍历选择原则:
内存管理:
性能关键点:
扩展建议:
多叉树作为基础数据结构的扩展形式,在JavaScript中有着广泛的应用场景。通过合理的实现和优化,可以构建出高效、稳定的树形结构解决方案。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。