从本篇起,我会尽我所能阐释那些复杂的数据结构,包括树与图,同时,从本篇起,会穿插地说一说其他的算法,例如排序,搜索,贪心等等,取决于我的思考程度以及leetcode做题程度(做的比较慢,总是想不出或总是debug失败。。。)。这一篇将会介绍树这一数据结构,本篇是基础篇,随后会有一篇树相关的算法。由于树中大量的运用到递归,总想不明白,目前leetcode只写出了很少的相关题。那么闲话少叙,现在开始。这里的树,仅限于二叉树。
基础代码实现
基础树的定义
首先我们定义二叉树的节点。跟其他数据结构的节点相比,二叉树的节点应包括他本身的值,以及指向该节点左子树以及右子树的指针。
1 2 3 4 5
| function Node(data, left, right) { this.data = data; this.left = left; this.right = right; }
|
然后,我们开始定义二叉树本身的内容,首先,指定根节点,然后定义相关方法。这里将整个问题进行简单化,在节点插入过程中自动通过数值的大小,自动将其变为二叉搜索树。
1 2 3 4 5 6 7 8 9 10 11
| function BST() { this.root = null; this.length = 0; this.insert = insert; this.inOrder = inOrder; this.preOrder = preOrder; this.postOrder = postOrder; }
|
具体方法的实现
根据二叉树的定义“二叉树是n(n>=0)个有限结点构成的集合。n=0称为空二叉树;n>0的二叉树由一个根结点和两互不相交的,分别称为左子树和右子树的二叉树构成”可知,二叉树的遍历可以通过递归得到:只要所遍历的节点不为空,即可递归地查看它地左右两个子树,从而遍历整个二叉树。而对于已有的前序、中续以及后续三种遍历方法来说,所改变的是遍历左子树,查看节点自身以及遍历右子树,这三个子模块的顺序。
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
| function inOrder(node) { if (node != null) { inOrder(node.left); print(node.show() + " "); inOrder(node.right); } }
function preOrder(node) { if (node != null) { print(node.show() + " "); preOrder(node.left); preOrder(node.right); } }
function postOrder(node) { if (node != null) { postOrder(node.left); postOrder(node.right); print(node.show() + " "); } }
|
以下就是构造一颗搜索二叉树的插入节点的方法,大体思路就是不断的遍历节点,小了往左走,大了往右走,直到走到尽头,插进去,完事。
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
| function insert(data) { let newNode = new Node(data, null, null); if (this.root == null) { this.root = newNode; this.length ++; } else { let current = this.root; let parent; while (true) { parent = current; if (data < current.data) { current = current.left; if (current == null) { parent.left = newNode; this.length ++; break; } } else { current = current.right; if (current == null) { parent.right = newNode; this.length ++; break; } } } } }
|