二叉排序树
首先定义二叉树的存储结构
1 /* 二叉树的二叉链表结点结构定义 */ 2 typedef char TreeElemType; 3 typedef struct tagBiTreeNode { 4 TreeElemType data;//结点数据 5 struct tagBiTreeNode *lchild, *rchild;//结点左右孩子指针 6 }BiTrNode, *BiTrNodePtr;
二叉排序树的查找函数实现如下:
1 /* 2 ** @brief 二叉排序树查找的递归实现 3 ** @param 4 ** @arg root : 根结点 5 ** @arg key : 待查找的关键字 6 ** @arg parent: root节点的双亲结点,初始值为NULL 7 ** @arg result: 查找结果中找到的结点指针 8 ** @retval 如果查找成功,则result指向该元素结点并返回1; 9 ** 如果失败,则result指向查找路径上访问的最后一个节点。 10 */ 11 int BST_Search(BiTrNodePtr root, TreeElemType key, BiTrNodePtr parent, BiTrNodePtr *result) 12 { 13 if (root == NULL){//查找不成功 14 *result = parent; 15 return 0; 16 } 17 if (key == root->data){//查找成功 18 *result = root; 19 return 1; 20 }else if (key < root->data){//被查找元素小于根结点元素 21 return BST_Search(root->lchild, key, root, result);//在左子树继续查找 22 }else{//被查找元素大于根结点元素 23 return BST_Search(root->rchild, key, root, result);//在右子树继续查找 24 } 25 }
在实现了查找的基础上,我们可以实现二叉查找树的插入(构造)函数:
1 /* 2 ** @brief 二叉排序树的插入 3 ** @retval 当二叉树root中不存在关键字等于key的数据元素时, 4 ** 插入key并返回1;否则直接返回0 5 */ 6 int BST_Insert(BiTrNodePtr *root, TreeElemType key) 7 { 8 BiTrNodePtr result = NULL, s = NULL; 9 if (!BST_Search(*root, key, NULL, &result)){//查找不成功 10 s = (BiTrNodePtr)malloc(sizeof(BiTrNode)); 11 s->data = key; 12 s->lchild = s->rchild = NULL; 13 14 if (result == NULL){ 15 *root = s;//插入节点s为新的根结点 16 }else if (key < result->data){ 17 result->lchild = s;//插入结点s为左孩子 18 }else{ 19 result->rchild = s;//插入结点s为右孩子 20 } 21 22 return 1;//插入成功 23 }else{//树中已经存在关键字相同的结点,不再插入 24 return 0;//插入失败 25 } 26 }
为了验证,我们可以实现二叉树的中序遍历:
1 /* 2 ** 中序遍历二叉排序树 3 */ 4 void BST_Traverse(BiTrNodePtr root, void (*visit)(BiTrNodePtr)) 5 { 6 if (root == NULL) return; 7 BST_Traverse(root->lchild, visit); 8 visit(root); 9 BST_Traverse(root->rchild, visit); 10 }
二叉排序树的删除操作相对复杂一点,代码如下:
1 /* 2 ** 从二叉排序树中删除结点p,并重接它的左子树或右子树 3 */ 4 int DeleteNode(BiTrNodePtr *p) 5 { 6 BiTrNodePtr q = NULL, s = NULL; 7 if ((*p)->rchild == NULL){//右子树为空,则只需要重接它的左子树 8 q = *p; 9 *p = (*p)->lchild; 10 free(q); 11 }else if ((*p)->lchild == NULL){//左子树为空,只需要重接它的右子树 12 q = *p; 13 *p = (*p)->rchild; 14 free(q); 15 }else{//左右子树均不为空 16 q = *p; 17 s = (*p)->lchild;//s指向待删除结点的左孩子 18 while (s->rchild){ 19 q = s;//q存储s的双亲结点 20 s = s->rchild;//一直向右子树查找,指导右子树的尽头(找到待删除结点的前驱) 21 } 22 //找到p的直接前驱s 23 (*p)->data = s->data;//用s的值替代待删除结点的值 24 if (q != (*p)){//如果待删除结点的直接前驱不是其左孩子 25 q->rchild = s->lchild;//将s的左子树重新接到其双亲结点的右子树 26 }else{//如果待删除结点的直接前驱是其左孩子 27 q->lchild = s->lchild;//重接q的左子树 28 } 29 free(s);//删除前驱结点 30 } 31 return 1; 32 } 33 34 /* 35 ** 若二叉排序树root中存在关键字等于key的数据元素,则删除该结点 36 ** 并返回1;如果不存在,则返回0 37 */ 38 int BST_Delete(BiTrNodePtr *root, TreeElemType key) 39 { 40 if (NULL == *root){//没有找到关键字等于key的结点 41 return 0; 42 } 43 44 if ( key == (*root)->data ){//找到关键字等于key的结点 45 return DeleteNode(root); 46 }else if ( key < (*root)->data ){//如果关键字小于根结点元素值 47 return BST_Delete(&(*root)->lchild, key);//在左子树删除 48 }else{//如果关键字大于根结点元素值 49 return BST_Delete(&(*root)->rchild, key);//在右子树删除 50 } 51 }
最后给一段测试代码:
1 #include <stdio.h> 2 #include "search.h" 3 4 void visit(BiTrNodePtr e) 5 { 6 printf(" %c ", e->data); 7 } 8 9 int main(void) 10 { 11 BiTrNodePtr root = NULL; 12 TreeElemType key; 13 14 scanf("%c", &key); 15 while (key != '#'){ 16 BST_Insert(&root, key); 17 scanf("%c", &key); 18 } 19 BST_Traverse(root, visit); 20 21 fflush(stdin);//刷新输入缓冲区 22 printf("\nEnter key to be deleted: "); 23 scanf("%c", &key); 24 BST_Delete(&root, key); 25 BST_Traverse(root, visit); 26 27 return 0; 28 }
运行结果如下: