# 创建二叉树数据结构
# 广义表(generalized lists)
使用来表示二叉树非常方便,假如我们有这么一个二叉树:
它可以表示为L = (A (B (C, D), E ( , F) ) ),直观地表达了树中各个节点之间的关系。
主要思路:
逐个获取广义表字符串中除空格之外的每个字符,遇到左括号就标记START_LEFT_CHILD,遇到逗号就标记START_RIGHT_CHILD,遇到右括号就返回到父节点层次。当遇到字母时,就创建一个节点,并与父节点进行关联。
遇到左括号时,下一步就要处理左子节点了,此时将当前新创建的节点入栈作为栈顶元素(第一次为空),它是下一个新创建节点的父节点。
遇到字母A时,创建一个节点对象作为根节点;之后再遇到字母时,如果当前标记为START_LEFT_CHILD,就作为父节点的左子节点,如果当前标记为START_RIGHT_CHILD,那就作为父节点的右子节点。
遇到右括号时,返回父节点层次,此时相应元素出栈,栈顶指针退回一位。
继续重复上几个步骤,最终返回根节点。
//二叉树节点结构
function BinTreeNode (val) {
this.val = val;
this.left = null;
this.right = null;
}
//通过广义表创建二叉树
function createBinTreeByGLists (gLists) {
//根节点和当前节点
var rootNode = null, currNode = null;
//数组作为栈结构,top为栈顶指针,模拟入栈出栈
var stack = [], top = -1;
//flag标识当前要解析的类型
var flag = 0;
var START_LEFT_CHILD = 1, START_RIGHT_CHILD = 2;
//字符串当前索引
var index = 0;
while (index < gLists.length) {
//获取广义表字符串当前要解析的字符
var c = gLists.charAt(index++);
switch (c) {
//遇到'('时,开始解析左子节点,栈顶指针递增一位,当前节点入栈作为新的父节点
case '(':
flag = START_LEFT_CHILD;
stack[++top] = currNode;
break;
//遇到',' 开始解析右子节点
case ',':
flag = START_RIGHT_CHILD;
break;
//遇到')'时,栈顶指针递减一位,返回到父节点层次
case ')':
top--;
break;
//忽略空格
case ' ':
break;
//处理节点
default:
//创建新节点
currNode = new BinTreeNode(c);
//第一个节点作为根节点
if (rootNode === null) {
rootNode = currNode;
} else {
//当前栈顶存放父节点,根据flag处理与父节点的关系
switch (flag) {
case START_LEFT_CHILD:
stack[top].left = currNode;
break;
case START_RIGHT_CHILD:
stack[top].right = currNode;
break;
}
}
}
}
//返回树的根节点
return rootNode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 完全二叉树模型
完全二叉树的模型空数据的地方用#表示,如下图所示我们称之为扩展二叉树,我们取其前序遍历的序列 AB#D##C##
//前序遍历得到的字符串
function createBitree (string) {
let strArr = string.split('');
function BiNode (val) {
this.val = val;
this.left = null;
this.right = null;
}
var newTree = new BiNode('#');
// 前序递归创建,可调整中序后序
function createNode (biTree) {
if (strArr.length == 0) return;
let str = strArr.shift();
if (str == '#') return;
biTree.val = str;
if (strArr[0] != '#') {
biTree.left = new BiNode('#')
}
createNode(biTree.left);
if (strArr[0] != '#') {
biTree.right = new BiNode('#')
}
createNode(biTree.right);
}
createNode(newTree)
return newTree
}
createBitree('AB#D##C#')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 二叉树遍历方法
# 前序遍历
先遍历根结点,然后左子树,再右子树
function preTraverse(biTree) {
if (biTree == null) return;
console.log(biTree.data);
preTraverse(biTree.lChild);
preTraverse(biTree.rChild);
}
1
2
3
4
5
6
2
3
4
5
6
# 中序遍历
先遍历左子树,然后根结点,再右子树
function centerTraverse(biTree) {
if (biTree == null) return;
centerTraverse(biTree.lChild);
console.log(biTree.data);
centerTraverse(biTree.rChild);
}
1
2
3
4
5
6
2
3
4
5
6
# 后序遍历
先遍历左子树,然后右子树,再根结点
function lastTraverse(biTree) {
if (biTree == null) return;
lastTraverse(biTree.lChild);
lastTraverse(biTree.rChild);
console.log(biTree.data);
}
1
2
3
4
5
6
2
3
4
5
6
# 层次遍历
按照二叉树层级遍历
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrderBottom = function (root) {
/**
* 栈方法
*/
// const stack = [{ index: 0, node: root }]
// const res = []
// while (stack.length > 0) {
// const { index, node } = stack.pop()
// if (!node) continue;
// res[index]
// ? (res[index].push(node.val))
// : (res[index] = [node.val])
// node.right && stack.push({ index: index + 1, node: node.right })
// node.left && stack.push({ index: index + 1, node: node.left })
// }
// return res.reverse()
/**
* 队列方法
*/
const queue = [root]
let index = 0
const res = []
while (queue.length > 0) {
const len = queue.length
for (let i = 0; i < len; i++) {
const node = queue.shift()
if (!node) continue
res[index]
? (res[index].push(node.val))
: (res[index] = [node.val])
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
index++
}
return res.reverse()
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 判断镜像对称二叉树
// 方法一 递归
const isSymmetric = (root) => {
const check = (left, right) => {
if (left == null && right == null) { // 两个子树都为null,是对称的
return true;
}
if (left && right) { // 两个子树都存在,则需要:root值相同,且他们的子树也满足镜像
return left.val == right.val && check(left.left, right.right) && check(left.right, right.left);
}
return false; // 一个子树存在一个不存在,肯定不对称
};
if (root == null) { // 如果传入的root就是null,对称
return true;
}
return check(root.left, root.right); // 否则,判断它的左右子树是否满足对称
};
// 方法二 BFS 层次
const isSymmetric = (root) => {
var q = [root, root], n, m
while (q.length) {
n = q.shift(), m = q.shift()
if (!m && !n) continue
if (!m || !n || m.val !== n.val) return false
q.push(n.left, m.right, n.right, m.left)
}
return true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
← 算法总结