- 一种分层数据的抽象模型
- 前端中常见的树包括:DOM树、级联选择、树形控件


- js 中没有树,但可以用 Object 和 Array 构建树 - const tree = {
- val: 'a',
- children: [
- {
- val: 'b',
- children: [
- {
- val: 'd',
- children: []
- },
- {
- val: 'e',
- children: []
- },
- ]
- },
- {
- val: 'c',
- children: [
- {
- val: 'f',
- children: []
- },
- {
- val: 'g',
- children: []
- },
- ]
- },
- ]
- }
 
- 树的常用操作 - 深度广度优先遍历、先中后续遍历
 
深度优先遍历
尽可能深的搜索树的分支

- 口诀 - 访问根节点
- 对根节点 children 挨个进行深度优先遍历
```javascript
/**- 深度优先遍历:访问根结点,对根结点 children 挨个进行深度优先遍历 */ const dfs = (root) => { console.log(root.val);
 
 - root.children.forEach(child => dfs(child)); } 
dfs(tree);
<a name="WHQBO"></a>
## 广度优先遍历
先访问离根节点最近的节点<br />
口诀
- 新建一个队列,把根节点入队
- 把对头出队并访问
- 把对头的 children 挨个入队
- 重复二三步,直到队列为空
```javascript
/**
* 广度优先遍历:
* 1.新建一个队列,把根结点入队
* 2.把队头出队并访问
* 3.把队头的 children 挨个入队
* 4.重复第二、三步,直到队列为空
*/
const bfs = (root) => {
const q = [root];
while(q.length > 0) {
const n = q.shift();
console.log(n.val);
n.children.forEach(item => q.push(item));
}
}
bfs(tree);
二叉树
什么是二叉树?
- 树中的每个节点最多只能有两个子节点
- js 中通常用 Object 来模拟二叉树
```javascript
const bt = {
val: 1,
left: {
  val: 2,
  left: {
 }, right: {val: 4, left: { val: 8, left: null, right: null, }, right: null,
 } }, right: { val: 3, left: {val: 5, left: null, right: null,
 }, right: {val: 6, left: null, right: null,
 } } }val: 7, left: null, right: null,
module.exports = bt;
<a name="E2CqD"></a>
### 二叉树先序遍历
- 访问根节点
- 对根节点的左子树进行先序遍历
- 对根节点的右子树进行先序遍历
```javascript
/** 
 * 先序遍历
 * 访问根结点
 * 对根结点的左子树进行先序遍历
 * 对根结点的右子树进行先序遍历
 */ 
const preOrder = (root) => {
  if (!root) {
    return;
  }
  console.log(root.val);
  preOrder(root.left);
  preOrder(root.right);
}
/** 
 * 非递归版
 */
const preOrder = (root) => {
  if (!root) { return };
  const stack = [root];
  while(stack.length > 0) {
    const n = stack.pop();
    if (n) {
      console.log(n.val);
      stack.push(n.right)
      stack.push(n.left)
    }
  }
}
preOrder(bt);
二叉树中序遍历
- 对根结点的左子树进行中序遍历
- 访问根结点
- 对根节点的右子树进行中序遍历 ```javascript /** - 中序遍历
- 对根结点的左子树进行中序遍历
- 访问根结点
- 对根节点的右子树进行中序遍历 */ const inOrder = (root) => { if (!root) { return; }
 - inOrder(root.left); - console.log(root.val); - inOrder(root.right); } 
inOrder(bt);
```javascript
/** 
 * 非递归版
 */
const inOrder = (root) => {
  if (!root) {
    return;
  }
  const stack = [];
  let p = root;
  while(stack.length || p) {
    while(p) {
      stack.push(p);
      p = p.left;
    }
    const n = stack.pop();
    console.log(n.val);
    p = n.right;
  }
}
inOrder(bt);
二叉树后序遍历
- 对根结点的左子树进行先序遍历
- 对根结点的右子树进行先序遍历
- 访问根节点 ```javascript /** - 后续遍历
- 对根结点的左子树进行先序遍历
- 对根结点的右子树进行先序遍历
- 访问根节点 */ const postOrder = (root) => { if (!root) { return; }
 - postOrder(root.left); postOrder(root.right); - console.log(root.val); } 
postOrder(bt);
```javascript
/** 
 * 非递归版
 */
const postOrder = (root) => {
  if (!root) {
    return;
  }
  const stack = [root];
  const outStack = [];
  while(stack.length) {
    const n = stack.pop();
    outStack.push(n);
    if (n.left) {
      stack.push(n.left);
    }
    if (n.right) {
      stack.push(n.right);
    }
  }
  while(outStack.length) {
    const n = outStack.pop();
    console.log(n.val);
  }
}
postOrder(bt);
遍历 json 的所有节点值
const json = {
  a: { b: { c: 1 } },
  d: [1,2]
}
const dfs = (n, path) => {
  console.log(n, path);
  Object.keys(n).forEach(k => {
    dfs(n[k], path.concat(k));
  })
}
dfs(json, []);
结果
JSjsonjs
1
constjson
a:fb:fc:1j万,
2
d:[1,2],
3
4
5
constdfs(n,path)>
67
conso1e.1og(n,path);
object.keys(n).forEach(k->
8
dfs(n[k],path.concat(k));
9
);
10
11
12
dfs(json,[i);
13
1
 
 
                         
                                

