查找->动态查找表->二叉排序树
文字描述
二叉排序树的定义
又称二叉查找树,英文名为Binary Sort Tree, 简称BST。它是这样一棵树:或者是一棵空树;或者是具有下列性质的二叉树:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左、右子树也分别是二叉排序树。
二叉排序树的查找
其查找过程和次优二叉树类似。即当二叉排序树不为空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。
二叉排序树的插入
和次优查找树相对,次优查找树是一种静态查找表。而二叉排序树是一种动态树表,其特点是,树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值的结点时再进行插入。新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。
二叉排序树的删除
在二叉排序树上删除一个结点相当于删除有序序列中的一个纪录,只要在删除某个结点之后依旧保持二叉排序树的特性即可。假设被删除结点*p(指向结点的指针为p),其双亲结点*f(结点类型为f),且不失一般性,可设*p是*f的左孩子。下面分3种情况进行讨论:
(1)若*p结点为叶子结点,即PL和PR均为空树。由于删除叶子结点*p不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
(2)若*p结点只有左子树PL或只有右子树PR,此书只要令PL或PR直接成为其双亲结点*f的左子树即可。
(3)若*p结点的左子树和右子树均不为空。从下图知,在删除*p之前,中序遍历该二叉树的序列为{…CLC…QLQSLSPPRF…}, 在删除*p之后,为保持其他元素之间的相对位置不变,可以有两种方法:[3.1]令*p的左子树为*f的左子树,而*p的右子树为*s的右子树。如下图(c)所示。[3.2]另*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)。如下图(d)所示,当以直接前驱*s替代*p时,由于*s只有左子树SL,则在删除*s之后,只要令SL为*s的双亲*q的右子树即可。
示意图
算法分析
和折半查找类似,与给定值比较的关键字个数不超过树的深度。然而,折半查找长度为n的表的判定树是惟一的,而含有n个结点的二叉排序树却不惟一。因此,含有n个结点的二叉排序树的平均查找长度和树的形态有关。
当先后插入的关键字有序时,构成的二叉排序树蜕变成单支树。树深度为n,其平均查找长度为(n+1)/2,和顺序查找相同,这是最差情况。
最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log2n成正比。
假设含有n(n>=1)个关键字的序列中,查找概率相等的情况下,其平均查找长度如下图,由此可见,在随机情况下,二叉排序树的平均查找长度和logn是等数量级的。
代码实现
1 //./a.out 45 12 53 3 37 100 24 61 90 78 2 3 //测试 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #define DEBUG 9 10 #define MAX_SIZE 50 11 #define TRUE 1 12 #define FALSE 0 13 14 #define EQ(a, b) ((a)==(b)) 15 #define LT(a, b) ((a)< (b)) 16 #define LQ(a, b) ((a)<=(b)) 17 18 /*定义关键字key为int型*/ 19 typedef int KeyType; 20 /*数据元素类型*/ 21 typedef struct{ 22 KeyType key; 23 }ElemType; 24 /*二叉链表结构*/ 25 typedef struct{ 26 ElemType data; 27 struct BiTNode *lchild; 28 struct BiTNode *rchild; 29 }BiTNode, *BiTree; 30 31 /*二叉排序树查找算法 32 * 33 *在根指针T所指二叉排序树中递归地查找其关键字等于key。 34 *若查找成功,则指针p指向该数据元素结点,指针f2指向p的父亲结点,并返回TRUE 35 *若查找失败,则指针p指向查找路径上访问的最后一个结点,并返回FALSE。 36 * 37 *注意: 38 *指针f是传入参数,指向T的双亲,其初始调用值为NULL 39 *指针f2是传出参数,若查找成功,则指向p的父亲结点 40 */ 41 int SearchBST(BiTree T, KeyType key, BiTree f, BiTree *p, BiTree *f2){ 42 if(!T){ 43 //查找不成功 44 *p = f; 45 return FALSE; 46 }else if(EQ(key, T->data.key)){ 47 //查找成功 48 *p = T; 49 //f2指向结点p的父亲结点 50 if(f2){ 51 *f2 = f; 52 } 53 return TRUE; 54 }else if(LT(key, T->data.key)){ 55 //在左子树上继续查找 56 return SearchBST((BiTree)T->lchild, key, T, p, f2); 57 }else{ 58 //在右子树上继续查找 59 return SearchBST((BiTree)T->rchild, key, T, p, f2); 60 } 61 } 62 63 /*二叉排序树插入算法 64 * 65 *当二叉排序树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE,否则返回FALSE。 66 */ 67 int InsertBST(BiTree *T, ElemType e){ 68 //提示:这儿必须用malloc给p分配堆,否则调用的SearchBST函数里无法给*p赋值。 69 BiTree *p = (BiTree*)malloc(sizeof(BiTree*)); 70 if(!SearchBST(*T, e.key, NULL, p, NULL)){ 71 //查找不成功,所以不存在关键字等于e.key的数据元素,需要插入 72 BiTree s = (BiTree)malloc(sizeof(BiTNode)); 73 s->data = e; 74 s->lchild = s->rchild = NULL; 75 if(!(*p)){ 76 //被插结点*s为新的根结点 77 *T = s; 78 }else if(LT(e.key, (*p)->data.key)){ 79 //被插结点*s为左孩子 80 (*p)->lchild = s; 81 }else{ 82 //被插结点*s为右孩子 83 (*p)->rchild = s; 84 } 85 free(p); 86 return FALSE; 87 }else{ 88 //查找成功,说明树中已有关键字相同的结点,不需要再插入。 89 free(p); 90 return TRUE; 91 } 92 } 93 94 /*二叉排序树删除算法 95 * 96 *若二叉排序树T中存在关键字等于key的数据元素,则删除该数据元素结点,并返回TRUE。 97 *否则返回FALSE 98 */ 99 int DeleteBST(BiTree *T, KeyType key){ 100 int ret = FALSE; 101 102 BiTree *p = (BiTree*)malloc(sizeof(BiTree*)); 103 BiTree *father = (BiTree*)malloc(sizeof(BiTree*)); 104 105 if(SearchBST(*T, key, NULL, p, father)){ 106 //找到关键字等于key的数据元素,需要删除 107 108 if(!(*p)->lchild){ 109 //左子树空,则只需重接它的右子树 110 111 if(*father){ 112 //被删结点不是根结点,因为其父亲结点father非空 113 if((*p) == (BiTree)(*father)->lchild){ 114 //被删结点是其父亲结点的左子树 115 (*father)->lchild = (*p)->rchild; 116 }else{ 117 //被删结点是其父亲结点的右子树 118 (*father)->rchild = (*p)->rchild; 119 } 120 }else{ 121 //被删结点是根结点,因为其父亲结点father空 122 *T = (BiTree)((*p)->rchild); 123 } 124 free(*p); 125 *p = NULL; 126 }else if(!(*p)->rchild){ 127 //右子树空,则只需重接它的左子树 128 129 if(*father){ 130 //被删结点不是根结点,因为其父亲结点father非空 131 if((*p) == (BiTree)(*father)->lchild){ 132 //被删结点是其父亲结点的左子树 133 (*father)->lchild = (*p)->lchild; 134 }else{ 135 //被删结点是其父亲结点的右子树 136 (*father)->rchild = (*p)->lchild; 137 } 138 }else{ 139 //被删结点不是根结点,因为其父亲结点father空 140 *T = (BiTree)((*p)->lchild); 141 } 142 free(*p); 143 *p = NULL; 144 }else{ 145 //左右子树都不为空 146 BiTNode *q, *s; 147 q = (BiTNode*)*p; 148 //转左 149 s = (BiTNode*)(*p)->lchild; 150 //然后向右走到尽头 151 while(s->rchild){ 152 q = s; 153 s = (BiTNode*)s->rchild; 154 } 155 //s指向被删除结点的"前驱" 156 (*p)->data = s->data; 157 if(q!=(BiTNode*)(*p)){ 158 //重接*q的右子树 159 q->rchild = s->lchild; 160 }else{ 161 //重接*q的左子树 162 q->lchild = s->lchild; 163 } 164 free(s); 165 } 166 167 ret = TRUE; 168 }else{ 169 //不存在关键字等于key的数据元素,不需要删除,返回FALSE。 170 ret = FALSE; 171 } 172 free(p); 173 free(father); 174 return ret; 175 } 176 177 /*先序遍历二叉树算法声明*/ 178 int PreOrderTraverse(BiTree T); 179 /*中序遍历二叉树算法声明*/ 180 int InOrderTraverse(BiTree T); 181 /*后序遍历二叉树算法声明*/ 182 int PostOrderTraverse(BiTree T); 183 184 /*分别用先、中、后序遍历算法顺序打印二叉排序树*/ 185 void print(BiTree T) 186 { 187 printf("先序遍历二叉排序树:\n"); 188 PreOrderTraverse(T); 189 printf("\n"); 190 191 printf("中序遍历二叉排序树:\n"); 192 InOrderTraverse(T); 193 printf("\n"); 194 195 printf("后序遍历二叉排序树:\n"); 196 PostOrderTraverse(T); 197 printf("\n"); 198 } 199 200 int main(int argc, char *argv[]) 201 { 202 if(argc < 2) 203 return FALSE; 204 int i = 0; 205 BiTree T = NULL; 206 ElemType e; 207 //动态创建二叉排序树 208 for(i=1; i<argc; i++){ 209 e.key = atoi(argv[i]); 210 //如果元素e不存在,就插入到二叉排序树T中 211 InsertBST(&T, e); 212 } 213 #ifdef DEBUG 214 print(T); 215 #endif 216 217 KeyType k = 0; 218 while(1){ 219 printf("\n输入要删除的key(负值表示结束):"); 220 scanf("%d", &k); 221 if(k<0) 222 break; 223 if(DeleteBST(&T, k)){ 224 printf("删除key(%d)成功!!!!!!\n", k); 225 #ifdef DEBUG 226 print(T); 227 #endif 228 }else{ 229 printf("删除key(%d)失败!!!!!!\n", k); 230 } 231 } 232 return 0; 233 } 234 235 /*先序遍历二叉树算法实现*/ 236 int PreOrderTraverse(BiTree T){ 237 if(T){ 238 printf("%d ", ((BiTNode*)T)->data.key); 239 PreOrderTraverse((BiTree)T->lchild); 240 PreOrderTraverse((BiTree)T->rchild); 241 } 242 return 0; 243 } 244 245 /*中序遍历二叉树算法实现*/ 246 int InOrderTraverse(BiTree T){ 247 if(T){ 248 InOrderTraverse((BiTree)T->lchild); 249 printf("%d ", ((BiTNode*)T)->data.key); 250 InOrderTraverse((BiTree)T->rchild); 251 } 252 return 0; 253 } 254 255 /*后序遍历二叉树算法实现*/ 256 int PostOrderTraverse(BiTree T){ 257 if(T){ 258 PostOrderTraverse((BiTree)T->lchild); 259 PostOrderTraverse((BiTree)T->rchild); 260 printf("%d ", ((BiTNode*)T)->data.key); 261 } 262 return 0; 263 }
运行
posted on 2018-08-21 18:19 LiveWithACat 阅读(1569) 评论(0) 编辑 收藏 举报