动态查找:动态查找不仅要查找结点,而且还要不断地插入和删除结点,当表采用顺序结构时,这需要花费大量的时间用于结点的移动,效率很低。这里采用树表的形式,树表本身可以动态建立,树表主要有二叉排序树,平衡二叉树,B-树和B+树等。
二叉排序树的特点是:lchild <= root <= rchild,对此树中序遍历就可以找到一组有序的数组。二叉树的复杂度一般为O(log n ),但在特殊情况为O(n)。
这里要强调一点就是二叉排序树删除时要分两种情况,一种被删除点没有左子树,另外一种是有左子树。详细请见源代码:
#include <iostream.h> #include <string.h> typedef int KeyType; #define NUM 11 class BinStree; class BinSTreeNode { public: KeyType key; BinSTreeNode *lchild; BinSTreeNode *rchild; BinSTreeNode() { lchild = NULL; rchild = NULL; } }; class BinSTree { public: BinSTreeNode *root; BinSTree() { root = NULL; } ~BinSTree() { // DeleteTree(); } BinSTreeNode *BSTreeSearch( BinSTreeNode *bt, KeyType k, BinSTreeNode *&p ); void BSTreeInsert( BinSTreeNode *&bt, KeyType k ); int BSTreeDelete( BinSTreeNode *&bt, KeyType k ); // void Destroy( BinSTreeNode *current ); // void DeleteTree() // { // Destroy( root ); // root = NULL; // } bool IsEmpty() { return root == NULL; } }; /** * 二叉树排序查找算法 * 在根指针为bt的二叉排序树中查找元素k的节点,若查找成功,则返回指向该节点的指针 * 参数p指向查找到的结点,否则返回空指针,参数p指向k应插入的父结点 */ BinSTreeNode* BinSTree::BSTreeSearch( BinSTreeNode *bt, KeyType k, BinSTreeNode *&p ) { BinSTreeNode *q = NULL; q = bt; while( bt ) { q = bt; if( bt->key == k ) { p = bt; return( bt ); } if( bt->key > k ) bt = bt->lchild; else bt = bt->rchild; } p = q; return( bt ); } /** * 二叉排序树的插入节点算法 * bt指向二叉排序树的根结点,插入元素k的结点 */ void BinSTree::BSTreeInsert( BinSTreeNode *&bt, KeyType k ) { BinSTreeNode *p = NULL, *q; q = bt; if( BSTreeSearch( q, k, p ) == NULL ) { BinSTreeNode *r = new BinSTreeNode; r->key = k; r->lchild = r->rchild = NULL; if( q == NULL ) { bt = r; //被插入节点做为树的根节点 } if( p && k < p->key ) p->lchild = r; else if( p ) p->rchild = r; } } /** * 二叉排序树的删除结点算法 * 在二叉排序树中删除元素为k的结点,*bt指向二叉排序树的根节点 * 删除成功返回1,不成功返回0. */ int BinSTree::BSTreeDelete( BinSTreeNode *&bt, KeyType k ) { BinSTreeNode *f, *p, *q, *s; p = bt; f = NULL; //查找关键字为k的结点,同时将此结点的双亲找出来 while( p && p->key != k ) { f = p; if( p->key > k ) p = p->lchild; else p = p->rchild; } if( p == NULL ) //找不到待删除的结点时返回 return 0; if( p->lchild == NULL ) //待删除结点的左子树为空 { if( f == NULL ) //待删除结点为根节点 bt = p->rchild; else if( f->lchild == p ) //待删结点是其双亲结点的左节点 f->lchild = p->rchild; else f->rchild = p->rchild; //待删结点是其双亲结点的右节点 delete p; } else //待删除结点有左子树 { q = p; s = p->lchild; while( s->rchild ) //在待删除结点的左子树中查找最右下结点 { q = s; s = s->rchild; } if( q == p ) q->lchild = s->lchild; else q->rchild = s->lchild; p->key = s->key; delete s; } return 1; } int main( void ) { int a[NUM] = { 34, 18, 76, 13, 52, 82, 16, 67, 58, 73, 72 }; int i; BinSTree bst; BinSTreeNode *pBt = NULL, *p = NULL, *pT = NULL; for( i = 0; i < NUM; i++ ) { bst.BSTreeInsert( pBt, a[i] ); //创建二叉排序树 } pT = bst.BSTreeSearch( pBt, 52, p ); //搜索排序二叉树 bst.BSTreeDelete( pBt, 13 ); //删除无左孩子的情况 bst.BSTreeDelete( pBt, 76 ); //删除有左孩子的情况 return 0; }