二叉树接口及其应用

 二叉树为连接于一对二叉树的一个外部节点或内部节点,这两棵二叉树分别称为这个节点的左子树和右子树。这个定义表明,二叉树本身就是一个抽象的数学概念。当我们制定计算机表示方式时,就是在制定一个具体实现。这种情形与用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中没有复数,我们可以通过定义复数类型并提供接口来实现复数的运算。总之,处理方法多种多样。在好的算法和数据结构的基础上,我们可以再对程序进行包装,做出人机界面,使程序更易于使用。
阅读更多
想对作者说点什么? 我来说一句

二叉树及其应用

2014年12月08日 73KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭