C语言之实现二叉树结构-诺禾

二叉查找树是一种结合了二分查找策略的链接结构。二叉树的每个节点都包含一个项和两个指向其他节点(称为子节点)的指针。图17.12演示了二叉查找树中的节点是如何链接的。二叉树中的每个节点都包含两个子节点——左节点和右节点,其顺序按照如下规定确定:左节点的项在父节点的项前面,右节点的项在父节点的项后面。这种关系存在于每个有子节点的节点中。进一步而言,所有可以追溯其祖先回到一个父节点的左节点的项,都在该父节点项的前面;所有以一个父节点的右节点为祖先的项,都在该父节点项的后面。图17.12中的树以这种方式存储单词。有趣的是,与植物学的树相反,该树的顶部被称为根(root)。树具有分层组织,所以以这种方式存储的数据也以等级或层次组织。一般而言,每级都有上一级和下一级。如果二叉树是满的,那么每一级的节点数都是上一级节点数的两倍。

C语言之实现二叉树结构
A binary search tree storing words

二叉查找树中的每个节点是其后代节点的根,该节点与其后代节点构成称了一个子树(subtree)。如上图所示,包含单词fate、carpet和llama的节点构成了整个二叉树的左子树,而单词voyage是style-plenum-voyage子树的右子树。 假设要在二叉树中查找一个项(即目标项)。如果目标项在根节点项的前面,则只需查找左子树;如果目标项在根节点项的后面,则只需查找右子树。因此,每次比较就排除半个树。假设查找左子树,这意味着目标项与左子节点项比较。如果目标项在左子节点项的前面,则只需查找其后代节点的左半部分,以此类推。与二分查找类似,每次比较都能排除一半的可能匹配项。 我们用这种方法来查找puppy是否在图17.12的二叉树中。比较puppy和melon(根节点项),如果puppy在该树中,一定在右子树中。因此,在右子树中比较puppy和style,发现puppy在style前面,所以必须链接到其左节点。然后发现该节点是plenum,在puppy前面。现在要向下链接到该节点的右子节点,但是没有右子节点了。所以经过3次比较后发现puppy不在该树中。 二叉查找树在链式结构中结合了二分查找的效率。但是,这样编程的代价是构建一个二叉树比创建一个链表更复杂。下面我们在下一个ADT项目中创建一个二叉树。

1 二叉树ADT
和前面一样,先从概括地定义二叉树开始。该定义假设树不包含相同的项。许多操作与链表相同,区别在于数据层次的安排。下面建立一个非正式的树定义:

C语言之实现二叉树结构
2 二叉查找树接口

原则上,可以用多种方法实现二叉查找树,甚至可以通过操控数组下标用数组来实现。但是,实现二叉查找树最直接的方法是通过指针动态分配链式节点。因此我们这样定义:

typedef SOMETHING Item;

typedef struct trnode
{
Item item;
struct trnode * left;
struct trnode * right;
} Trn;

typedef struct tree
{
Trnode * root;
int size;
} Tree;
每个节点包含一个项、一个指向左子节点的指针和一个指向右子节点的指针。可以把Tree定义为指向Trnode的指针类型,因为只需要知道根节点的位置就可访问整个树。然而,使用有成员大小的结构能很方便地记录树的大小。 我们要开发一个维护Nerfville宠物俱乐部的花名册,每一项都包含宠物名和宠物的种类。程序tree.h就是该花名册的接口。我们把树的大小限制为10,较小的树便于在树已满时测试程序的行为是否正确。当然,你也可以把MAXITEMS设置为更大的值。

The tree.h Interface Header File

/* tree.h – binary search tree /
/
no duplicate items are allowed in this tree /
#ifndef TREE_H
#define TREE_H
#include <stdbool.h>

/
redefine Item as appropriate /
typedef struct item
{
char petname[20];
char petkind[20];
} Item;

#define MAXITEMS 10

typedef struct trnode
{
Item item;
struct trnode * left; /
pointer to right branch /
struct trnode * right; /
pointer to left branch /
} Trnode;

typedef struct tree
{
Trnode * root; /
pointer to root of tree /
int size; /
number of items in tree /
} Tree;

/
function prototypes /

/
operation: initialize a tree to empty /
/
preconditions: ptree points to a tree /
/
postconditions: the tree is initialized to empty /
void InitializeTree(Tree * ptree);

/
operation: determine if tree is empty /
/
preconditions: ptree points to a tree /
/
postconditions: function returns true if tree is /
/
empty and returns false otherwise /
bool TreeIsEmpty(const Tree * ptree);

/
operation: determine if tree is full /
/
preconditions: ptree points to a tree /
/
postconditions: function returns true if tree is /
/
full and returns false otherwise /
bool TreeIsFull(const Tree * ptree);

/
operation: determine number of items in tree /
/
preconditions: ptree points to a tree /
/
postconditions: function returns number of items in /
/
tree /
int TreeItemCount(const Tree * ptree);

/
operation: add an item to a tree /
/
preconditions: pi is address of item to be added /
/
ptree points to an initialized tree /
/
postconditions: if possible, function adds item to /
/
tree and returns true; otherwise, /
/
the function returns false /
bool AddItem(const Item * pi, Tree * ptree);

/
operation: find an item in a tree /
/
preconditions: pi points to an item /
/
ptree points to an initialized tree /
/
postconditions: function returns true if item is in /
/
tree and returns false otherwise /
bool InTree(const Item * pi, const Tree * ptree);

/
operation: delete an item from a tree /
/
preconditions: pi is address of item to be deleted /
/
ptree points to an initialized tree /
/
postconditions: if possible, function deletes item /
/
from tree and returns true; /
/
otherwise the function returns false*/
bool DeleteItem(const Item * pi, Tree * ptree);

/* operation: apply a function to each item in /
/
the tree /
/
preconditions: ptree points to a tree /
/
pfun points to a function that takes*/
/* an Item argument and has no return /
/
value /
/
postcondition: the function pointed to by pfun is /
/
executed once for each item in tree /
void Traverse (const Tree * ptree, void (
pfun)(Item item));

/* operation: delete everything from a tree /
/
preconditions: ptree points to an initialized tree /
/
postconditions: tree is empty */
void DeleteAll(Tree * ptree);

#endif
3 二叉树的实现
接下来,我们要实现tree.h中的每个函数。InitializeTree()、EmptyTree()、FullTree()和TreeItems()函数都很简单,与链表ADT、队列ADT类似,所以下面着重讲解其他函数。

1.添加项

在树中添加一个项,首先要检查该树是否有空间放得下一个项。由于我们定义二叉树时规定其中的项不能重复,所以接下来要检查树中是否有该项。通过这两步检查后,便可创建一个新节点,把待添加项拷贝到该节点中,并设置节点的左指针和右指针都为NULL。这表明该节点没有子节点。然后,更新Tree结构的size成员,统计新增了一项。接下来,必须找出应该把这个新节点放在树中的哪个位置。如果树为空,则应设置根节点指针指向该新节点。否则,遍历树找到合适的位置放置该节点。AddItem()函数就根据这个思路来实现,并把一些工作交给几个尚未定义的函数:SeekItem()、MakeNode()和AddNode()。

bool AddItem(const Item * pi, Tree * ptree)
{
Trnode * new_node;

if (Tree

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值