概念引用自:https://blog.csdn.net/qq_35896304/article/details/90268316
树的定义:
1.树包含n(n ≥≥ 0 )个节点,n = 0时称为空树。
2.在树的结构关系中,有且仅有一个节点没有前趋节点,这个节点称为树的根节点。
3.除根节点外,树中其他的节点有且仅有一个前趋节点,但可以有很多后继节点。如图,A为根节点。
树的基本术语:
1.结点的度:每个节点具有的子树的个数(后继节点的个数)称为该节点的度;A 的度为3,B的度为0。(节点的度 = 节点的孩子节点 = 节点的后继节点)
2.树的度:树中所有节点的度的最大值;图中树的度为3。(树的度 取 所有节点度的最大值)
3.分枝节点:度大于0的节点。(有分枝【孩子节点,后继节点,度】的节点)
4.叶子节点:度为0的节点;如B、H、F、G。
5.孩子节点:一个节点的后继称为该节点的孩子节点;B为A的孩子节点。
6.父亲节点:一个节点的前趋称为该节点的父亲节点;A为B的父亲节点。
7.子孙节点:一个节点的所有子树中的节点称为该节点的子孙节点。(例如C的子孙节点是E、F、H)
8.祖先节点:从树根节点到达某个节点的路径上所通过的所有节点称为该节点的祖先节点。(H的祖先节点是E、C、A)
9.兄弟节点:具有相同父亲节点的节点;B、C、D为兄弟节点。
10.节点的层数:从上到下,根为第一层。(H在第四层)
11.树的深度:树中节点的最大层数称为树的深度或高度;图中树深为4。
二叉树的定义:二叉树是指树的度为2的有序树。左边的为左子树,右边的为右子树。
二叉树常被用于实现二叉查找树和二叉堆。
二叉树的性质:
1.二叉树上叶子节点数等于度为2的节点数加1。(上面树的度[子孙节点]为2的几点有7个,叶子节点有8个)
2.二叉树上第i层上最多有 2^(i-1) 个节点(i ≥ 1)。(上面的树第2层有 2个节点)
3.深度为h的二叉树最多 2^h - 1 有个节点。
下面是二叉树的一些基本算法:
//二叉树节点
class Node{
char data;
Node left;
Node right;
Node(char data) {
this.data = data;
}
}
public class Tree {
//使用前序遍历建立二叉树
//String s = "ABCD#EF#G#######";
public static Node createBtree(String s,int index) {
Node root = null;
if(index >= s.length()) return root;
char c = s.charAt(index-1);
if('#' == c) {
return root;
}else {
//节点的顺序存储结构: 双亲节点的索引为 i 左孩子的索引为 2*i 右孩子的索引为 2*i + 1
root = new Node(c);
root.left = createBtree(s,index*2);
root.right = createBtree(s,index*2+1);
return root;
}
}
/**
* 先序遍历:
* 1.遍历根节点
* 2.遍历左子树
* 3.遍历右子树
*/
//前序遍历-递归
public static void preOrder(Node root) {
if(root != null) {
System.out.print(root.data+" ");
preOrder(root.left);
preOrder(root.right);
}
}
//前序遍历-非递归1
public static void preOrderNoRecursive1(Node root) {
Stack<Node> st = new Stack<Node>();
if(root != null) {
st.push(root);
while(!st.isEmpty()) {
Node node = st.pop();
System.out.print(node.data+" "); //先访问根节点
if(node.right != null) { //借助栈的特点,先进栈右节点
st.push(node.right);
}
if(node.left != null) { //再进栈左节点,循环后,达到根节点,左节点,右节点的访问顺序
st.push(node.left);
}
}
}else {
System.out.print("请不要拿一颗空树来调戏我!!!");
}
System.out.println();
}
//前序遍历-非递归2
public static void preOrderNoRecursive2(Node root) {
Stack<Node> st = new Stack<Node>();
if(root != null) {
Node p = root;
while(!st.isEmpty() || p != null) {
while(p != null) { //先进栈左节点,直到最左下的那个节点
System.out.print(p.data+" "); //边进栈边访问
st.push(p);
p = p.left;
}
if(!st.isEmpty()) {
p = st.pop(); //弹出栈顶节点,处理右子树
p = p.right;
}
}
}else {
System.out.print("请不要拿一颗空树来调戏我!!!");
}
System.out.println();
}
//中序遍历-递归
public static void midOrder(Node root) {
if(root != null) {
midOrder(root.left);
System.out.print(root.data+" ");
midOrder(root.right);
}
}
//中序遍历-非递归
public static void midOrderNoRecursive(Node root) {
Stack<Node> st = new Stack<Node>();
if(root != null) {
Node p = root;
while(!st.isEmpty() || p != null) {
while(p != null) {
st.push(p);
p = p.left;
}
if(!st.isEmpty()) {
p = st.pop();
System.out.print(p.data+" ");
p = p.right;
}
}
}else {
System.out.print("请不要拿一颗空树来调戏我!!!");
}
System.out.println();
}
//后序遍历-递归
public static void endOrder(Node root) {
if(root != null) {
endOrder(root.left);
endOrder(root.right);
System.out.print(root.data+" ");
}
}
//后序遍历-非递归
public static void endOrderNoRecursive(Node root) {
Stack<Node> st = new Stack<Node>();
if(root != null) {
Node p = root;
do {
//遍历p节点的左孩子进栈
while(p != null) {
st.push(p);
p = p.left;
}
//此时栈顶节点没有左孩子或者左子树已遍历过
boolean flag = true; //判断当前是否在处理栈顶节点
Node r = null; // 指向刚刚被访问过的节点,初始时为null
while(!st.isEmpty() && flag) {
p = st.peek();//获取栈顶节点
if(p.right == r) { //如果栈顶节点的右孩子就是r节点,就访问p节点
System.out.print(p.data+" ");
p = st.pop();
r = p; //指向刚刚被访问过的节点
}else {
p = p.right; //转向处理右子树
flag = false; //当前不是栈顶节点,而是栈顶节点的右孩子
}
}
}while(!st.isEmpty());
}else {
System.out.print("请不要拿一颗空树来调戏我!!!");
}
System.out.println();
}
/**
* 层次遍历-递归
* @param root 根节点
* @param a 存储结果的数组 长度为满二叉树节点的个数+1
* @param index 索引 初始为1
*/
public static void levelOrder(Node root, char[] a, int index) {
if(root.left != null) {
levelOrder(root.left, a, index*2);
}
if(root.right != null) {
levelOrder(root.right, a, index*2+1);
}
//存储节点位置
a[index] = root.data;
}
//层次遍历-非递归
public static void levelOrderNoRecursive(Node root) {
Queue<Node> qu = new LinkedList<Node>();
qu.add(root);
while(!qu.isEmpty()) {
Node node = qu.poll();
System.out.print(node.data+" ");
if(node.left != null) {
qu.add(node.left);
}
if(node.right != null) {
qu.add(node.right);
}
}
}
//获取二叉树的最大高度
public static int BtreeHeight(Node root) {
return root == null ? 0 : Math.max(BtreeHeight(root.left), BtreeHeight(root.right)) + 1;
}
//快速幂计算a^b
public static int quick(int a, int b) {
int res = 1;
while(b != 0) {
if(b%2 == 1)
res *= a;
a *= a;
b /= 2;
}
return res;
}
/**
* 计算二叉树某个节点x的层次
* @param root 根节点
* @param x 要查找的节点值
* @param h 高度 初始为 1
* @return 节点值x所在的层次 h 0:未找到或者空树
*/
public static int level(Node root, char x, int h) {
if(root == null) {
return 0;
}else if(root.data == x){
return h;
}else {
int l = level(root.left, x, h+1); //查找左子树
return l != 0 ? l : level(root.right, x, h+1); //如果在左子树查找到就返回,否则查找右子树
}
}
/**
* 基于先序遍历计算二叉树中第k层的节点个数
* @param root 根节点引用
* @param h 层次 初始为1
* @param k 第k层
* @param n 第k层节点有n个,n为全局变量
*/
public static int n = 0;
public static void lnodenum(Node root, int h, int k) {
if(root == null) {
return;
}else {
if(h == k) n++;
else if(h < k){
lnodenum(root.left, h+1, k);
lnodenum(root.right, h+1, k);
}
}
}
/**
* 判断两颗二叉树是否相似
* 相似:树结构相同,但是值不同而已
* @param t1
* @param t2
* @return
*/
public static boolean like(Node t1, Node t2) {
if(t1 == null && t2 == null)
return true;
else if(t1 == null || t2 == null)
return false;
else {
return like(t1.left, t2.left) && like(t1.right, t2.right);
}
}
/**
* 输出节点值为x的所有祖先节点
* @param root
* @param x
* @return true:root节点是祖先节点 false:不是祖先节点
*/
public static boolean ancestor(Node root, char x) {
if(root == null) {
return false;
}else if(root.left != null && root.left.data == x ||
root.right != null && root.right.data == x) {
System.out.print(root.data+" ");
return true;
}else if(ancestor(root.left, x) || ancestor(root.right, x)) {
System.out.print(root.data+" ");
return true;
}else {
return false;
}
}
public static void main(String[] args) {
String s = "ABCD#EF#G#######";
Node root = createBtree(s,1); //创建二叉树
System.out.println("前序遍历-递归:");
preOrder(root);
System.out.println();
System.out.println("前序遍历-非递归1:");
preOrderNoRecursive1(root);
System.out.println("前序遍历-非递归2:");
preOrderNoRecursive2(root);
System.out.println();
System.out.println("中序遍历-递归:");
midOrder(root);
System.out.println();
System.out.println("中序遍历-非递归:");
midOrderNoRecursive(root);
System.out.println();
System.out.println("后序遍历-递归:");
endOrder(root);
System.out.println();
System.out.println("后序遍历-非递归:");
endOrderNoRecursive(root);
System.out.println();
System.out.println("层次遍历-递归:");
int height = BtreeHeight(root); //计算二叉树的最大高度
int max = quick(2,height); //根据二叉树最大高度,计算出最多节点的个数,即满二叉树的节点个数
char[] a = new char[max+1]; //存储遍历结果
levelOrder(root,a,1); //结果存储在a数组里
System.out.println(Arrays.toString(a));
System.out.println("层次遍历-非递归:");
levelOrderNoRecursive(root);
System.out.println();
System.out.println();
int level = level(root,'G',1);
System.out.println("节点E所在的层次为:"+level);
int k = 3;
lnodenum(root,1,k);
System.out.println("第"+k+"层的节点个数为: "+n);
boolean b = like(root,root);
System.out.println("两个相同的二叉树是否相似: "+b);
char c = 'G';
System.out.print(c+"节点的祖先节点: ");
ancestor(root,c);
System.out.println();
}
}
测试结果: