二叉查找树描述
二叉查找树的性质:对于树中的每个结点X,它的左子树中所有关键字值小于X的关键值,而它的右子树中所有关键字大于X的关键值。由于树的递归定义,通常是递归的编写查找树的常用操作例程。对这些常用例程中,主要需要考虑的是插入和删除节点。下面将简要说明。(二叉查找树的平均深度是O(logN),所以一般不需要担心栈空间用尽。)
Insert:为了将X插入到树T中,可以像用Find那样沿着树查找。如果找到X,则什么也不用做。否则,将X插入到遍历的路径上的最后一点上。如下图所示,为了插入5,因而遍历该树,就好像在运行Find。在具有关键字4的节点处需要向右行进,但4的右子树不存在,因此5不在这棵树上,从而这个位置就是所要插入的位置。
Delete:一旦发现要删除的节点,考虑以下三种情况:如果该节点是一片树叶,那么它可以被立即删除;如果节点只有一个儿子,则该节点可以在其父节点调整指针绕过该节点后被删除,如下图:删除只有一个左孩子节点的元素:4。
复杂的情况是处理具有两个儿子的节点。一般的删除策略是用其右子树关键字最小的元素或左子树关键字最大的元素代替该节点的数据并递归的删除那个节点。因为右子树中最小节点不可能有左孩子(左子树的最大值节点则不可能有右孩子),所以第二次Delete变要容易一些。下图是一颗初始的二叉查找树即删除关键字为2的节点后的状态。
二叉查找树的具体代码实现
头文件:searchTree.h
typedef int ElementType; #ifndef _SEARCH_TREE_ #define _SEARCH_TREE_ struct TreeNode; typedef TreeNode *Position; typedef TreeNode *SearchTree; SearchTree MakeEmpty( SearchTree T ); //释放树中的所有元素 Position Find( ElementType X, SearchTree T ); Position FindMin( SearchTree T ); //查找最小值 Position FindMax( SearchTree T ); SearchTree Insert( ElementType X, SearchTree T ); SearchTree Delete( ElementType X, SearchTree T ); ElementType Retrieve( Position P ); //提取该位置上关键字 void PrintTree( SearchTree T ); //先序输出 #endif
实现文件:SearchTree.c
#include "searchTree.h" #include <stdio.h> #include <stdlib.h> struct TreeNode { ElementType Element; Position Left; Position Right; }; SearchTree MakeEmpty( SearchTree T ) { if (T != NULL) { MakeEmpty(T->Left); MakeEmpty(T->Right); free(T); } return NULL; } Position Find( ElementType X, SearchTree T ) { if (T == NULL) return NULL; if (T->Element < X) return Find(X, T->Right); else if(T->Element > X) return Find(X, T->Left); else return T; //非递归实现 /*while (T != NULL) { if (T->Element < X) T = T->Left; else if (T->Element > X) T = T->Right; else return T; }*/ } Position FindMin( SearchTree T ) { if (T == NULL) return NULL; else if (T->Left == NULL) return T; else return FindMin(T->Left); //非递归实现 /*Position P = T; while (P->Left != NULL) { P = P->Left; } return P;*/ } Position FindMax( SearchTree T ) { if (T == NULL) return NULL; else if (T->Right == NULL) return T; else return FindMax(T->Right); //非递归实现 /*Position P = T; while (P->Right != NULL) { P = P->Right; } return P;*/ } SearchTree Insert( ElementType X, SearchTree T ) { if (T == NULL) { //最后该插入X的位置 T = (Position)malloc(sizeof(struct TreeNode)); if (T == NULL) { printf("Out of space!\n"); return NULL; } T->Left = T->Right = NULL; T->Element = X; } else if (T->Element < X) T->Right = Insert(X, T->Right); else if (T->Element > X) T->Left = Insert(X, T->Left); return T; } SearchTree Delete( ElementType X, SearchTree T ) { Position TmpCell; if (T == NULL) printf("Cannot find element %d\n", X); else { if (X < T->Element) //在左子树中查找 T->Left = Delete(X, T->Left); else if (X > T->Element) T->Right = Delete(X, T->Left); else { //找到值为X的节点,即此时的T,判断该节点的左右孩子是否都存在 if (T->Left && T->Right) { TmpCell = FindMin(T->Right); //找到右子树中的最小者 T->Element = TmpCell->Element; T->Right = Delete(T->Element, T->Right); //改为删除T右子树中最小者 } else { TmpCell = T; if ( T->Left == NULL) T = T->Right; else if ( T->Right == NULL ) T = T->Left; free(TmpCell); } } } return T; } void PrintTree( SearchTree T ) { if (T != NULL) { printf("%5d\n", T->Element); PrintTree(T->Left); PrintTree(T->Right); } } ElementType Retrieve( Position P ) { return P->Element; }