二叉树是什么?
二叉树是一种非常重要的数据结构,很多数据结构都是基于二叉树的基础演变而来的。二叉树有两种,深度遍历和广度遍历:
深度遍历有前序、中序以及后序三种遍历方法,广度遍历即寻常所说的层次遍历。由于树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历,不仅容易理解,而且代码非常简洁。
广度遍历则需要其他数据结构的支撑,比方堆。所以,对一段代码而言,可读性往往比代码本身的效率要重要得多。
二叉树遍历的应用:
(1)前序遍历:可以用来实现目录结构的显示。
(2)中序遍历:可以用来做表达式树,在编译器底层实现的时候用户可以实现基本的加减乘除,比如 a*b+c。
(3)后序遍历可以用来实现计算目录内的文件占用的数据大小。
(4)层次遍历可用来解决计算机游戏中找寻路径的问题,如解谜宫。
四种基本的遍历思想为:
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:仅仅需按层次遍历就可以
新建节点
向上滑动阅览
public class Node {
private String data;
private Node leftNode;
private Node rightNode;
public Node(String data, Node leftNode, Node rightNode){
this.data = data;
this.leftNode = leftNode;
this.rightNode = rightNode;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node getLeftNode() {
return leftNode;
}
public void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
public Node getRightNode() {
return rightNode;
}
public void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
}
初始化界节点
向上滑动阅览
public Node init() {//注意必须逆序建立,先建立子节点,再逆序往上建立,因为非叶子结点会使用到下面的节点,而初始化是按顺序初始化的,不逆序建立会报错
Node H = new Node("H", null, null);
Node D = new Node("D", H, null);
Node E = new Node("E", null, null);
Node B = new Node("B", D, E);
Node F = new Node("F", null, null);
Node G = new Node("G", null, null);
Node C = new Node("C", F, G);
Node A = new Node("A", B, C);
return A; //返回根节点
}
1. 前序遍历
递归
向上滑动阅览
public void theFirstTraversal(Node root) { //先序遍历
printNode(root);
if (root.getLeftNode() != null) { //使用递归进行遍历左孩子
theFirstTraversal(root.getLeftNode());
}
if (root.getRightNode() != null) { //递归遍历右孩子
theFirstTraversal(root.getRightNode());
}
}
非递归
向上滑动阅览
public void theFirstTraversal_Stack(Node root) { //先序遍历
Stack stack = new Stack();
Node node = root;
while (node != null || stack.size() > 0) { //将所有左孩子压栈
if (node != null) { //压栈之前先访问
printNode(node);
stack.push(node);
node = node.getLeftNode();
} else {
node = stack.pop();
node = node.getRightNode();
}
}
}
2.中序遍历
递归
向上滑动阅览
public void theInOrderTraversal(Node root) { //中序遍历
if (root.getLeftNode() != null) {
theInOrderTraversal(root.getLeftNode());
}
printNode(root);
if (root.getRightNode() != null) {
theInOrderTraversal(root.getRightNode());
}
}
非递归
向上滑动阅览
public void theInOrderTraversal_Stack(Node root) { //中序遍历
Stack stack = new Stack();
Node node = root;
while (node != null || stack.size() > 0) {
if (node != null) {
stack.push(node); //直接压栈
node = node.getLeftNode();
} else {
node = stack.pop(); //出栈并访问
printNode(node);
node = node.getRightNode();
}
}
}
3.后序遍历
递归
向上滑动阅览
public void thePostOrderTraversal(Node root) { //后序遍历
if (root.getLeftNode() != null) {
thePostOrderTraversal(root.getLeftNode());
}
if(root.getRightNode() != null) {
thePostOrderTraversal(root.getRightNode());
}
printNode(root);
}
非递归
向上滑动阅览
public void thePostOrderTraversal_Stack(Node root) { //后序遍历
Stack stack = new Stack();
Stack output = new Stack();//构造一个中间栈来存储逆后序遍历的结果
Node node = root;
while (node != null || stack.size() > 0) {
if (node != null) {
output.push(node);
stack.push(node);
node = node.getRightNode();
} else {
node = stack.pop();
node = node.getLeftNode();
}
}
// System.out.println(output.size());
while (output.size() > 0) {
printNode(output.pop());
}
}
4. 层次遍历
向上滑动阅览
//层次遍历
public static void theLeverTraversal(Node root) {
if (root == null) {
return;
}
//新建一个队列,LinkedList实现了Quene接口,可以直接当作队列来用
LinkedList queue = new LinkedList();
Node current; //当前节点
queue.offer(root);//根节点入队列
while (!queue.isEmpty()) {
current = queue.poll(); //取出队列的头节点
System.out.print(current.getData() + " ");//输出队列的头节点的值
if (current.getLeftNode() != null) {
queue.offer(current.getLeftNode()); //如果当前节点的左节点不为空,则左节点入队列
}
if (current.getRightNode() != null) {
queue.offer(current.getRightNode()); //如果当前节点的右节点不为空,则右节点入队列
}
}
}