动态查找的大多借助于树类型的结构,这里只介绍最简单的一种——二叉排序树。
二叉排序树是这样一种树:它的要么是空的;如果它的左子树不为空,那么左子树上所有节点的值均小于根节点的值;如果右子树不为空,那么右子树上的值均大于根节点上的值,并且它的左右子树还是二叉排序树。二叉排序树有一个重要的性质:当你中序遍历该树时,得到的遍历结果是有序的。
但这一切跟动态查找查找有什么关系呢?使用线性数据结构,也能较好地完成查找工作,比如之前提过的折半查找法。但是如果我想完成的是:如果找不到这个元素,就把它插入或者如果找到这个元素,就把它删除,那么就比较麻烦了。原因出在两个方面,如果使用类似于数组的结构,那么插入、删除都会导致大量元素的移动;如果使用类似于链表的结构,由于链表不支持随机访问特性,只能从头开始一个挨着一个查找,不能发挥折半查找的效率优势。此时,如果我们使用二叉排序树就能很好解决这两个问题:首先,它可以较方便的插入和删除元素,其次沿着跟向任意路径的遍历恰好就是折半查找!每次遇到根节点,如果待查找的值小于根节点的值,则访问根节点的左子树;否则访问根节点的右子树。
下面我们看看程序的实现:
数据结构和函数的声明如下:
#include <stdio.h>
#include <malloc.h>
typedef struct BinarySortTree
{
int key;
//父节点
BinarySortTree* parent;
//左孩子
BinarySortTree* lchild;
//右孩子
BinarySortTree* rchild;
}BST,*pBST;
//初始化指向一个节点的指针
BST* initNode(int k);
//给parent节点增加一个名为child的孩子节点,lr=0为左孩子,否则为右孩子
bool addBranch(pBST parent,pBST child,int lr);
//中序遍历树
void InOrderTraverse(pBST t);
//查找key是否在t中,f为待查子树的父节点,找到的位置由p带出
bool searchBST(pBST t,int key,pBST f,pBST* p);
//向t中插入key
bool insertBST(BST* t,int key);
//执行删除的实际函数
void Delete(pBST t);
//从t中删除key
bool deleteBST(pBST t,int key);
//删除整个树
void destroyBST(pBST t);