二叉树的性质、表示方法和简单面试题

一、二叉树的一些概念

1.定义

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个由层次关系的集合。

2.树的特点

每个结点有零个或多个子结点。没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树。

3.节点的度

一个节点含有的子树个数称为该节点的度。

4.叶节点或终端节点

度为0的节点称为叶子节点。

5.兄弟节点

具有相同父节点的节点互称为兄弟节点。

6.树的度

一棵树中,最大节点的度称为树的度。

7.树的高度

树中节点的最大层次。

8.堂兄弟节点

双亲在同一层,但父节点不同的节点互称为堂兄弟节点。

9.节点的祖先

从根到该节点所经分支上的所有节点。

10.森林

由m(m>=0)棵互不相交的树的集合称为森林。

二、树的表示方法

1.孩子兄弟表示法

class Node{
     int value;//结点中的数据域
     Node firstChild;//保存第一个孩子结点
     Node nextChild;//保存同一层的下一个兄弟结点
}
   

2.双亲表示法

用一组连续的空间来存储树中的结点,在保存结点的同时附设一个指示器指示其双亲结点在表中的wei

class TNode{
    int data;//值
    int parent;//父结点的下标
}

3.孩子表示法

这种方法通常是把每个结点的孩子结点排列起来,构成一个单链表,称为孩子链表。n个结点共有n个孩子链表(叶子结点的孩子链表为空表),而n个结点的数据和n个孩子链表的头结点的头指针又组成一个顺序表。

//孩子链表结点的定义
class ChildNode{
    int child;//孩子结点在线性表中的位置
    ChildNode next;//下一个孩子结点
}

//顺序表结点的结构定义
class DataNode{
    int data;//结点的值
    ChildNode firstChild;//指向第一个孩子结点的引用
}

//树的定义
class ChildTree{
    DataNode nodes[MAX];//顺序表
    int root;//该树的根结点在线性表中的位置
    int num;//该树的结点个数
}

三、二叉树的概念和结构

1.概念

一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵被称为左子树和右子树的二叉树组成。

2.二叉树的特点

1)每个结点最多有两棵子树,即二叉树不存在度大于2的结点。

2)二叉树的子树有左右之分,其子树的次序不能颠倒。

3.二叉树的性质

性质1:在二叉树的第i层上至多有2^(i-1)个结点。

性质2:深度为k的二叉树至多有2^k-1(k>=1)个结点。

性质3:对任意一棵二叉树T,若终端结点数(叶子结点数)为n0,而度数为2的结点数为n2,则n0=n2+1

4.特殊的二叉树

1)满二叉树:一个二叉树,如果每一层的结点数都达到最大值,那么这个二叉树就是满二叉树。容易发现,满二叉树除叶子结点外,每个结点的度均为2.如果一个二叉树的层数为k,且结点总数是2^k-1,则它是满二叉树。

2)完全二叉树:对于深度为k,有n个结点的二叉树,当且仅当每一个结点都与深度为k的满二叉树中编号从1~n的结点一一对应时,称为完全二叉树。

由此可见,满二叉树一定是完全二叉树,而完全二叉树不一定是满二叉树。

3.完全二叉树的性质

性质1:具有n个结点的完全二叉树的深度为[log(n)]+1。(下取整)

性质2:对于具有n个结点的完全二叉树,如果按照从上到下和从左到右的顺序对二叉树中所有结点从1开始顺序编号,则对任意的序号为i的结点有

若i=1,则序号为i的结点是根结点,无双亲结点;若i>1,则序号为i的结点的双亲结点的标号为[i/2]。

若2i>n,则序号为i的结点无左孩子;若2i<=n,则序号为i的结点的左孩子结点的序号为2i。

若2i+1>n,则序号为i的结点无右孩子;若2i+1<=n,则序号为i的结点的右孩子结点为2i+1。

四、二叉树的存储结构

1.顺序存储

使用数组来存储,一般只适合完全二叉树(不会有空间的浪费)。二叉树顺序存储物理上是一个数组,逻辑上是一棵二叉树。现实中,我们通常把堆(一种二叉树)使用顺序结构的数组来存储。

2.链式存储

用链表来表示一棵二叉树。链式结构又分为二叉链和三叉链。

//二叉链-保存左右孩子
class  BinaryNode{
    int value;//值域
    Node left;//保存左孩子
    Node right;//保存右孩子
}


//三叉链-保存双亲结点和左右孩子
class BinaryTreeNode{
     int value;//值域
     Node parent;//保存双亲结点
     Node left;//保存左孩子结点
     Node right;//保存右孩子结点
}

五、二叉树的遍历、求结点个数、高度、查找结点、叶子结点个数、第k层的结点数

package com.xunpu.datastruct.tree;

public class TreeMethod {
    private static int count=0;
    private static class Node{
        char val;//值
        Node left;//左子树
        Node right;//右子树
        Node(char val){
            this.val=val;
        }
    }

    //前序遍历(根-左-右)
    //终止条件:根为空(遇到叶子节点)     先打印根的值,然后遍历左子树、右子树
    public static void preOrderTravel(Node root){
        if(root==null){
            return;
        }
        if(root!=null){
            System.out.print(root.val+" ");
        }
        preOrderTravel(root.left);
        preOrderTravel(root.right);
    }

    //中序遍历(左-根-右)
    //终止条件:根为空(遇到叶子节点)
    public static void inOrderTravel(Node root){
        if(root==null){
            return;
        }
        inOrderTravel(root.left);
        System.out.print(root.val+" ");
        inOrderTravel(root.right);
    }
    //后序遍历(左-右-根)
    //终止条件:根为空(遇到叶子节点)
    public static void postOrderTravel(Node root){
        if(root==null){
            return;
        }
        postOrderTravel(root.left);
        postOrderTravel(root.right);
        System.out.print(root.val+" ");
    }
    //求二叉树的结点个数(用遍历的思想解决  前序遍历)
    public static int getCounts(Node root){
        if(root!=null){
            getCounts(root.left);
            getCounts(root.right);
            count++;
        }
        return count;
    }
    //求二叉树的结点个数(子问题思想解决) 分别计算出左右子树的结点个数,然后再加1(根结点)
    //终止条件:根结点为空&遇到叶子结点
    private static int count(Node root){
        if(root==null){
            return 0;
        }else if(root.left==null&&root.right==null){
            return 1;//可选
        }else{
            return count(root.left)+count(root.right)+1;
        }
  }
  //求叶子结点个数
    //子问题思想  分别计算左子树、右子树的叶子结点
    //终止条件:根为空 & 遇到叶子结点
    public static int leafCount(Node root){
        if(root==null){
            return 0;
        }
        if(root.left==null&&root.right==null){
            return 1;
        }
        return leafCount(root.left)+leafCount(root.right);
    }
    //求树的高度
    //分别求出左右子树的高度,取较大值,最后返回较大值+1.
    public  static int height(Node root){
        if(root==null){
            return 0;
        }
        int leftHeight=height(root.left);
        int rightHeight=height(root.right);
        return (leftHeight>rightHeight?leftHeight
                :rightHeight)+1;
    }
    //求树的第k层的结点个数
    //其实就是求第k-1层左右子树之和。递归思想
    private static int kLevel(Node root,int k){
        if(root==null) {
            return 0;
        }else if(k==1){
            return 1;
        }else{
            return kLevel(root.left,k-1)+kLevel(root.right,k-1);
        }
    }
    //查找值为v的结点
    //遍历思想  先判断根结点是不是,再从左子树、右子树找。
    public  static Node find(Node root,char v){
        if(root==null){
            return null;
        }
        if(root.val==v){
            return root;
        }
        Node left=find(root.left,v);
        Node right=find(root.right,v);
        if(left!=null){
            return left;
        }else if(right!=null){
            return right;
        }
        return null;
    }
    private static Node createTree(){
        Node a=new Node('A');
        Node b=new Node('B');
        Node c=new Node('C');
        Node d=new Node('D');
        Node e=new Node('E');
        Node f=new Node('F');
        Node g=new Node('G');
        Node h=new Node('H');
        a.left=b;a.right=c;
        b.left=d;b.right=e;
        e.right=h;
        c.left=f;
        c.right=g;
        return a;
    }
    public static void main(String[] args) {
        Node root=createTree();
        System.out.print("前序遍历顺序为:");
        preOrderTravel(root);
        System.out.println();
        System.out.print("中序遍历顺序为:");
        inOrderTravel(root);
        System.out.println();
        System.out.print("后序遍历顺序为:");
        postOrderTravel(root);
        System.out.println();
        System.out.println("二叉树的结点个数为:"+count(root));
        System.out.println("二叉树的叶子结点个数为:"+leafCount(root));
        System.out.println("二叉树的高度为:"+height(root));
        System.out.println("值为‘F’的结点为:"+find(root,'F'));
    }
}

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值