树结构
一、树结构中常见术语
(1)结点的度(Degree):结点的子树个数。
(2)树的度:树的所有结点中最大的度数。
(3)叶结点(Leaf):度为0的结点。
(4)父结点(Parent):有子树的结点是其子树的根结点的父结点。
(5)子节点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点。
(6)兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点。
(7)路径和路径长度:从结点n1到nk的路径为一个结点序列。路径所包含的边的个数为路径的长度。
(8)祖先结点(Ancestor):沿树根到某一结点路径上的所有结点都是这个结点的祖先结点。
(9)子孙结点(Descendant):某一结点的子树中所有结点是这个结点的子孙。
(10)结点的层次(Level):规定根结点在1层,其他任一结点的层数是其父节点的层数加1。
(11)树的深度(Depth):树中所有结点中的最大层次是这棵树的深度。
二、认识常见的树结构
满二叉树
定义:指的是树的每一层从左到右依次遍满的。
它的节点个数为:2^n-1 (n代表层数)
完全二叉树
定义:树的叶子节点在最后一层,或者是倒数第二层,所有的叶子节点都向左边聚拢,如果跳过左边的那么就不是一颗完全二叉树了。
平衡二叉树
定义:假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过1。
二叉排序树
定义:一颗空树,或者满足以下条件的树,每一个节点的左孩子小于当前节点的值,每一个节点的右孩子大于当前节点的值。
三、树结构中的相关性质
-
性质1:一颗深度为n二叉树上节点最多为2^n -1 个 (n代表树的层数)
-
性质2:一颗二叉树第n层的节点最多右 2^(n-1) 个
-
性质3:n个节点的二叉树,他的高度最少为log2为底(n+1) 层
四、树的遍历方式
- 树的遍历方式无非就是三种 前序遍历、中序遍历、后序遍历
//以这个作为树的节点类,接下来的操作都是针对这个节点来操作的
public static class TreeNode{
Integer val;
TreeNode left;
TreeNode right;
public TreeNode(Integer val) {
this.val = val;
}
}
前序遍历
递归方式
遍历方式首先打印头节点、然后打印左节点、然后打印右节点
- coding
public static void preOrder(TreeNode node){
if (node == null){
return;
}
System.out.print(node.val + " ");
if (node.left!=null){
preOrder(node.left);
}
if (node.right!=null){
preOrder(node.right);
}
}
使用栈进行遍历
- 思路:
- 1、首先申请一个栈 记作stack , 首先将头节点放进去
- 2、从栈中弹出刚才的节点 , 记作cur,然后打印cur的值
- 3、如果cur.right 不为空,则压入
- 4、如果cur.left 不为空,则压入 , 一定是先压入右节点,然后在压入左节点
public static void proOrderStack(TreeNode head){
if (head == null){
return;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(head);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
System.out.print(cur.val + " ");
if (cur.right!=null){
stack.push(cur.right);
}
if (cur.left!=null){
stack.push(cur.left);
}
}
}
中序遍历
递归方式
遍历方式首先打印左节点、然后打印头节点、然后打印右节点
- coding
public static void inOrder(TreeNode node){
if (node == null){
return;
}
if (node.left!=null){
inOrder(node.left);
}
System.out.print(node.val + " ");
if (node.right!=null){
inOrder(node.right);
}
}
使用栈进行遍历
- 实现思路:
- 申请一个栈 stack,使用cur 保存以下头节点
- 首先将cur压入栈对于cur节点为头节点的整颗子树来说,依次把左侧边界节点入栈,不停的cur = cur.left
- 发现cur为空的时候,从栈中弹出来一个元素并打印,并记录,并且让cur = node.right
- 只有当stack为空或者cur == null 的时候结束
public static void inOrderStack(TreeNode head){
if (head == null){
return;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = head;
while(!stack.isEmpty() || cur!=null){
if (cur!=null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
System.out.print(cur.val + " ");
cur = cur.right;
}
}
}
后序遍历的方式
递归方式
遍历方式先打印左节点、然后打印右节点、然后打印根节点
- coding
public static void postOrder(TreeNode node){
if (node == null){
return;
}
if (node.left!=null){
postOrder(node.left);
}
if (node.right!=null){
postOrder(node.right);
}
System.out.print(node.val + " ");
}
使用栈进行遍历
- 思路
- 申请两个栈 分别为 stack1、stack2
- 首先是将头节点压入到stack1中,然后弹出stack1,放入到stack2里,记作cur,如果cur的左节点不为空,压入左节点,其次是右节点不为空压入右节点。然后依次重复
- 然后stack2不为空,则弹出打印,一直到stack2为空为止。
public static void postOrderStack(TreeNode head){
if (head == null) return;
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(head);
while(!stack1.isEmpty()){
TreeNode cur = stack1.pop();
stack2.push(cur);
if (cur.left!=null){
stack1.push(cur.left);
}
if (cur.right!=null){
stack1.push(cur.right);
}
}
while(!stack2.isEmpty()){
System.out.print(stack2.pop().val + " ");
}
}
二叉树按照层次遍历
遍历思路:使用队列
1、首先创建一个队列Queue,并将头节点放进来
2、当队列不为空的情况下,从队列中取出来一个元素,并且判断这个元素是否存在左节点和右节点,如果说存在先将左节点加入到队列,然后将右节点加入到队列中去。 一次循环,一直到这个队列为空 停。
public static void level(TreeNode head){
if (head == null){
return;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(head);
while(!queue.isEmpty()){
TreeNode cur = queue.poll();
System.out.print(cur.val + " ");
if (cur.left!=null){
queue.add(cur.left);
}
if (cur.right!=null){
queue.add(cur.right);
}
}
}
------》》》将会持续更新