二叉树接口及其应用

 二叉树为连接于一对二叉树的一个外部节点或内部节点,这两棵二叉树分别称为这个节点的左子树和右子树。这个定义表明,二叉树本身就是一个抽象的数学概念。当我们制定计算机表示方式时,就是在制定一个具体实现。这种情形与用float表示实数,用int表示整数等没有区别。当我们绘制一颗树,根节点通过与左边的左子树以及右边的右子树连接,此时,就是在选择一种方便的具体表示方式。

我们开发那些应用和操作二叉树的程序时,最常用的具体表示法是内部节点带两个链接的结构(左链接与右链接)。这些结构与链表相似,但它们的每个节点有2个链接,而不是一个。空链接与外部节点对应。

定义二叉树的接口如下:
/* 节点结构定义*/
typedef struct node *link;
struct node{
    Item item;
    link l,r;
};

/* 常用操作定义*/
link NEW(Item item,link l,link r);
int count(link h);
int height(link h);
void preorderTraverse(link h,void (*visit)(link));
void printnode(char c,int h);
void show(link x,int h);

实现如下:
#include <stdio.h>
#include <stdlib.h>
#include "Tree.h"

/* construct a new node*/
link NEW(Item item,link l,link r)
{
    link x=(link)malloc(sizeof(*x));
    x->item=item;
    x->l=l;
    x->r=r;
    return x;
}

/* get the number of the nodes*/
int count(link h)
{
    if(h==NULL)
        return 0;
    return count(h->l)+count(h->r)+1;
}

/* get the height of the tree*/
int height(link h)
{
    int u,v;
    if(h==NULL)
        return -1;
    u=height(h->l);
    v=height(h->r);
    if(u>v)
        return u+1;
    else
        return v+1;
}

/* preorder traverse*/
void preorderTraverse(link h,void (*visit)(link))
{
    if(h==NULL)
        return;
    preorderTraverse(h->l,visit);
    preorderTraverse(h->r,visit);
}

/* print the tree node*/
void printnode(char c,int h)
{
    int i;
    for(i=0;i<h;i++)
        printf("  ");
    printf("%c/n",c);
}

/* print a subtree which root is x and in level h*/
void show(link x,int h)
{
    if(x==NULL)
    {
        printnode('*',h);
        return;
    }
    show(x->r,h+1);
    printnode(x->item,h);
    show(x->l,h+1);
}

二叉树的应用广泛,这里举几个例子。
构建锦标赛:
下面的程序将数组a[0],...,a[r]分成两部分a[0],...,a[m]和a[m+1],...,a[r],分别对这两部分构建锦标赛(按递归方式),在对整个数组生成一个锦标赛。
link max(Item a[],int l,int r)
{
    int m=(l+r)/2;                    // get the middle number
    Item u,v;
    link x=NEW(a[m],NULL,NULL);        // construct a new node
    if(l==r)                        // left equals to right means they are the same one
        return x;
    x->l=max(a,l,m);                // return max of the left part
    x->r=max(a,m+1,r);                // return max of the right part
    u=x->l->item;
    v=x->r->item;
    if(u>v)
        x->item=u;
    else
        x->item=v;
    //show(x,0);                        // print the tree
    printf("/n/n");
    return x;
}

构建解析树:
利用求前缀表达式值的同样策略,下面程序根据一个前缀表达式构建一颗解析树。为了简单起见,我们假定操作数为单个字符。每个递归调用创建一个新节点,它包含从输入(作为符号)获取的下一个字符。如果符号为操作数,则返回新节点;如果是一个运算符,则将左指针和右指针分别指向这两个参数(递归)生成的树。
char *a;int i;
typedef struct Tnode* link;
struct Tnode{
    char token;
    link l, r;
};

link NEW(char token,link l,link r)
{
    link x=(link)malloc(sizeof(*x));
    x->token=token;
    x->l=l;
    x->r=r;
    return x;
}

link parse()
{
    char t=a[i++];
    link x=NEW(t,NULL,NULL);
    if((t=='+')||(t=='*'))
    {
       x->l=parse();
       x->r=parse();
    }
    return x;
}

树的应用还有好多,关键在于我们要将问题抽象成数学模型,然后运用这些模型求解问题。当然,小问题可以不用编写程序来求解,但是面对大量复杂计算的时候我们就可以编制程序来求解它们。这时就要用到数据结构与算法的知识了。最好的情况是我们使用的语言足够灵活,并且能够处理各种各样的数据,比如大整数,浮点数,复数,等等。有些可以通过语言的其他方法实现,比如C中没有复数,我们可以通过定义复数类型并提供接口来实现复数的运算。总之,处理方法多种多样。在好的算法和数据结构的基础上,我们可以再对程序进行包装,做出人机界面,使程序更易于使用。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 二叉树节点ADT接口 */ package dsa; public interface BinTreePosition extends Position { //判断是否有父亲(为使代码描述简洁) public boolean hasParent(); //返回当前节点的父节点 public BinTreePosition getParent(); //设置当前节点的父节点 public void setParent(BinTreePosition p); //判断是否为叶子 public boolean isLeaf(); //判断是否为左孩子(为使代码描述简洁) public boolean isLChild(); //判断是否有左孩子(为使代码描述简洁) public boolean hasLChild(); //返回当前节点的左孩子 public BinTreePosition getLChild(); //设置当前节点的左孩子(注意:this.lChild和c.parent都不一定为空) public void setLChild(BinTreePosition c); //判断是否为右孩子(为使代码描述简洁) public boolean isRChild(); //判断是否有右孩子(为使代码描述简洁) public boolean hasRChild(); //返回当前节点的右孩子 public BinTreePosition getRChild(); //设置当前节点的右孩子(注意:this.rChild和c.parent都不一定为空) public void setRChild(BinTreePosition c); //返回当前节点后代元素的数目 public int getSize(); //在孩子发生变化后,更新当前节点及其祖先的规模 public void updateSize(); //返回当前节点的高度 public int getHeight(); //在孩子发生变化后,更新当前节点及其祖先的高度 public void updateHeight(); //返回当前节点的深度 public int getDepth(); //在父亲发生变化后,更新当前节点及其后代的深度 public void updateDepth(); //按照中序遍历的次序,找到当前节点的直接前驱 public BinTreePosition getPrev(); //按照中序遍历的次序,找到当前节点的直接后继 public BinTreePosition getSucc(); //断绝当前节点与其父亲的父子关系 //返回当前节点 public BinTreePosition secede(); //将节点c作为当前节点的左孩子 public BinTreePosition attachL(BinTreePosition c); //将节点c作为当前节点的右孩子 public BinTreePosition attachR(BinTreePosition c); //前序遍历 public Iterator elementsPreorder(); //中序遍历 public Iterator elementsInorder(); //后序遍历 public Iterator elementsPostorder(); //层次遍历 public Iterator elementsLevelorder(); }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值