版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LoveHYZH/article/details/79049871
1.什么是树
- 典型的非线性结构,最开始有一个根节点其有若干子节点,每个子节点又有若干子节点
2.树的基本术语
- 根节点:没有双亲,一棵树最对一个根节点,如A节点
- 边:节点间的链接
- 叶子节点:没有孩子的节点,如K、L、M、N、O节点
- 兄弟节点:拥有相同双亲的节点,如B、C、D、E节点
- 节点的度:节点拥有的子树个数或者分支个数,例如A有四棵子树,度就为4
- 树的度:树中各节点度的最大值
- 层次:从根开始,根为第一层,根的孩子为第二层,根的孩子的孩子为第三层,以此类推
- 树的高度(或深度):树中节点的最大层次
- 节点的深度和高度:节点的深度从根节点算起,根节点的深度为1;根节点的深度是从最底层的叶子节点算起的,最底层叶子节点的高度为1
3.二叉树
- 如果一棵树中的每个节点有0、1或者2个子节点,那么这棵树称为二叉树
- 空树也是一棵有效的二叉树
4.二叉树的类型
- 满二叉树:二叉树中所有叶子节点在同一层,也是完全二叉树
- 完全二叉树:除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干节点
5.二叉树的性质
性质1:非空二叉树叶子结点数等于双分支节点数加1
- 证明:设
n0=叶子结点数,n1=单分支节点数,n2=双分支节点数总结点数=n0+n1+n2
由于二叉树除了根节点,每个节点都有一个分支指向它,因此
总分支数n1+2n2n0===总结点数−1n0+n1+n2−1n2+1
- 证明:设
性质2:
二叉树的第i层最多有2i−1(i≥1)个节点 - 性质3:
高度为k的二叉树最多有2k−1(k≥1)个节点 - 性质4:完全二叉树的编号关系
- 假设对各节点从上到下,从左到右依次编号1~n,则对任意节点a编号i,有
如果i≠1,则a双亲节点的编号为[i2](高斯函数)如果2i≤n,则a的左孩子编号为2i;如果2i≥n,则a无左孩子如果2i+1≤n,则a的右孩子编号为2i+1;如果2i+1≥n,则a无右孩子
- 假设对各节点从上到下,从左到右依次编号1~n,则对任意节点a编号i,有
性质5:
Catalan()函数,给定n个节点,能够成h(n)种不同的二叉树,h(n)=Cn2nn+1 性质6:
具有n(n≥1)个节点的完全二叉树的高度(或深度为)[log2n]+1
6.二叉树的结构
public class Tree{
private static class BTNode{
public int data;
public BTNode lchild;
public BTNode rchild;
}
private BTNode root;
}
7.二叉树的遍历
★前序遍历
//递归
public void preOrder(BTNode p){
if(p != null){
visit(p);
preOrder(p.lchild);
preOrder(p.rchild);
}
}
------------------------------------------------
//非递归Ⅰ
public void preOrder(BTNode p){
if (p == null) {
return;
}
Stack<BTNode> stack = new Stack<BTNode>();
stack.push(p);
while(!stack.isEmpty()){
p = stack.pop();
visit(p);
if(p.rchild != null){
stack.push(p.rchild);
}
if(p.lchild != null){
stack.push(p.lchild);
}
}
}
------------------------------------------------
//非递归Ⅱ
public void preOrder(BTNode p){
if (p == null) {
return;
}
Stack<BTNode> stack = new Stack<BTNode>();
while(true){
while(p != null){
visit(p);
stack.push(p);
p = p.lchild;
}
if(stack.isEmpty()){
return;
}
p = stack.pop();
p = p.rchild;
}
}
★中序遍历
//递归
public void inOrder(BTNode p){
if(p != null){
inOrder(p.lchild);
visit(p);
inOrder(p.rchild);
}
}
-------------------------------------------------
//非递归
public void inOrder(BTNode p){
if (p == null) {
return;
}
Stack<BTNode> stack = new Stack<BTNode>();
while(true){
while (p != null) {
stack.push(p);
p = p.lchild;
}
if (stack.isEmpty()) {
return;
}
p = stack.pop();
visit(p);
p = p.rchild;
}
}
★后序遍历
//递归
public void postOrder(BTNode p){
postOrder(p.lchild);
postOrder(p.rchild);
visit(p);
}
--------------------------------------------------
//非递归
/**
* 后序遍历:左孩子-->右孩子-->节点
* 后序遍历逆序:节点-->右孩子-->左孩子
* 有没有感到很熟悉,对,前序遍历
* 仿照前序遍历,把右孩子当左孩子,左孩子当右孩子
* 但是是把visit方法换成进入另一个栈
* 最后对另一个栈执行出栈,再visit
*/
public void postOrder(BTNode p){
if(p == null){
return;
}
Stack<BTNode> stack1 = new Stack<BTNode>();
Stack<BTNode> stack2 = new Stack<BTNode>();
stack1.push(p);
while(!stack1.isEmpty()){
p = stack1.pop();
stack2.push(p);
if(p.lchild != null){
stack.push(p.lchild);
}
if(p.rchild != null){
stack.push(p.rchild);
}
}
while(!stack2.isEmpty()){
visit(stack2.pop());
}
}
★层次遍历
public void levelOrder(BTNode p){
if(p == null){
return;
}
Queue<BTNode> queue = new Queue<BTNode>();
queue.offer(p);
while (!queue.isEmpty()) {
p = queue.poll();
visit(p);
if(p.lchild != null){
queue.offer(p.lchild);
}
if(p.rchild != null){
queue.offer(p.rchild);
}
}
}