一、二分搜索树便利的介绍
在我们实现二分搜索树中,我们学习了好多的知识,二分搜索树当中,我觉得最重要的是实现树的便利和查找操作。
实现二分搜索树的便利,我们有两种不同的实现方式。
1、第一种,递归实现。
(1)、先序便利,我们可以通过先输出根节点,然后便利左子树,最后便利右子树。
(2)、中序便利,我们可以先便利左子树,然后输出根节点,最后输出右子树。
(3)、后续便利,我们是可以先便利左子树,然后便利右子树,最后便利根节点。
下面 是它们的实现代码。
/**
* 前序遍历
*/
public void preOrder() {
preOrder(root);
}
public void preOrder(Node node) { // 当前节点 左 右
if (node == null) {
return;
}
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
/**
* 中序便利
*/
public void inOrder() {
inOrder(root);
}
private void inOrder(Node node) {
if (node == null) return;
inOrder(node.left); //左 当前 右
System.out.println(node.e);
inOrder(node.right);
}
/**
* 后序便利
*/
public void postOrder() {
postOrder(root);
}
//左子树 右子树 当前节点
private void postOrder(Node node) {
if (node == null) return;
postOrder(node.left); //左 右 当前
postOrder(node.right);
System.out.println(node.e);
}
2、非递归实现
1、前序便利的基本思想,我们可以利用栈来实现
第一步,首先把树的根元素,加入我们的栈中。
第二步,然后判断栈是不是空、然后弹出栈顶元素,并打印输出。
第三步,判断弹出的右孩子是不是空,不为null,就压入栈顶元素。
第四步,判断弹出的左孩子是不是空,不为空,就压入栈顶元素。
public void preOrderDq() {
if (root == null) {
return;
}
Stack<Node> stack = new Stack<Node>();
stack.push(root);
while (!stack.isEmpty()) {
Node node = stack.pop();
System.out.println(node.e);
//如果右子树不为null 压人栈中。
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
}
2、中序便利的基本思想,我们可以利用栈来实现
第一步,首先把树的根元素,加入我们的栈中,然后把树的根节点的左子树,复制给当前节点。
第二步,判断栈是不是空,或者说当前元素是不是空,只要是栈不为null,或者当前元素不为null。我们进入循环。
第三步,判断当前元素是不是空,如果不空,我们就把它压入栈顶。当前元素,就变成它的左孩子。
如果为null 的话,弹出栈顶元素,然后,当前元素变成它的右孩子。继续执行第二步。
基本思想是,先把左子树,全部压入栈中,然后弹出来,并打印。然后判断右子树是不是存在,存在就也压入栈中。
/**
* 非递归实现中序便利。
* 我们主要是先便利左子树,依次压入栈中。
* 然后,弹出栈顶的元素,并打印出来。
* 然后,判断弹出元素的右子树为不为null。
* 不为null ,就压人栈中,又判断该元素的左子树为不为null。
*/
public void dgInOrder() {
if (root == null) return;
Stack<Node> stack = new Stack<Node>();
stack.push(root);
Node cur = root.left;
while (!stack.isEmpty() || cur != null) { //如果左孩子不为null 或者栈也不为 null
if (cur != null) { //如果 cur 为 null ,必须栈顶还有元素。
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop(); //弹出一个元素
System.out.println(cur.e);
cur = cur.right;
}
}
stack.push(root);
}
3、后序便利的基本思想,我们可以利用栈来实现
我的基本实现方式和前序基本一样。我们只是把 前序便利,访问根节点 然后左子树,最后右节点。改成了 先根节点 ,然后右节点,最后左节点。然后我们利用栈,把顺序反过来,就变成后续便利,先左子树,然后右子树,最后根节点。
//1、非递归实现后续便利。
//基本思想:左 右 根 我们可以用两个栈来实现。
//利用 根右左的思想实现。
public void DgpostOrder() {
Stack<Node> stack = new Stack<Node>();
Stack<Node> stack2 = new Stack<Node>();
if (root == null) {
return;
}
Node node = root;
stack.push(node); //栈为null
while (!stack.isEmpty()) {
node = stack.pop();
stack2.push(node);
if (node.left != null) {
stack.push(node.left);
}
if (node.right != null) {
stack.push(node.right);
}
}
while (!stack2.isEmpty()) {
System.out.println(stack2.pop());
}
}
3、层次便利的实现
我们是利用队列来实现的,基本实现思路。
第一步,我们把根 元素入队列。
第二步,我们判断队列是不是空,队列不为空,我们就弹出队首元素,
第三步,然后判断队首元素的左孩子为不为空,不为空就压入队列中。
第四步,然后判断队首元素的右孩子为不为空,不为空就压入队列中。依次第二步。
// 二分搜索树的层序遍历
public void levelOrder(){
if(root == null)
return;
Queue<Node> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()){
Node cur = q.remove();
System.out.println(cur.e);
if(cur.left != null)
q.add(cur.left);
if(cur.right != null)
q.add(cur.right);
}
}