今天我来介绍一下 搜索二叉树及其算法。
一。首先我们要先知道什么是搜索二叉树。
1.二叉搜索树又称为二叉排序树,它或者是一个空树。它的主要性质是
(1)若他的左子树不为空,则左子树上所有节点的值都小于根节点的值。
(2)若他的右子树不为空,则右子树上所有节点的值都大于根节点的值。
(3)它的左右子树也分别为二叉搜索树。
2.它的基本算法:查找、插入以及删除的普通和递归方法。
#pragma once
#include
#include
#include
#include
#include
typedef struct BSTreeNode{ //定义一个搜索二叉树的结构体
int key; //包含值、左子树和右子树。
struct BSTreeNode *pleft;
struct BSTreeNode *pright;
}BSTreeNode;
BSTreeNode *CreatNode(int key) //创建子树。
{
BSTreeNode *pNew=(BSTreeNode *)malloc(sizeof(BSTreeNode));
assert(pNew);
pNew->key=key;
pNew->pleft=pNew->pright=NULL;
return pNew;
}
//普通查找
//1:找到。
//0:没找到。
int Find(BSTreeNode *pRoot,int key)
{
BSTreeNode *p=pRoot;
while(p!=NULL) //总循环是节点不为空。
{
if(p->key==key) //当找到节点时,输出1.
{
return 1;
}
else if(keykey) //如果小于节点的值,就往左子树走。
{
p=p->pleft;
}
else{ //否则往右子树走。
p=p->pright;
}
}
return 0; //循环出来表示没找到。
}
//递归查找。
int FindR(BSTreeNode *pRoot,int key)
{
if(pRoot==NULL) //若为空,没找到。
{
return 0;
}
if(key==pRoot->key) //若等于根节点直接返回1.
{
return 1;
}
else if(keykey) //小于根节点,则递归左子树。
{
return FindR(pRoot->pleft,key);
}
return FindR(pRoot->pright,key); //否则递归右子树。
}
//普通插入
//0:插入成功
//-1:插入失败。
int Insert(BSTreeNode **pRoot,int key)
{
BSTreeNode *p=*pRoot; //定义两个变量。
BSTreeNode *q=NULL;
while(p!=NULL) //总循环直到找到节点为空的。
{
if(p->key==key) //如果与根节点相同则插入失败。
{
return -1;
}
else if(keykey) //若小于根节点,先用一个变量保存这个节点,在让根节点往左子树移。
{
q=p;
p=p->pleft;
}
q=p; //若大于根节点,先用一个变量保存这个节点,在让根节点往右子树移。
p=p->pright;
}
if(q==NULL) //如果根节点为空,直接插入即可。
{
(*pRoot)=CreatNode(key);
return 0;
}
if(keykey) //如果空节点的父节点的值大于要插入的值,则给它的左子树直接插入。
{
q->pleft=CreatNode(key);
return 0;
}
else if(key>q->key)
{
q->pright=CreatNode(key); //否则给它的右子树插入。
return 0;
}
}
//递归插入。
int InsertR(BSTreeNode **pRoot,int key)
{
if(*pRoot==NULL) //如果根节点为空,直接插入。
{
*pRoot=CreatNode(key);
return 0;
}
if((*pRoot)->key==key) //若与根节点相等,插入失败。
{
return -1;
}
else if(key<((*pRoot)->key)) //小于根节点的值,递归左子树。
{
return InsertR(&((*pRoot)->pleft),key);
}
return InsertR(&((*pRoot)->pright),key); //否则递归右子树。
}
//普通删除
//0:删除成功。
//-1:删除失败。
int Remove(BSTreeNode **pRoot,int key)
{
BSTreeNode *p=*pRoot;
BSTreeNode *q=*pRoot;
BSTreeNode *m=NULL;
while(p!=NULL) //循环节点不为空。
{
if(keykey) //若小于节点的值,向左子树移。
{
q=p;
p=p->pleft;
}
else if(key>p->key) //若大于节点的值,向右子树移。
{
q=p;
p=p->pright;
}
else{ //当等于节点的值时。
if(p->pleft==NULL) //若它的左子树为空
{
if(q->pleft==NULL) //当它的父节点的左子树为空时
{
q->pright=p->pright; //直接替换删除即可。
free(p);
return 0;
}
else if(q->pright==NULL) //当它的父节点的右子树为空
{
q->pleft=p->pright; //同理。
free(p);
return 0;
}
}
else if(p->pright==NULL) //当节点的右子树为空时,同理如上。
{
if(q->pleft==NULL)
{
q->pright=p->pleft;
free(p);
return 0;
}
else if(q->pright==NULL)
{
q->pleft=p->pleft;
free(p);
return 0;
}
}
else{ //当节点的左右子树都不为空时
m=p->pleft; //用变量m记下它的左子树。
while(m->pright)
{
q=m;
m=m->pright;
} //循环找最后的右子树。
if(p->pleft=m) //若m没变,证明m的右子树为空。
{
if(m->pleft==NULL) //若m的左子树也为空。
{
p->key=m->key; //直接将m赋给p即可。
free(m);
return 0;
}
else{ //若M的左子树不为空。
p->key=m->key; //将m赋给p之后,让p的左子树指向m的左子树,再删除即可。
p->pleft=m->pleft;
free(m);
return 0;
}
}
else{ //若m变了,证明m是最后的右子树,直接赋值删除即可。
p->key=m->key;
free(m);
}
}
}
}
return -1; //若退出循环,则删除失败。
}
//递归删除。
int RemoveR(BSTreeNode **pRoot,int key)
{
BSTreeNode *q=NULL;
if(*pRoot==NULL) //如果根节点为空,删除失败。
{
return -1;
}
if((*pRoot)->key>key) //若小于根节点的值,递归左子树。
{
return RemoveR(&((*pRoot)->pleft),key);
}
else if(key>(*pRoot)->key) //大于根节点的值,递归右子树。
{
return RemoveR(&((*pRoot)->pright),key);
}
else{ //当等于根节点的值时。
if((*pRoot)->pleft==NULL) //如果根节点的左子树为空,则它的右孩子作为根节点。
{
*pRoot=(*pRoot)->pright;
return 0;
}
else if((*pRoot)->pright==NULL) //右子树为空,它的左孩子为根节点。
{
*pRoot=(*pRoot)->pleft;
return 0;
}
q=(*pRoot)->pleft; //当左右孩子都不为空时。先用变量记下根节点的左子树。
while(q->pright) //循环找到最后的右子树。
{
q=q->pright;
}
(*pRoot)->key=q->key; //此时将右子树的值替换根节点的值。
RemoveR(&((*pRoot)->pleft),q->key); //在删除掉这个右子树即可。
return 0;
}
}
void test1()
{
BSTreeNode *p=NULL;
Insert(&p,1);
Insert(&p,2);
Insert(&p,3);
Insert(&p,4);
printf("%d\n",Find(p,3));
printf("%d\n",FindR(p,4));
Remove(&p, 4);
RemoveR(&p, 3);
printf("%d\n",FindR(p,4));
printf("%d\n",Find(p,3));
printf("\n");
}
以上就是搜索二叉树的基本算法。