通过学习我们可以知道:顺序表便于搜索,但是不便于插入与删除;而链表便于插入和删除却不便于搜索,那么有没有比较折中的数据结构呢?答案就是:二叉排序树。二叉排序树既有数组的有点也有链表的优点,非常适合处理大批量的动态数据。
二叉排序树的定义:
- 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 左、右子树也分别为二叉排序树;
- 没有键值相等的结点。
二叉排序树的结构定义:
typedef struct BiTNode
{
int data ;
struct BiTNode *lchid , *rchild ;
}BiTNode , *BiTree ;
二叉排序树的查找操作:
如果树中有与key相等的元素,那么返回这个结点的地址,如果没有与key相等的结点,那么返回在沿着查找key路径上的最后一个结点的地址。因为这棵树可能是空树,f的初始值应该设置为NULL。
Status SearchBST( BiTree T , int key , BiTree f , BiTree *p )
{
if( T == NULL )
{
*p = f ;
return FALSE ;
}
else if( key == T->data )
{
*p = T ;
return OK ;
}
else if( key < T->data )
return SearchBST( T->lchid , key , T , p ) ;
else
return SearchBST( T->rchild , key , T , p ) ;
}
插入操作:
Status InsertBST( BiTree *T , int val )
{
BiTree p , s ;
if( !SearchBST( *T , val , NULL , &p ) )//树中不能存在与val相等的结点
{
s = ( BiTNode * )malloc( sizeof( BiTNode ) ) ;
s->data = val ;
s->lchid = s->rchild = NULL ;
if( p == NULL )
*T = s ;
else if( p->data > val )
p->lchid = s ;
else
p->rchild = s ;
return OK ;
}
else
return FALSE ;
}
删除操作:
这个比较就会比较麻烦一点。
当我们要删除18时,我们只需要把结点20的左孩子指针指向结点15就行了。
当我们要删除结点22时,同样的道理:只需要把结点20的右孩子指针指向结点24就可以了。
我们再来看一个二叉排序树:
如果这个时候我们要删除结点10呢?是直接把结点19的左,右孩子指针分别指向结点6和结点15吗?
看图我们知道:结点15是结点19的右孩子,若按照二叉排序树的定义,结点19的右孩子必须比19大,显然这里15是违反了这个规定的。
那么该怎么办呢?
5 6 8 10 12 13 14 15 16 19 20 21 22 24,这是在未删除结点10的时候,二叉排序树对数据的排序结果。既然结点19不能代替结点10的位置,那么这个时候我们就要找这个排序中里最接近结点10的结点来代替10,有两个选择:结点8或者结点12,这两个的方法的实现几乎一样,这里就讲用结点8代替结点10的情况。
既然结点8是结点10的前驱,那么我们就应该在结点10的左子树中查找结点8的位置。
再综合上面分析的三种情况考虑:
对于要删除的结点:
- 只有左子树
- 只有右子树
- 既有右子树又有左子树
用结点10的前驱结点8来代替结点10:
Status Delete( BiTree *p )
{
BiTree q ;
if( ( *p )->lchid == NULL )
{
q = *p ;
*p = ( *p )->rchild ;
free( q ) ;
}
else if( ( *p )->rchild == NULL )
{
q = *p ;
*p = ( *p )->lchid ;
free( q ) ;
}
else
{
BiTree s ;
q = *p ;
s = ( *p )->lchid ;
while( s->rchild )
{
q = s ;
s = s->rchild ;
}
( *p )->data = s->data ;
if( q != ( *p ) )
q->rchild = s->lchid ;
else //这个情况表示的是:要删除的结点的左孩子没有右子树的情况
( *p )->lchid = s->lchid ;
free( s ) ;
}
return OK ;
看图更易于理解:
用结点10的后继结点12的操作与上述的大同小异:
Status Delete( BiTree *p )
{
BiTree q ;
if( ( *p )->lchid == NULL )
{
q = *p ;
*p = ( *p )->rchild ;
free( q ) ;
}
else if( ( *p )->rchild == NULL )
{
q = *p ;
*p = ( *p )->lchid ;
free( q ) ;
}
else
{
BiTree s ;
q = *p ;
s = ( *p )->rchild ;
while( s->lchid )
{
q = s ;
s = s->lchid ;
}
( *p )->data = s->data ;
if( q != ( *p ) )
q->lchid = s->rchild ;
else
q->rchild = s->rchild ;
free( s ) ;
}
return OK ;
}
通过二叉排序树的定义可以知道,数据的顺序输出其实就是树的中序遍历:
void InorderTraverse( BiTree T )
{
if( T == NULL )
return ;
else
{
InorderTraverse( T->lchid ) ;
printf( "%d " , T->data ) ;
InorderTraverse( T->rchild ) ;
}
}
最后附上源代码:
#include<stdio.h>
#include<stdlib.h>
#define FALSE 0
#define OK 1
typedef int Status ;
typedef struct BiTNode
{
int data ;
struct BiTNode *lchid , *rchild ;
}BiTNode , *BiTree ;
Status SearchBST( BiTree T , int key , BiTree f , BiTree *p ) ;
Status InsertBST( BiTree *T , int val ) ;
void InorderTraverse( BiTree T ) ;
Status Delete( BiTree *p ) ;
Status DeleteBST( BiTree *T , int key ) ;
int main( void )
{
int i ;
BiTree T = NULL ;
int Array[ 14 ] = { 13 , 15 , 16 , 5 , 6 , 8 , 10 , 14 , 12 , 19 , 20 , 21 , 22 , 24 } ;
for( i = 0 ; i < 14 ; i++ )
{
InsertBST( &T , Array[ i ] ) ;
}
InorderTraverse( T ) ; printf( "\n" ) ;
DeleteBST( &T , 10 ) ;
InorderTraverse( T ) ; printf( "\n" ) ;
return 0 ;
}
Status SearchBST( BiTree T , int key , BiTree f , BiTree *p )
{
if( T == NULL )
{
*p = f ;
return FALSE ;
}
else if( key == T->data )
{
*p = T ;
return OK ;
}
else if( key < T->data )
return SearchBST( T->lchid , key , T , p ) ;
else
return SearchBST( T->rchild , key , T , p ) ;
}
Status InsertBST( BiTree *T , int val )
{
BiTree p , s ;
if( !SearchBST( *T , val , NULL , &p ) )
{
s = ( BiTNode * )malloc( sizeof( BiTNode ) ) ;
s->data = val ;
s->lchid = s->rchild = NULL ;
if( p == NULL )
*T = s ;
else if( p->data > val )
p->lchid = s ;
else
p->rchild = s ;
return OK ;
}
else
return FALSE ;
}
void InorderTraverse( BiTree T )
{
if( T == NULL )
return ;
else
{
InorderTraverse( T->lchid ) ;
printf( "%d " , T->data ) ;
InorderTraverse( T->rchild ) ;
}
}
Status Delete( BiTree *p )
{
BiTree q ;
if( ( *p )->lchid == NULL )
{
q = *p ;
*p = ( *p )->rchild ;
free( q ) ;
}
else if( ( *p )->rchild == NULL )
{
q = *p ;
*p = ( *p )->lchid ;
free( q ) ;
}
else
{
BiTree s ;
q = *p ;
s = ( *p )->lchid ;
while( s->rchild )
{
q = s ;
s = s->rchild ;
}
( *p )->data = s->data ;
if( q != ( *p ) )
q->rchild = s->lchid ;
else
( *p )->lchid = s->lchid ;
free( s ) ;
}
return OK ;
}
Status DeleteBST( BiTree *T , int key )
{
if( *T == NULL )
return FALSE ;
else
{
if( key == ( *T )->data )
return Delete( T ) ;
else if( key > ( *T )->data )
return DeleteBST( &( *T )->rchild , key ) ;
else
return DeleteBST( &( *T )->lchid , key ) ;
}
}