二叉树的性质与基本应用

1.二叉树的基本性质

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

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

性质三:对任何一棵树的 T, 如果其终端结点数为 n0, 度为 2 的结点数为 n2, 则 n0 = n2 + 1;

性质四:具有 n 个结点的完全二叉树的深度为 【log2 n】+1;

性质五:如果对一棵有 n 个结点的完全二叉树的结点按层序(从上到下,从左到右)从1开始编号,则对任一编号为 i 的结点(1<= i <=n),有

(1)如果 i = 1, 则编号为 i 的结点是二叉树的根,无双亲;如果 i>1,则其双亲结点的编号是【i/2】;

(2)如果 2i > n,则编号为 i 的结点无左孩子;否则某左孩子的结点 LChild(i)的编号是 2i;

 

 

(3)如果 2i+1 > n,则编号为i的结点无右孩子;否则某右孩子的结点 RChild(i)的编号是 2i+1;

2.二叉树的储存结构

(1)顺序存储结构(只适合完全二叉树)

对于完全二叉树,只需要从根按照层序存储即可。根据完全二叉树的特性,将完全二叉树上编号为 i 的结点元素储存在一维数组中下标为 i-1 的分量中,对于一般的二叉树,没有结点的需填充空白字符。显然,这种储存方式只适用于完全二叉树,对于一般的二叉树将造成存储空间极大的浪费。

 

const MaxSize=100;//暂定二叉树中结点数最大值为100
typedef struct
{
   TElemType *data;//存储空间地址
   int nodenum     //二叉树中的结点数
}SqBiTree       //完全二叉树的顺序存储结构

 

(2)链式储存表示

 

typedef struct BiTNode
{
   TElemType data;
   struct BiTNode *lchild,*rchild; //左右孩子指针
}BiTree,*BiTree;

 

3、二叉树的遍历

(1)先序遍历

void Preorder(BiTree T, void(*visit)(BiTree))
{
   if(T) //T=NULL时,二叉树为空树,不做任何操作
   {
     visit(T);//通过函数指针*visit访问根节点,以便灵活完成相应的操作
     Preorder(T->lchild);//先序遍历左子树
     Preorder(T->rchild);//先序遍历右子树
   }
}

(2)中序遍历

 

void Inorder(BiTree T, void(*visit)(BiTree))
{
   if(T)
   {
     Inorder(T->lchild);//中序遍历左子树
     visit(T);访问结点
     Inorder(T->rchild);//中序遍历右子树
   }
}

 

(3)后序遍历

 

void Latorder(BiTree T, void(*visit)(BiTree))
{
   if(T)
   {
     Latorder(T->lchild);
     Latorder(T->rchild);
     visit(T);
   }
}

 

(4)非递归遍历(仅以中序遍历为例)

 

Typedef enum{Travel=1; Visit=0}TaskType;//Travel为 1 表示工作状态为遍历;Visit为 0 表示工作状态为访问
Typedef struct
{
   BiTree ptr; //指向二叉树结点的指针
   TaskType task;//任务的性质
}SElemType;//栈元素类型的定义

void Inorder(BiTree BT,void(*visit)(BiTree))
{
   InitStack(S);
   SElemType e;
   e.ptr=BT;e.task=Travek;//e为栈元素
   if(BT) Push(S,e); //布置初始任务
   while(!StackEmpty(S))
   {//每次处理一项任务
      Pop(S,e);
      if(e.task==Visit) visit(e.ptr);//处理访问任务
      else
      {
           if(e.ptr)
           {
               p=e.ptr;
               e.ptr=p->rchild;Push(S,e);  //最不迫切任务(遍历右子树)进栈
               e.ptr=p;e.task=Visit;Push(S,e); //处理访问任务的工作状态和结点指针进栈
               e.ptr=p->lchild;e.task=Travel;Push(S,e);//迫切任务(遍历左子树)进栈
           }
       }
   }

}

 

4、二叉树遍历的应用

(1)建立二叉树链表

以先序遍历的次序输入二叉树各节点,对于空结点,用‘#’表示(叶子节点后会有两个#号)

 

void CreatBiTree(BiTree &T)
{//在先序遍历二叉树的过程中输入结点字符建立二叉链表储存结构,指针 T 指向所建立的树的结点
   cin>>ch;
   if(ch=='#') T=NULL;//建空树
   else
   {
      T=new BiTree; //访问操作为生成根结点
      T->data=ch;
      CreatBiTree(T->lchild);//递归建立左子树
      CreatBiTree(T->rchild);//递归建立右子树
   }
}

 

(2)求二叉树的深度

二叉树的深度为二叉树中叶子节点所在层次的最大值

 

void BiTreeDepth(BiTree T,int h,int& depth)//先序遍历求二叉树深度
{//h为T指向的结点的所在层次, T指向二叉树的根,则 h 的初值为1,depth为当前求得的最大层次,其初值为 0
   if(T)
   {
      if(h>depth)depth=h;
      BiTreeDepth(T->lchild,h+1,depth);
      BiTreeDepth(T->rchild,h+1,depth);
   }
}

 

void BiTreeDepth(BiTree T)//后序遍历求二叉树深度
{
    if(T)
    {
         HL=BiTreeDepth(T->lchild);
         HR=NiTreeDepth(T->rchild);
         if(HL<HR) return HR+1;
         return HL+1;
    }
    else
       return 0;
}

 

(3)复制二叉树

 

BiTNode *GetTreeNode(TElemType item, BiTNode *lptr, BiTNode *rptr)
{//生成一个其元素值为item, 左指针为 lptr, 右指针为 rptr的结点
   T=new BiTNode; T->data=item;
   T->lchild=lptr; T->rchild=rptr;
   return T;
}

BiTree* CopyTree(BiTNode *T)
{//已知二叉树的根指针为T,本算法返回他的复制品的根指针
   if(!T)
        return NULL;//复制一颗空树
   if(T->lchild)
       newlptr=CopyTree(T->lchild);//复制左子树
   else  return newlptr=NULL;
   if(T->rchild)
        newrptr=CopyTree(T->rchild);//复制右子树
   else return newrptr=NULL;
   newNode=GetTreeNode(T->data,newlptr,newrptr);//生成根节点
   return newNode;
}

 

 

 

 

 


 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值