二叉排序/搜索/查找树
二叉排序树(Binary Sort Tree)又称二叉查找树或二叉搜索树。 它或者是一棵空树;或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树。
通俗地讲很简单:一句话就是左孩子比父节点小,右孩子比父节点大,还有一个特性就是”中序遍历“可以让结点有序。如下图:
几种常见的操作:
1、二叉树数据结构
struct BSTNode { int data; // value of node BSTNode *lchild; // left child of node BSTNode *rchild; // right child of node }BSTNode,*BSTree;
2、创建二叉排序树
/* 递归建立二叉排序树 */ void addBSTNode(BSTree &pCurrent,int value)//在这个函数中会要改变指针值,一定要记得使用引用传递 { if (pCurrent==NULL) { BSTree pBSTree=new BSTNode(); //BSTree pBSTree = (BSTree)malloc(sizeof(BSTNode)); pBSTree->data=value; pBSTree->lchild=NULL; pBSTree->rchild=NULL; pCurrent=pBSTree; } else if (pCurrent->data<value) addBSTNode(pCurrent->rchild,value); else if (pCurrent->data>value) addBSTNode(pCurrent->lchild,value); else cout<<"node repeated"<<endl; }
3、二叉排序树的插入(跟创建时操作一样,只是返回根节点),二叉查找树的插入过程如下:1.若当前的二叉查找树为空,则插入的元素为根节点,2.若插入的元素值小于根节点值,则将元素插入到左子树中,3.若插入的元素值不小于根节点值,则将元素插入到右子树中。首先找到插入的位置,要么向左,要么向右,直到找到空结点,即为插入位置,如果找到了相同值的结点,插入失败。
(1)递归版本:
BSTree insert(BSTree root, int value) { BSTree pBSTree=new BSTNode(); pBSTree->data=value; pBSTree->lchild=NULL; pBSTree->rchild=NULL; if(root==NULL){ root=pBSTree; } else if(value<root->data) root->lchild=insert(root->lchild,value); else root->rchild=insert(root->rchild,value); return root; }
(2)非递归版本:
void insert_BST(BSTree q, int value) { BSTree p = new BSTNode(); p->data = value; p->lchild = NULL; p->rchild = NULL; if(q == NULL){ q = p; return ; } while(q->lchild != p && q->rchild != p){ if(value < q->data){ if(q->lchild){ q = q->lchild; } else{ q->lchild = p; } } else{ if(q->rchild){ q = q->rchild; } else{ q->rchild = p; } } } return; }
4、二叉排序树的删除
二叉查找树的删除,分三种情况进行处理:
1.p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点),如图a。
2.p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可;(注意分是根节点和不是根节点);如图b。
3.有两个孩子的情况,当前结点与左子树中最大的元素交换,然后删除当前结点。左子树最大的元素一定是叶子结点,交换后,当前结点即为叶子结点,删除参考没有孩子的情况。另一种方法是,当前结点与右子树中最小的元素交换,然后删除当前结点。如图c。
bool bst_delete(BSTree &node, int value) { BSTree parent = NULL; BSTree tmp; while(node != NULL) { if(value < node->data) { // 向左 parent = node; node = node->lchild; } else if(value > node->data) { // 向右 parent = node; node = node->rchild; } else { // 找到了 if(NULL==node->lchild && NULL==node->rchild) { // 叶子结点 if(parent == NULL) { // 根结点 delete node; node = NULL; } else { // 非根结点 (parent->lchild==node)?(parent->lchild=NULL):(parent->rchild=NULL); delete node; node = NULL; } } else if(NULL!=node->lchild && NULL==node->rchild) { // 只有左孩子 if(parent == NULL) { // 根结点 tmp = node; node = node->lchild; delete tmp; } else { // 非根结点 (parent->lchild==node)?(parent->lchild=node->lchild):(parent->rchild=node->lchild); delete node; } } else if(NULL!=node->rchild && NULL==node->lchild) { // 只有右孩子 if(parent == NULL) { // 根结点 tmp = node; node = node->rchild; delete tmp; } else { // 非根结点 (parent->lchild==node)?(parent->lchild=node->rchild):(parent->rchild=node->rchild); delete node; } } else { // 既有左孩子也有右孩子 BSTree leftNode = node; while(leftNode->rchild != NULL) { parent = leftNode; leftNode = leftNode->rchild; } // 交换leftNode与node int swapValue = leftNode->data; leftNode->data = node->data; node->data = swapValue; // 删除leftNode,parent肯定不为空 (parent->lchild==node)?(parent->lchild=NULL):(parent->rchild=NULL); delete node; } } } return false; // 失败 }
(3)二叉排序树的查找
这个比较简单,要么找到了,要么向左,要么向右。
BSTree bst_search(BSTree node, int value) { while(node != NULL) { if(value < node->data) // 向左 node = node->lchild; else if(value > node->data) // 向右 node = node->rchild; else // 找到 return node; } return NULL; // 失败 }
主函数测试代码:
int main() { BSTree pRoot=NULL; int a[7]; for(int i=0;i<7;i++) { cin>>a[i]; addBSTNode(pRoot,a[i]); } //各种函数测试... system("pause"); return 0; }