【数据结构】树与二叉树、完全二叉树

版权声明:本文为博主原创文章,未经博主允许不得转载。 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+n21n2+1
  • 性质2 i2i1(i1)

  • 性质3 k2k1(k1)
  • 性质4:完全二叉树的编号关系
    • 假设对各节点从上到下,从左到右依次编号1~n,则对任意节点a编号i,有
      i1a[i2]2ina2i2ina2i+1na2i+12i+1na
  • 性质5 Catalan()nh(n)h(n)=Cn2nn+1

  • 性质6 n(n1)[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);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/LoveHYZH/article/details/79049871