话不多说,直接上代码,注释也比较详尽。
1、数据结构:
public class BinarySearchTree {
private Node root;
public BinarySearchTree() {
root = null;
}
private static class Node {
int item;
Node left;
Node right;
Node(Node left, int item, Node right) {
this.item = item;
this.right = right;
this.left = left;
}
}
……
2、插入新节点-递归方式
/**
* 插入新节点
*
* @param currentRoot:当前(子)树的根节点
* @param newNode:待插入的新节点
*/
private void insertNode(Node currentRoot, Node newNode) {
if (currentRoot == null || newNode == null) {
throw new NullPointerException();
}
if (newNode.item < currentRoot.item) {
if (currentRoot.left == null) {
//如果左子树为空说明当前节点就是叶子节点,直接把新节点挂到这个位置上并结束
currentRoot.left = newNode;
return;
}
// 添加到左子树去
insertNode(currentRoot.left, newNode);
} else if (newNode.item > currentRoot.item) {
if (currentRoot.right == null) {
currentRoot.right = newNode;
}
// 添加到右子树去
insertNode(currentRoot.right, newNode);
} else { // 新节点的 value 跟当前节点值相等
// do nothing
}
}
/**
* 插入节点-递归的方式
*
* @param newItem
*/
public void putByRecursion(int newItem) {
Node newNode = new Node(null, newItem, null);
if (root == null) {
// 为空树则直接把新节点作为 root
root = newNode;
return;
}
Node current = root;
// 递归的方式插入新节点
insertNode(current, newNode);
}
/**
* 插入新值
*
* @param newItem
*/
public void put(int newItem) {
putByRecursion(newItem);
}
3、深度遍历-递归方式
/**
* 深度遍历-递归方式
*
* @param root
* @return
*/
public List<Integer> depthTraverseByRecursion(Node root) {
if (root == null) {
// 空树直接返回一个空 list
return new ArrayList<Integer>() {
};
}
List<Integer> resultList = new ArrayList<>();
// 1、前序遍历(先访问父节点,再以此访问左子树和右子树)
// 先访问父节点
resultList.add(root.item);
// System.out.println(root.item);
// 再遍历左子树
resultList.addAll(depthTraverseByRecursion(root.left));
// 再遍历右子树
resultList.addAll(depthTraverseByRecursion(root.right));
return resultList;
}
4、 深度遍历-非递归方式(栈的方式)
/**
* 深度遍历-非递归方式(仿递归的函数调用栈,直接用栈存储遍历值再后入先出达到深度遍历效果)
* 通过画图方式更容易理解
*
* @param root
* @return
*/
public List<Integer> depthTraverseByLoop(Node root) {
if (root == null) {
// 空树直接返回一个空 list
return new ArrayList<Integer>() {
};
}
Node curr = root;
List<Integer> resultList = new ArrayList<>();
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
// 先把当前节点(父节点)出栈
Node popNode = stack.pop();
resultList.add(popNode.item);
// 然后再把当前节点的右节点和左节点依次入栈
// 先把 right 节点入栈
if (popNode.right != null) {
stack.push(popNode.right);
}
// left 也一并入栈
if (popNode.left != null) {
stack.push(popNode.left);
}
}
return resultList;
}
5、测试代码:
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
bst.put(3);
bst.put(1);
bst.put(2);
bst.put(7);
bst.put(0);
bst.put(5);
// System.out.println(bst.root.item);
List<Integer> traverseList = bst.depthTraverseByLoop(bst.root);
for (Integer integer : traverseList) {
System.out.println(integer);
}
}
}
6、完整代码:
package tree;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* @Description:构建二叉树并进行深度遍历(使用递归方式+非递归方式)
* @author: Victor Lv
* @date: 2020/12/24 10:46
*/
public class BinarySearchTree {
private Node root;
public BinarySearchTree() {
root = null;
}
private static class Node {
int item;
Node left;
Node right;
Node(Node left, int item, Node right) {
this.item = item;
this.right = right;
this.left = left;
}
}
/**
* 插入新节点
*
* @param currentRoot:当前(子)树的根节点
* @param newNode:待插入的新节点
*/
private void insertNode(Node currentRoot, Node newNode) {
if (currentRoot == null || newNode == null) {
throw new NullPointerException();
}
if (newNode.item < currentRoot.item) {
if (currentRoot.left == null) {
//如果左子树为空说明当前节点就是叶子节点,直接把新节点挂到这个位置上并结束
currentRoot.left = newNode;
return;
}
// 添加到左子树去
insertNode(currentRoot.left, newNode);
} else if (newNode.item > currentRoot.item) {
if (currentRoot.right == null) {
currentRoot.right = newNode;
}
// 添加到右子树去
insertNode(currentRoot.right, newNode);
} else { // 新节点的 value 跟当前节点值相等
// do nothing
}
}
/**
* 插入节点-循环的方式
*
* @param newItem
*/
public void putByLoop(int newItem) {
Node newNode = new Node(null, newItem, null);
if (root == null) {
// 为空树则直接把新节点作为 root
root = newNode;
return;
}
Node current = root;
// 1、循环的方式插入新节点
while (current != null) {
if (newItem < current.item) {
if (current.left == null) {
//如果左子树为空,就直接把新节点挂到这个位置上并结束循环
current.left = newNode;
break;
}
// 添加到左子树去
current = current.left;
} else if (newItem > current.item) {
if (current.right == null) {
current.right = newNode;
break;
}
// 添加到右子树去
current = current.right;
}
}
}
/**
* 插入节点-递归的方式
*
* @param newItem
*/
public void putByRecursion(int newItem) {
Node newNode = new Node(null, newItem, null);
if (root == null) {
// 为空树则直接把新节点作为 root
root = newNode;
return;
}
Node current = root;
// 递归的方式插入新节点
insertNode(current, newNode);
}
/**
* 插入新值
*
* @param newItem
*/
public void put(int newItem) {
putByRecursion(newItem);
}
/**
* 深度遍历-递归方式
*
* @param root
* @return
*/
public List<Integer> depthTraverseByRecursion(Node root) {
if (root == null) {
// 空树直接返回一个空 list
return new ArrayList<Integer>() {
};
}
List<Integer> resultList = new ArrayList<>();
// 1、前序遍历(先访问父节点,再以此访问左子树和右子树)
// 先访问父节点
resultList.add(root.item);
// System.out.println(root.item);
// 再遍历左子树
resultList.addAll(depthTraverseByRecursion(root.left));
// 再遍历右子树
resultList.addAll(depthTraverseByRecursion(root.right));
return resultList;
}
/**
* 深度遍历-非递归方式(仿递归的函数调用栈,直接用栈存储遍历值再后入先出达到深度遍历效果)
* 通过画图方式更容易理解
*
* @param root
* @return
*/
public List<Integer> depthTraverseByLoop(Node root) {
if (root == null) {
// 空树直接返回一个空 list
return new ArrayList<Integer>() {
};
}
Node curr = root;
List<Integer> resultList = new ArrayList<>();
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
// 先把当前节点(父节点)出栈
Node popNode = stack.pop();
resultList.add(popNode.item);
// 然后再把当前节点的右节点和左节点依次入栈
// 先把 right 节点入栈
if (popNode.right != null) {
stack.push(popNode.right);
}
// left 也一并入栈
if (popNode.left != null) {
stack.push(popNode.left);
}
}
return resultList;
}
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
bst.put(3);
bst.put(1);
bst.put(2);
bst.put(7);
bst.put(0);
bst.put(5);
// System.out.println(bst.root.item);
List<Integer> traverseList = bst.depthTraverseByLoop(bst.root);
for (Integer integer : traverseList) {
System.out.println(integer);
}
}
}