数据结构之---树(二)

二叉树是一棵每个节点都不能有多余2个儿子的树,它的一个重要的性质是平均二叉树的深度要比N小得多,而二叉查找树的深度的平均值是O(logN)。二叉树的定义比较简单

/*二叉树有两个儿子,所以可以直接由根节点指向它们即可*/
typedef struct tree_node *ptrnode;
typedef struct tree_node *tree;
struct tree_node
{
int element;
ptrnode lchild;
ptrnode rchild;
}/*二叉树结构清晰,分别指向左右孩子即可,当然也可用数组实现,不过指针比较清晰,我采取指针*/
二叉树有很多应用,这里举两个很常见的例子,第一个是表达式树,表达式树是叶节点为操作数,其余节点为操作符的一种树。对其进行中序遍历可以得到一个标准的表达式。(联想:可以用来制作计算器),由于中缀表达式可以很方便的转化为后缀表达式,所以这里讨论一下根据后缀表达式构造一颗表达式树。它的思想是,对输入序列进行扫描,如果为操作数,则进栈,为操作符则弹出两个元素,使它们指向这个新进的元素,同时该元素进栈。

/*其策略为如果为操作数,则进栈,如果为操作符,则弹出两个元素,指向该操作符,将该操作符进栈*/
tree create_expression_tree()
{
char in;
stack store;/*这是一个树节点指针类型的栈,用于存储*/
while((in=getchar())!=EOF)
{
ptrnode new_node=create_tree_node(in);/*创建一个节点*/
if in is operand
push(new_node,store);
if in is operator
{
new_node->rchild=pop(store);
new_node->lchild=pop(store);
push(new_node,store);
}
}
}
/*至此一棵表达式树构造完成*/
还有一个应用的例子是非常出名的二叉查找树,它在查找中很有应用。一棵二叉查找树的平均深度为logN。二叉查找树是左子树的关键字小于该节点,右子树的关键字大于该节点的树,很明显这是一个递归的定义。

对于二叉树进行的操作有创建一棵空树,查找某个元素,查找最大值,查找最小值,删除,插入等。

创建一颗空树make_empty:

tree make_empty(tree T)
{
if(T!=NULL)
{
make_empty(T->lchild);
make_empty(T->rchild);
free(T);
}
return NULL;
}

查找 find:
ptrnode find(int x,tree T)
{
if(T==NULL)
return NULL;
if(x<T->element)
return find(T->lchild);
if(x>T->element)
return find(T->rchild);
else
return T;
}

查找最小find_min:

ptrnode find_min(tree T)
{
if(T==NULL)
return NULL;
else
if(T->lchild==NULL)
return T;
else
return find_min(T->lchild);
}

查找最大find_max:

ptrnode find_max(tree T)
{
if(T==NULL)
return NULL;
else
if(T->rchild==NULL)
return T;
else
return find_max(T->rchild);
}
/*当然完全不用使用递归,使用递归是为了让结构更加清晰*/

插入操作:

tree insert(int x,tree T)
{
if(T==NULL)
{
T=(tree)malloc(sizeof(struct tree_node));
T->element=x;
T->lchild=NULL;
T->rchild=NULL;
}
else
if(x<T->element)
T->lchild=insert(x,T->lchild);
else
if(x>T->element)
T->rchild=insert(x,T->rchild);
return T;
}
/*注意到如果x相等的话,我们什么也不做*/

最后是删除操作,几乎在所有结构中删除都是比较麻烦的,注意到删除一个元素后,可以用它右子树的最小节点来填充(或者左子树的最大),然后递归删除即可

tree delete(int x,tree T)
{
if(T==NULL)
Error("not found");
else
if(x<T->element)
T->lchild=delete(x,T->lchild);
else
if(x>T->element)
T->rchild=delete(x,T->rchild);
else/*找到了*/
{
if(T->lchild&&T->rchild)/*拥有两个孩子*/
{
ptrnode temp;
temp=find_min(T->rchild);
T->element=temp->element;
T->rchild=delete(temp->element,T->rchild);
}
else/*只有一个孩子*/
{
if(T->lchild==NULL)
T=T->rchild;
if(T->rchild==NULL)
T=T->lchild;
}
}
return T;
}
/*注意到为了保持程序易读,后面进行了两次遍历,效率并不高。当然这很容易改进*/

树还有很多像什么AVL树,B树,伸展树等等。这里推荐一本数据结构的书籍,严的那本很多人推荐,我也看过,不过个人觉得他的讲法并不是很好,分析也不够透彻。推荐一本老外的吧:data structures and algorithom analysis in c。不得不说,老外很多书都很经典的,这本也是很多一线高校的教材,英语好的话可以挑战一下原版。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值