zoukankan      html  css  js  c++  java
  • "排序二叉树"之探幽

     /*怎么理解排序二叉树呢?在二叉树的基本定义上增加两个基本条件:
    (1)所有左子树的节点数值都小于此节点的数值;
    (2)所有右节点的数值都大于此节点的数值。
    */
    1
    /************************头文件部分**************************/ 2 /******************************************************** 3 filename :tree_head.h 4 time :2013-11-13 5 copyrignt:none 6 author :cheng 7 **********************************************************/ 8 9 #ifndef _DOUBLE_TREE_ 10 #define _DOUBLE_TREE_ 11 12 #include <assert.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 typedef enum{ 18 false = 0,true = !false 19 }bool; 20 21 /* 22 二叉树节点的数据结构,我们看到每一个数据节点有三个指针,分别是:指向父母的指针,指向左孩子的指针,指向右孩子的指针。每一个节点都是通过指针相互连接的。相连指针的关系都是父子关系。 23 */ 24 typedef struct _sort_double_tree 25 { 26 int data; 27 struct _sort_double_tree* parent; 28 struct _sort_double_tree* left_child; 29 struct _sort_double_tree* right_child; 30 31 }TREE_NODE; 32 33 /*提供一个测试用的结构*/ 34 typedef struct _func_mode_manager 35 { 36 void* (*find_data_in_tree_node)(const TREE_NODE* pTreeNode, int data); 37 int (*count_node_number_in_tree)(const TREE_NODE* pTreeNode); 38 void (*print_all_node_data)(const TREE_NODE* pTreeNode); 39 bool (*delete_node_from_tree)(TREE_NODE** ppTreeNode, int data); 40 bool (*insert_node_into_tree)(TREE_NODE **ppTreeNode,int data); 41 42 }Manager_mode; 43 44 /*一些功能函数*/ 45 TREE_NODE* create_tree_node(int data); 46 TREE_NODE* create_double_tree(TREE_NODE *node,int *data,int mum); 47 TREE_NODE* find_data_in_tree_node(const TREE_NODE* pTreeNode, int data); 48 TREE_NODE* find_max_node(const TREE_NODE *pTreeNode); 49 int count_node_number_in_tree(const TREE_NODE* pTreeNode); 50 void print_all_node_data(const TREE_NODE* pTreeNode); 51 int calculate_height_of_tree(const TREE_NODE* pTreeNode); 52 bool insert_node_into_tree(TREE_NODE** ppTreeNode, int data); 53 bool delete_node_from_tree(TREE_NODE** ppTreeNode, int data); 54 55 Manager_mode* alloc_test_mode(void); 56 57 #endif //endif tree_head.h 58 59 /***************************功能函数实现部分**********************/ 60 #include "tree_head.h" 61 62 static bool _insert_node_into_tree(TREE_NODE** ppTreeNode, int data, TREE_NODE* pParent); 63 64 static bool _delete_node_from_tree(TREE_NODE* pTreeNode); 65 /************************************************ 66 函数名:alloc_test_mode 67 功能:初始化Manager_mode结构的成员 68 返回:Manager_mode结构类型的变量 69 *************************************************/ 70 Manager_mode* alloc_test_mode(void) 71 { 72 Manager_mode* manager=NULL; 73 manager = (Manager_mode*)malloc(sizeof(Manager_mode)); 74 assert(manager != NULL); 75 76 manager->find_data_in_tree_node=find_data_in_tree_node; 77 manager->count_node_number_in_tree=count_node_number_in_tree; 78 manager->print_all_node_data=print_all_node_data; 79 manager->delete_node_from_tree=delete_node_from_tree; 80 manager->insert_node_into_tree=insert_node_into_tree; 81 82 return manager; 83 } 84 /************************************************ 85 函数名:create_tree_node 86 功能:创建一个二叉节点 87 返回:返回一个初始化的节点 88 *************************************************/ 89 TREE_NODE* create_tree_node(int data) 90 { 91 TREE_NODE* pTreeNode = NULL; 92 pTreeNode = (TREE_NODE*)malloc(sizeof(TREE_NODE)); 93 assert(NULL != pTreeNode); 94 95 memset(pTreeNode, 0, sizeof(TREE_NODE)); 96 pTreeNode->data = data; 97 return pTreeNode; 98 } 99 /************************************************ 100 函数名:create_double_tree 101 功能:创建一颗排序二叉树 102 返回:返回传入的头节点 103 *************************************************/ 104 TREE_NODE* create_double_tree(TREE_NODE *node,int *data,int num) 105 { 106 assert((node != NULL) && (data !=NULL) && (num > 0)); 107 int i=0; 108 bool flag = true; 109 while((i < num) && flag){ 110 flag = insert_node_into_tree(&node,data[i]); 111 i++; 112 } 113 114 return node; 115 } 116 /************************************************ 117 函数名:insert_node_into_tree 118 功能:向排序二叉树中插入结点 119 返回:成功返回true,好、失败返回false 120 *************************************************/ 121 /*分析: 122 一般来说,二叉树的插入主要分为以下两个步骤: 123 1) 对当前的参数进行判断,因为需要考虑到头结点,所以我们使用了指针的指针作为函数的输入参数 124 2) 分情况讨论: 125 如果原来二叉树连根节点都没有,那么这个新插入的数据就是根节点; 126 如果原来的二叉树有根节点,那我们判断这个数据是否存在过,如果存在,那么返回;如果不存在,那么继续插入数据。 127 那继续插入的数据怎么保存呢?又要分三种情况: 128 1)如果插入的数据小于当前节点的数据,那么往当前节点的左子树方向继续寻找插入位置 129 2)如果插入的数据大于当前插入的位置,那么往当前节点的右子树方向继续寻找插入位置 130 3)如果方向当前的节点为空,那么表示插入的位置找到了,插入数据即可 */ 131 static bool _insert_node_into_tree(TREE_NODE** ppTreeNode, int data, TREE_NODE* pParent) ; 132 bool insert_node_into_tree(TREE_NODE** ppTreeNode, int data) 133 { 134 bool FALSE= false; 135 bool TRUE = true ; 136 if(NULL == ppTreeNode) 137 return FALSE; 138 139 if(NULL == *ppTreeNode) 140 { 141 *ppTreeNode = (TREE_NODE*)create_tree_node(data); 142 assert(NULL != *ppTreeNode); 143 return TRUE; 144 } 145 return _insert_node_into_tree(ppTreeNode, data, NULL); 146 } 147 static bool _insert_node_into_tree(TREE_NODE** ppTreeNode, int data, TREE_NODE* pParent) 148 { 149 bool TRUE = true ; 150 if(NULL == *ppTreeNode) 151 { 152 *ppTreeNode = create_tree_node(data); 153 assert(NULL != *ppTreeNode); 154 (*ppTreeNode)->parent = pParent; 155 return TRUE; 156 } 157 if(data < (*ppTreeNode)->data) 158 return _insert_node_into_tree(&(*ppTreeNode)->left_child, data, *ppTreeNode); 159 else 160 return _insert_node_into_tree(&(*ppTreeNode)->right_child, data, *ppTreeNode); 161 } 162 163 /************************************************ 164 函数名:find_data_in_tree_node 165 功能:在排序二叉树中查询一个数据 166 返回:返回传入的头结点 167 *************************************************/ 168 TREE_NODE* find_data_in_tree_node(const TREE_NODE* pTreeNode, int data) 169 { 170 if(NULL == pTreeNode) 171 return NULL; 172 173 if(data == pTreeNode->data) 174 return (TREE_NODE*)pTreeNode; 175 else if(data < pTreeNode->data) 176 return find_data_in_tree_node(pTreeNode->left_child, data); 177 else 178 return find_data_in_tree_node(pTreeNode->right_child, data); 179 } 180 /*分析:我们的查找是按照递归迭代进行的。因为整个二叉树是一个排序二叉树,所以我们的数据只需要和每一个节点依次比较就可以了,如果数值比节点数据小,那么向左继续遍历;反之向右继续遍历。如果遍历下去遇到了NULL指针,只能说明当前的数据在二叉树中还不存在 .*/ 181 182 /************************************************ 183 函数名:find_max_node 184 功能:在排序二叉树中寻找一个最大结点 185 返回:返回传入的头结点 186 *************************************************/ 187 TREE_NODE* find_max_node(const TREE_NODE *pTreeNode) 188 { 189 if(NULL == pTreeNode) 190 return NULL; 191 if(((NULL == pTreeNode->left_child )&&(NULL == pTreeNode->right_child))|| 192 ((NULL == pTreeNode->right_child)&&(NULL != pTreeNode->left_child))) 193 return pTreeNode; 194 else 195 return pTreeNode->right_child; 196 } 197 /************************************************ 198 函数名:count_node_number_in_tree 199 功能:统计排序二叉树中结点的个数 200 返回:返回结点的个数 201 *************************************************/ 202 int count_node_number_in_tree(const TREE_NODE* pTreeNode) 203 { 204 if(NULL == pTreeNode) 205 return 0; 206 207 return 1 + count_node_number_in_tree(pTreeNode->left_child) 208 + count_node_number_in_tree(pTreeNode->right_child); 209 } 210 /******************************************************* 211 函数名:print_all_node_data 212 功能:打印一颗排序二叉树各个结点的data值 213 返回:无 214 *******************************************************/ 215 void print_all_node_data(const TREE_NODE* pTreeNode) 216 { 217 if(pTreeNode){ 218 print_all_node_data(pTreeNode->left_child); 219 printf("%d ", pTreeNode->data); 220 print_all_node_data(pTreeNode->right_child); 221 } 222 } 223 分析:因为二叉树本身的特殊性,按顺序打印二叉树的函数本身也比较简单。首先打印左子树的节点,然后打印本节点的数值,最后打印右子树节点的数值,这样所有节点的数值就都可以打印出来了。 224 225 /************************************************ 226 函数名:calculate_height_of_tree 227 功能:计算树的高度 228 返回:树的高度 229 *************************************************/ 230 int calculate_height_of_tree(const TREE_NODE* pTreeNode) 231 { 232 int left, right; 233 if(NULL == pTreeNode) 234 return 0; 235 236 left = calculate_height_of_tree(pTreeNode->left_child); 237 right = calculate_height_of_tree(pTreeNode->right_child); 238 return (left > right) ? (left + 1) : (right + 1); 239 } 240 241 /************************************************ 242 函数名:delete_node_from_tree 243 功能:删除指定的数据并释放该结点空间 244 返回:成功返回true,失败返回false 245 *************************************************/ 246 分析: 247 相比较节点的添加,平衡二叉树的删除要复杂一些。因为在删除的过程中,你要考虑到不同的情况,针对每一种不同的情况,你要有针对性的反应和调整。所以在代码编写的过程中,我们可以一边写代码,一边写测试用例。编写测试用例不光可以验证我们编写的代码是否正确,还能不断提高我们开发代码的自信心。这样,即使我们在开发过程对代码进行修改或者优化也不会担心害怕。 248 在排序二叉树的删除过程当中,我们应该怎么做呢?大体上分为下面三个步骤: 249 1)判断参数的合法性,判断参数是否在当前的二叉树当中 250 2)删除的节点是根节点,此时应该怎么调整 251 3)删除的节点是普通节点,此时又应该怎么调整 252 static bool _delete_node_from_tree(TREE_NODE* pTreeNode) ; 253 bool delete_node_from_tree(TREE_NODE** ppTreeNode, int data) 254 { 255 bool FALSE= false; 256 bool TRUE = true ; 257 TREE_NODE* pTreeNode; 258 TREE_NODE* pLeftMax; 259 260 if(NULL == ppTreeNode || NULL == *ppTreeNode) 261 return FALSE; 262 263 pTreeNode = find_data_in_tree_node(*ppTreeNode, data); 264 if(NULL == pTreeNode) 265 return FALSE; 266 267 if(*ppTreeNode == pTreeNode) 268 { 269 if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){ 270 *ppTreeNode = NULL; 271 } 272 else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){ 273 *ppTreeNode = pTreeNode->left_child; 274 pTreeNode->left_child->parent = NULL; 275 } 276 else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){ 277 *ppTreeNode = pTreeNode->right_child; 278 pTreeNode->right_child->parent = NULL; 279 } 280 else 281 { 282 pLeftMax = find_max_node(pTreeNode->left_child); 283 if(pLeftMax == pTreeNode->left_child) 284 { 285 *ppTreeNode = pTreeNode->left_child; 286 (*ppTreeNode)->right_child = pTreeNode->right_child; 287 (*ppTreeNode)->right_child->parent = *ppTreeNode; 288 (*ppTreeNode)->parent = NULL; 289 } 290 else 291 { 292 pTreeNode->data = pLeftMax->data; 293 pLeftMax->parent->right_child = pLeftMax->left_child; 294 pLeftMax->left_child->parent = pLeftMax->parent; 295 pTreeNode = pLeftMax; 296 } 297 } 298 free(pTreeNode); 299 return TRUE; 300 } 301 return _delete_node_from_tree(pTreeNode); 302 } 303 304 static bool _delete_node_from_tree(TREE_NODE* pTreeNode) 305 { 306 bool TRUE = true ; 307 TREE_NODE* pLeftMax; 308 309 if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child) 310 { 311 if(pTreeNode == pTreeNode->parent->left_child) 312 pTreeNode->parent->left_child = NULL; 313 else 314 pTreeNode->parent->right_child = NULL; 315 } 316 else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child) 317 { 318 pTreeNode->left_child->parent = pTreeNode->parent; 319 320 if(pTreeNode == pTreeNode->parent->left_child) 321 pTreeNode->parent->left_child = pTreeNode->left_child; 322 else 323 pTreeNode->parent->right_child = pTreeNode->left_child; 324 } 325 else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child) 326 { 327 pTreeNode->right_child->parent = pTreeNode->parent; 328 329 if(pTreeNode == pTreeNode->parent->left_child) 330 pTreeNode->parent->left_child = pTreeNode->right_child; 331 else 332 pTreeNode->parent->right_child = pTreeNode->right_child; 333 } 334 else 335 { 336 pLeftMax = find_max_node(pTreeNode->left_child); 337 if(pLeftMax == pTreeNode->left_child) 338 { 339 340 if(pTreeNode == pTreeNode->parent->left_child) 341 pTreeNode->parent->left_child = pTreeNode->left_child; 342 else 343 pTreeNode->parent->right_child = pTreeNode->left_child; 344 345 pTreeNode->left_child->parent = pTreeNode->parent; 346 pTreeNode->left_child->right_child = pTreeNode->right_child; 347 pTreeNode->right_child->parent = pTreeNode-> left_child; 348 349 } 350 else 351 { 352 pTreeNode->data = pLeftMax->data; 353 pLeftMax->parent->right_child = pLeftMax->left_child; 354 pLeftMax->left_child->parent = pLeftMax->parent; 355 pTreeNode = pLeftMax; 356 } 357 } 358 359 free(pTreeNode); 360 return TRUE; 361 } 362 363 /******************下面是完整的测试例子(包含两种测试方法)************************/ 364 365 #include "tree_head.h" 366 367 /*************************************************************************** 368 name:main 369 function description: 370 call same sub function be used to test the create double tree 371 parameters:none 372 return:none 373 **************************************************************************/ 374 375 int main(void) 376 { 377 378 int arr[12]={11,8,7,6,5,4,3,2,1,13,12}; 379 TREE_NODE *node = NULL; 380 TREE_NODE *parent=NULL; 381 TREE_NODE *find=NULL; 382 parent = create_tree_node(10); 383 node = create_double_tree(parent,arr,12); 384 385 #if 1 386 printf(" print data in double tree "); 387 print_all_node_data(node); 388 int num = count_node_number_in_tree(node); 389 printf(" node number is %d ",num); 390 find = find_data_in_tree_node(node,10); 391 printf(" find the data1 is %d ",find->data); 392 find = find_data_in_tree_node(node,1); 393 printf(" find the data2 is %d ",find->data); 394 find = find_data_in_tree_node(node,9); 395 if(find == NULL) 396 printf(" the data %d isn`t in double tree ",9); 397 if(delete_node_from_tree(&node , 10)){ //delete parent 398 printf(" after delete parent print data in double tree "); 399 print_all_node_data(node); 400 } 401 if(delete_node_from_tree(&node , 7)){ 402 printf(" after delete left child print data in double tree "); 403 print_all_node_data(node); 404 } 405 if(delete_node_from_tree(&node , 11)){ 406 printf(" after delete right child print data in double tree "); 407 print_all_node_data(node); 408 } 409 free(node); 410 free(parent); 411 free(find); 412 #endif 413 414 #if 0 415 Manager_mode *this = NULL; 416 int num,data,count=0; 417 char ch[20]={0}; 418 this = alloc_test_mode(); 419 printf("please input test function num such as "); 420 printf(" 0:test_print,1:test_count,2:test_find,3:test_delete ==>:"); 421 scanf("%d",&num); 422 switch(num) 423 { 424 case 0: 425 this->print_all_node_data(node); 426 break; 427 case 1: 428 count=this->count_node_number_in_tree(node); 429 printf(" node number is %d ",count); 430 break; 431 case 2: 432 printf("please input your want find number "); 433 scanf("%d",&data); 434 find=this->find_data_in_tree_node(node,data); 435 if(find) 436 printf(" find the data is %d ",find->data); 437 else 438 printf(" the data %d isn`t in double tree ",data); 439 break ; 440 case 3: 441 printf("please input your want delete number:"); 442 scanf("%d",&data); 443 if(this->delete_node_from_tree(&node,data)) 444 printf("delete :%d ok ",data); 445 else 446 printf("sorry no such data %d ",data); 447 break; 448 default: 449 printf("you input number isn`t [0,1,2,3] "); 450 printf("print the double tree "); 451 this->print_all_node_data(node); 452 exit(1); 453 } 454 free(node); 455 free(parent); 456 if(find!= NULL) 457 free(find); 458 free(this); 459 #endif 460 return 0; 461 }
  • 相关阅读:
    c语言数据处理!
    指针的概念
    return的用处
    用java写随机出题
    java 新手
    分支程序设计。
    不同车型 不同起步价不同费用的问题(switch语句)
    这两天做了很多随机函数的用法(下面是一个出题实验)。
    yum 命令讲解
    日常工作中一些常用命令
  • 原文地址:https://www.cnblogs.com/chengliangsheng/p/3597225.html
Copyright © 2011-2022 走看看