您的位置:首页 > 其它

【算法导论】第12章二叉查找树

2012-06-19 15:40 429 查看
1、问题引入

  查找树是一种数据结构,它支持多种动态集合操作,包括构造、查找、插入、删除、寻找最小值、寻找最大值等,其中构造过程主要采用不断插入值来完成。

  二叉查找树中的关键字存储方式满足以下性质:设x为二叉查找树中的一个节点,如果y是x的左子树中的一个节点,则y->data < x->data;如果y是x的右子树中的一个节点,则y->data > x->data。

  二叉查找树上执行的基本操作的时间与树的高度成正比,对于一棵含n个节点的完全二叉树,这些操作的最坏情况运行时间为o(lgn)。同样的,如果树是含有n个节点的线性链,则这些操作的最坏时间为o(n)。

2、数据结构

  二叉查找树是按照二叉树结构来组织的,这样的树可以采用数组来表示,也可以采用链表结构来表示,不过数组表示没有链表结构简单明了,这里采用链表结构来表示,每一个节点就表示一个对象,节点中包含data数据部分、left指针(指向左儿子)、right指针(指向右儿子),如果某个节点的儿子节点不存在,则相应的儿子节点为NULL。

  定义为:typedef struct treenode
      {
         elemType data;
        struct treenode *left;
        struct treenode *right;
      }tree;

3、基本算法

3.1 构造二叉查找树算法

//构造二叉查找树
tree *makeTree(tree *p)
{
scanf("%d",&k);
while(k!=-1)//以输入-1表示构造结束
{
p=insertTreeNode(p,k);//通过插入节点方式构造
scanf("%d",&k);
}
return(p);//得到树p
}


3.2 中序遍历算法

void printTree(tree *t)
{
if(t)
{
printTree(t->left);
printf("%d ",t->data);
printTree(t->right);
}
}


3.3 查找一个给定的关键字所在节点算法

tree *searchTreeNode(tree *p,elemType k)
{
if(p==NULL) || k=p->data
return p;
if(k<p->data)
return searchTreeNode(p->left,k);
else
return searchTreeNode(p->right,k):
}


3.4 查找最大和最小关键字元素

//在二叉查找树中查找最小节点
tree *findMinTreeNode(tree *t)
{
if(t==NULL) //树为空
{
printf("error!!");
return NULL;
}
while(t->left)//二叉查找树中的最小节点在最左边
t=t->left;
return(t);
}
//二叉查找树中的最大节点在最右边,算法类似。。。


3.5 在二叉查找树中插入一个节点

//在二叉查找树中插入节点
tree *insertTreeNode(tree *t,elemType e)
{
if(t==NULL)//定位到要插入的节点位置t=null
{
t=(tree *)malloc(sizeof(tree));
if(t==NULL) printf("error!");
t->data=e;
t->left=NULL;
t->right=NULL;
}
else if(e<t->data )//节点值小于t节点值
t->left=insertTreeNode(t->left,e);
else //节点值不小于t节点值得
t->right=insertTreeNode(t->right,e);
return(t);//返回结果
}


3.6 在二叉查找树中删除一个节点

  删除节点的操作稍微复杂一些,要分三种情况:

    (a)如果要删除的节点没有子女,则定位到该节点之后直接删除即可。

    (b)如果要删除的节点有一个子女,则定位到该节点之后,让节点的父节点直接指向该节点的子节点,然后删除该节点即可。

    (c)如果要删除的节点有两个子女,则定位到该节点之后,找出其后继结点,用后继结点的data和附加数据替换该节点的数据,然后删除后继结点(递归调用删除算法)。

具体算法:

tree *deleteTreeNode(tree *t,elemType e)
{
tree *p;
if(t==NULL)
{
printf("error!!!\n");
return NULL;
}
if(e < (t->data))//e小于t中的data值,则从t的左子树中删除e;
t->left=deleteTreeNode(t->left,e);
else if(e > (t->data))//e大于t中的data值,则从t的右子树中删除e;
t->right=deleteTreeNode(t->right,e);
else if((t->left) && (t->right))//找到节点且该节点的左右子树都存在
{
p=findMinTreeNode(t->right);//找到后继结点
t->data=p->data;//将后继结点的值赋给t节点
t->right=deleteTreeNode(t->right,t->data);//删除后继结点
}
else//找到节点且节点或者只存在一个子节点或者不存在子节点
{
p=t;
if(t->left==NULL)
t=t->right;
else if(t->right==NULL)
t=t->left;
free(p);
return(t);
}
return(t);
}


4、具体的代码实现:

View Code

#include<stdlib.h>
#include<stdio.h>
typedef int elemType;
typedef struct treenode
{
elemType data;
struct treenode *left;
struct treenode *right;
}tree;
tree *makeTree(tree *p);
void printTree(tree *t);
tree *insertTreeNode(tree *t,elemType e);
tree *deleteTreeNode(tree *t,elemType e);
tree *findMaxTreeNode(tree * t);
tree *findMinTreeNode(tree *t);
tree *findTreeNode(tree *t,elemType e);
//-------------------------------------------------
//构造二叉查找树
tree *makeTree(tree *p)
{
int k;
printf("构造树,请输入节点值(以-1结束):\n");
scanf("%d",&k);
while(k!=-1)
{
p=insertTreeNode(p,k);
scanf("%d",&k);
}
printf("\n");
return(p);
}
//中序遍历二叉查找树
void printTree(tree *t)
{
if(t)
{
printTree(t->left);
printf("%d ",t->data);
printTree(t->right);
}
}
//在二叉查找树中查找最小节点
tree *findMinTreeNode(tree *t)
{
if(t==NULL)
{
printf("error!!");
return NULL;
}
while(t->left)
t=t->left;
return(t);
}
//在二叉查找树中查找最大节点
tree *findMaxTreeNode(tree *t)
{
if(t==NULL)
{
printf("error!!");
return NULL;
}
while(t->right)
t=t->right;
return(t);
}
//在二叉查找树中插入节点
tree *insertTreeNode(tree *t,elemType e)
{
if(t==NULL)
{
t=(tree *)malloc(sizeof(tree));
if(t==NULL) printf("error!");
t->data=e;
t->left=NULL;
t->right=NULL;
}
else if(e<t->data )
t->left=insertTreeNode(t->left,e);
else
t->right=insertTreeNode(t->right,e);
return(t);
}
//在二叉查找树中删除节点
tree *deleteTreeNode(tree *t,elemType e)
{
tree *p;
if(t==NULL)
{
printf("error!!!\n");
return NULL;
}
if(e < (t->data))//e小于t中的data值,则从t的左子树中删除e;
t->left=deleteTreeNode(t->left,e);
else if(e > (t->data))//e大于t中的data值,则从t的右子树中删除e;
t->right=deleteTreeNode(t->right,e);
else if((t->left) && (t->right))//找到节点且该节点的左右子树都存在
{
p=findMinTreeNode(t->right);//找到后继结点
t->data=p->data;//将后继结点的值赋给t节点
t->right=deleteTreeNode(t->right,t->data);//删除后继结点
}
else//找到节点且节点或者只存在一个子节点或者不存在子节点
{
p=t;
if(t->left==NULL)
t=t->right;
else if(t->right==NULL)
t=t->left;
free(p);
return(t);
}
return(t);
}
void main()
{
int d;
tree *p;
p=NULL;
//-----------------------------------------------
p=makeTree(p);
printf("构造后的树采用中序遍历结果为:\n");
printTree(p);
//-----------------------------------------------
printf("插入节点:\n");
printf("请输入要插入的节点值:\n");
scanf("%d",&d);
p=insertTreeNode(p,d);
printf("插入节点后的树采用中序遍历结果为:\n");
printTree(p);
//-----------------------------------------------
printf("删除节点:\n");
printf("请输入要删除的节点值:\n");
scanf("%d",&d);
p=deleteTreeNode(p,d);
printf("删除节点后的树采用中序遍历结果为:\n");
printTree(p);
//------------------------------------------------
printf("\n构造树中的最小节点为:\n");
p=findMinTreeNode(p);
printf("%d  \n",p->data);
printf("\n构造树中的最大节点为:\n");
p=findMaxTreeNode(p);
printf("%d  \n",p->data);
}


5、参考资料:

(1)http://kb.cnblogs.com/a/2336968/

(2)算法导论
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: