JAVA数据结构与算法(三)树
定义
树(Tree)是n(n≥0)个结点的有限集T,并且当n>0时满足下列条件:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可以划分为m(m>0)个互不相交的有限集T1、T2 、…、Tm,每个集Ti(1≤i≤m)均为树,且称为树T的子树(SubTree)。
特别地,不含任何结点(即n=0)的树,称为空树。
树的术语
1.结点:包含了数据项和指向其他结点的分支
2.结点的度:结点所拥有的子树棵树。例如上图中,B的度为1,C的度为2,D的度为3
3.叶结点&终端结点:即度为0的结点,例如上图中,F,G,H,I,J均为叶结点
4.分支结点&非终端结点:除了叶结点以外的其他结点
5.子女结点:若结点x有子树,则子树的根结点即为结点x的子女。例如上图中,A有两个子女,分别为B,C
6.父结点:若结点x有子女,它即为子女的父结点
7.根结点:没有父结点的结点称为根结点
8.兄弟结点:同一父结点的子女互称为兄弟。例如上图中,D,E,F互为兄弟
9.祖先结点:从根结点到该结点所经历分支上的所有结点。例如上图中,G的祖先结点为A,B,D
10.子孙结点:某一结点的子女,以及这些子女的子女都是该结点的子孙。例如上图中,结点B的子孙D,G
11.结点所处的层次:从根到该结点所经路径上的分支条数.根结点在第1层,它的子女在第二层。树中任一12.结点的层次为它的父结点的层次加1。结点所处层次亦称为结点的深度
13.树的高度:叶结点的高度为1,非叶结点的高度等于它子女结点高度的最大值加1。该树的高度为4
14.树的度:树中结点的度的最大值。例如上图中该树的高度为3
树的存储与表示
顺序存储:将数据结构存储在固定的数组中,然在遍历速度上有一定的优势,但因所占空间比较大,是非主流二叉树。二叉树通常以链式存储
链式存储
常见的一些树的应用场景
1.xml,html等,那么编写这些东西的解析器的时候,不可避免用到树
2.路由协议就是使用了树的算法
3.mysql数据库索引
4.文件系统的目录结构
5.所以很多经典的AI算法其实都是树搜索,此外机器学习中的decision tree也是树结构
创建一颗树
class TreeNode{
int data;
TreeNode leftChild;
TreeNode rightChild;
}
省略get set方法
树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次,我们把这种对所有节点的访问称为遍历(traversal)。
那么树的两种重要的遍历模式是 深度优先遍历和广度优先遍历, 深度优先一般用 递归 ,广度优先一般用 队列 。一般情况下能用递归实现的算法大部分也能用堆栈来实现。
深度优先遍历
1.1 对于一颗二叉树,深度优先搜索(Depth First Search)是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
深度遍历有重要的三种方法。这三种方式常被用于访问树的节点,它们之间的不同在于访问每个节点的次序不同。这三种遍历分别叫做先序遍历(preorder),中序遍历(inorder)和后序遍历(postorder)
先序遍历
在先序遍历中,我们先访问根节点,然后递归使用先序遍历访问左子树,再递归使用先序遍历访问右子树
根节点->左子树->右子树
public static void preOrder(Node head){
if(head==null){
return;
}
System.out.println(head.getData()+" ");
preOrder(head.leftChild);
preOrder(head.rightChild);
}
中序遍历
在中序遍历中,我们递归使用中序遍历访问左子树,然后访问根节点,最后再递归使用中序遍历访问右子树
左子树->根节点->右子树
public static void inOrder(Node head){
if(head==null){
return;
}
preOrder(head.leftChild);
System.out.println(head.getData()+" ");
preOrder(head.rightChild);
}
后序遍历
在后序遍历中,我们先递归使用后序遍历访问左子树和右子树,最后访问根节点
左子树->右子树->根节点
public static void posOrder(Node head){
if(head==null){
return;
}
preOrder(head.leftChild);
preOrder(head.rightChild);
System.out.println(head.getData()+" ");
}
广度优先遍历
从树的root开始,从上到下从从左到右遍历整个树的节点
public void levelOrderTraversal(Node node){
if(node==null){
System.out.print("empty tree");
return;
}
ArrayList<Integer> lists=new ArrayList<Integer>();
Queue<Node> queue=new LinkedList<Node>();
queue.offer(node);
while(!queue.isEmpty()){
Node tree=queue.poll();
if(tree.leftChild!=null){
queue.offer(tree.leftChild);
}
if(tree.rightChild!=null){
queue.offer(tree.rightChild);
}
lists.add((Integer) tree.data);
}
}