树的基本概念
如上图所示:
根节点:没有父节点的节点,如E
父节点:A是B的父节点
子节点:B是A的子节点
兄弟节点:拥有同一父节点的节点,如BCD是兄弟节点
叶节点:没有子节点的节点,如G、H、I、J、K、L
高度:节点到叶子节点的最长路径,如E节点的高度是3,A节点的高度是2,B节点是1,G节点是0
深度:根节点到此节点所经历的边的个数,如E的深度是0,A的深度是1
层:节点的深度+1
树的高度:根节点的高度
二叉树
每个节点最多有两个叉,分别是左子节点和右子节点。
满二叉树:除了叶子结点之外,每个节点都有两个节点的树。
完全二叉树:叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大。
满二叉树可以看做是一个特殊的完全二叉树。
二叉树如何表示?
1、链式存储法
每个节点都有三个字段,data存储数据,left表示节点的左子节点的指针,right表示节点的右子节点的指针。
2、基于数组的顺序存储法
把根节点存储在数组下标为i=1的位置,左子节点在数组中的下标就是2i=2的位置,右子节点在数组中的下标就是2i+1=3的位置。
这是在完全二叉树的情况下,可以很好的利用数组的空间,但若不是完全二叉树甚至于比较极端的情况,数据都分布在根节点的左子节点树或者右子节点树,那么数组就会出现大量未被使用的元素,造成空间浪费。
二叉树遍历
public class BinaryTreeNode {
private int data;
private BinaryTreeNode leftNode;
private BinaryTreeNode rightNode;
public BinaryTreeNode(int data, BinaryTreeNode leftNode, BinaryTreeNode rightNode){
this.data = data;
this.leftNode = leftNode;
this.rightNode = rightNode;
}
public BinaryTreeNode(){}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public BinaryTreeNode getLeftNode() {
return leftNode;
}
public void setLeftNode(BinaryTreeNode leftNode) {
this.leftNode = leftNode;
}
public BinaryTreeNode getRightNode() {
return rightNode;
}
public void setRightNode(BinaryTreeNode rightNode) {
this.rightNode = rightNode;
}
}
前序遍历
打印顺序是:根节点->左子节点->右子节点
/**
* 前序遍历
*
* @param root
*/
public static void preOrder(BinaryTreeNode root) {
if (root == null) return;
System.out.print(root.getData() + " ");
preOrder(root.getLeftNode());
preOrder(root.getRightNode());
}
public static void main(String[] args) {
BinaryTreeNode node10 = new BinaryTreeNode(10, null, null);
BinaryTreeNode node8 = new BinaryTreeNode(8, null, null);
BinaryTreeNode node9 = new BinaryTreeNode(9, null, node10);
BinaryTreeNode node4 = new BinaryTreeNode(4, null, null);
BinaryTreeNode node5 = new BinaryTreeNode(5, node8, node9);
BinaryTreeNode node6 = new BinaryTreeNode(6, null, null);
BinaryTreeNode node7 = new BinaryTreeNode(7, null, null);
BinaryTreeNode node2 = new BinaryTreeNode(2, node4, node5);
BinaryTreeNode node3 = new BinaryTreeNode(3, node6, node7);
BinaryTreeNode node1 = new BinaryTreeNode(1, node2, node3);
preOrder(node1);
}
运行结果:
1 2 4 5 8 9 10 3 6 7
中序遍历
打印顺序是:左子节点->根节点->右子节点
/**
* 中序遍历
* @param
*/
public static void inOrder(BinaryTreeNode root){
if (root == null) return;
inOrder(root.getLeftNode());
System.out.print(root.getData() + " ");
inOrder(root.getRightNode());
}
public static void main(String[] args) {
BinaryTreeNode node10 = new BinaryTreeNode(10, null, null);
BinaryTreeNode node8 = new BinaryTreeNode(8, null, null);
BinaryTreeNode node9 = new BinaryTreeNode(9, null, node10);
BinaryTreeNode node4 = new BinaryTreeNode(4, null, null);
BinaryTreeNode node5 = new BinaryTreeNode(5, node8, node9);
BinaryTreeNode node6 = new BinaryTreeNode(6, null, null);
BinaryTreeNode node7 = new BinaryTreeNode(7, null, null);
BinaryTreeNode node2 = new BinaryTreeNode(2, node4, node5);
BinaryTreeNode node3 = new BinaryTreeNode(3, node6, node7);
BinaryTreeNode node1 = new BinaryTreeNode(1, node2, node3);
inOrder(node1);
}
运行结果:
4 2 8 5 9 10 1 6 3 7
后序遍历
打印顺序是:左子节点->右子节点->根节点
/**
* 后序遍历
* @param
*/
public static void postOrder(BinaryTreeNode root){
if (root == null) return;
postOrder(root.getLeftNode());
postOrder(root.getRightNode());
System.out.print(root.getData() + " ");
}
public static void main(String[] args) {
BinaryTreeNode node10 = new BinaryTreeNode(10, null, null);
BinaryTreeNode node8 = new BinaryTreeNode(8, null, null);
BinaryTreeNode node9 = new BinaryTreeNode(9, null, node10);
BinaryTreeNode node4 = new BinaryTreeNode(4, null, null);
BinaryTreeNode node5 = new BinaryTreeNode(5, node8, node9);
BinaryTreeNode node6 = new BinaryTreeNode(6, null, null);
BinaryTreeNode node7 = new BinaryTreeNode(7, null, null);
BinaryTreeNode node2 = new BinaryTreeNode(2, node4, node5);
BinaryTreeNode node3 = new BinaryTreeNode(3, node6, node7);
BinaryTreeNode node1 = new BinaryTreeNode(1, node2, node3);
postOrder(node1);
}
运行结果:
4 8 10 9 5 2 6 7 3 1
时间复杂度
与节点个数n成正比,所以时间复杂度是O(n)。
原文:https://gper.club/articles/7e7e7f7ff7g54gcdg67