这个二叉排序树写完了,虽然还有些bug,但还是很高兴的。
主要实现二叉排序树的构建。(*表示稍微重要点)
二叉排序树的打印。
二叉排序树的删除。
代码里的三种情况都测了
顺便附送一个简单的中序遍历,递归。
代码现在还有很多内存泄漏,不想改了,明天或者下周改。
主要遇到的小问题:1.排序树的打印,本想链式结构打印出来,但是控制不好,就换了一种简单的方法。
2.内存malloc和free还有很大问题。tips:为什么一般malloc之后,内存释放后NULL指针,现在有点明白,free 那块malloc的内存,不然会形成很多内存碎片,而此时的指针还是指向原先的那块内存地址,只不过数据被free掉了,,p= NULL,这样把指针内容清掉。
3.最不该的错误是2个,一个笔误把=写成了==,找了半个小时的bug,另一个是类型转换,漏掉一个&, PrintBTree((BTREE*) &delNode);//here I forget the sybol &
1 #include <stdio.h> 2 #define ISLCHILD 1 3 #define ISRCHILD 2 4 5 typedef int DATATYPE; 6 typedef struct treenode 7 { 8 DATATYPE data; 9 struct treenode *parent; 10 struct treenode *lchild; 11 struct treenode *rchild; 12 }TreeNode; 13 14 typedef TreeNode* BTREE; 15 TreeNode* InitBTree(DATATYPE oriData[], int size); 16 //TreeNode * GetRootNode(DATATYPE data); 17 TreeNode * GetRootNode(DATATYPE data, TreeNode* newTreeNode); 18 TreeNode *InsertNode(TreeNode* parNode, DATATYPE data); 19 TreeNode *GetFixNode(BTREE *btree, DATATYPE data); 20 void PrintBTree(BTREE* btree); 21 void PrintTreeNode(TreeNode* ); 22 void PrintViewTreeNode(TreeNode* treeNode, int num); 23 void PrintNTab(int i); 24 void DeleteNode(BTREE* btree, DATATYPE delData); 25 int IsLeafNode(TreeNode* Node); 26 TreeNode* GetNodePos(BTREE* btree, DATATYPE Data); 27 int IsLchild(TreeNode* pareNode, DATATYPE sonNode); 28 int IsHasOneChlid(TreeNode *Node); 29 int IsHasTwoChlid(TreeNode *Node); 30 31 TreeNode* GetMaxNodePos(BTREE* btree); 32 void PreTravel(BTREE *btree); 33 //中序遍历 34 void PreTravel(BTREE *btree) 35 { 36 TreeNode* curTreeNode = *btree; 37 if(IsLeafNode(curTreeNode)) 38 { 39 printf("%d ", curTreeNode->data); 40 } 41 else 42 { 43 if((*btree)->lchild!=NULL) 44 { 45 PreTravel((BTREE*)&((*btree)->lchild)); 46 } 47 printf("%d ", curTreeNode->data); 48 if((*btree)->rchild!=NULL) 49 { 50 PreTravel((BTREE*)&((*btree)->rchild)); 51 } 52 53 } 54 return ; 55 } 56 57 TreeNode* GetMaxNodePos(BTREE* btree) 58 { 59 TreeNode* maxTreeNode = *btree; 60 while(maxTreeNode) 61 { 62 printf("NodeValue[%d] ", maxTreeNode->data); 63 printf("NodeValue[%d] ", maxTreeNode->data); 64 printf("NodeValue[%d] ", maxTreeNode->data); 65 66 if(maxTreeNode->rchild == NULL) 67 { 68 break; 69 //return maxTreeNode; 70 }else{ 71 maxTreeNode = maxTreeNode->rchild; 72 } 73 } 74 return maxTreeNode; 75 } 76 77 78 /*1=> has 2 childrean*/ 79 int IsHasTwoChlid(TreeNode *Node) 80 { 81 return ((Node->lchild!=NULL)&&(Node->rchild!=NULL)); 82 } 83 84 int IsHasOneChlid(TreeNode *Node) 85 { 86 if((Node->lchild !=NULL)&&(Node->rchild == NULL)) 87 return ISLCHILD; 88 if((Node->lchild ==NULL)&&(Node->rchild != NULL)) 89 return ISRCHILD; 90 return 0; 91 } 92 93 /* 1——> isLchild */ 94 int IsLchild(TreeNode* pareNode, DATATYPE sonNode) 95 { 96 return (pareNode->lchild->data == sonNode); 97 } 98 TreeNode* GetNodePos(BTREE* btree, DATATYPE data) 99 { 100 //TreeNode* curTreeNode = (TreeNode*)malloc(sizeof(TreeNode)); 101 TreeNode* curTreeNode = *btree; 102 while(//(curTreeNode->data!= data ) 103 1&&(curTreeNode != NULL)) 104 { 105 if(data == curTreeNode->data) 106 { 107 break; 108 } 109 else if(data> curTreeNode->data) 110 { 111 curTreeNode = curTreeNode->rchild; 112 } 113 else if(data < curTreeNode->data) 114 { 115 curTreeNode = curTreeNode->lchild; 116 } 117 118 } 119 return curTreeNode; 120 } 121 122 123 /*1 -> isleaf*/ 124 int IsLeafNode(TreeNode* Node) 125 { 126 return ((Node->lchild == NULL)&&(Node->rchild == NULL)); 127 } 128 129 /* 130 RULE:其删除一个节点需要考虑对应节点的状态,具体的说就是,是否存在左右节点,等等。需要按照以下情况讨论。 131 132 1.查找待删除节点,在查找的同时需要记录一下待删除节点的父亲。 133 134 2.如果待删除节点的左右节点都不存在,那么直接删除(叶子节点)。 135 136 3.如果待删除节点左子树存在右子树不存在,或者左子树不存在右子树存在。直接将其子树中存在的一边候补上来即可。 137 138 4.如果待删除节点左右子树都在,这个情况是最复杂的。需要按照二叉排序树的性质从其左子树或者有子树中选择节点补到待删除节点的位置。 139 140 如果从左子树中选,就应该选择左子树中最右边的那个叶子节点(这里肯定是叶子,如果不是叶子,那么就不是最右边的节点) 141 142 如果从右子树中选,就应该选择有子树中最左边的那个叶子节点。 143 */ 144 void DeleteNode(BTREE* btree, DATATYPE delData) 145 { 146 TreeNode *delNode = GetNodePos(btree, delData); 147 148 if(delNode == NULL) 149 { 150 printf("delNode not exist. "); 151 return ; 152 } 153 /*叶子节点*/ 154 if(IsLeafNode(delNode)) 155 { 156 printf("delNode is leaf node,del directly. "); 157 if(IsLchild(delNode->parent, delData)) 158 { 159 /*in left tree*/ 160 delNode->parent->lchild = NULL; 161 delNode = NULL; 162 } 163 else 164 { 165 delNode->parent->rchild = NULL; 166 delNode = NULL; 167 } 168 return ; 169 170 } 171 172 /*只有一个孩子节点,直接删除*/ 173 if(IsHasOneChlid(delNode) == ISLCHILD) 174 { 175 delNode->lchild->parent = delNode->parent; 176 /*judge the del is the left or right*/ 177 if(IsLchild(delNode->parent, delNode->data)) 178 { 179 delNode->parent->lchild = delNode->lchild; 180 181 } 182 else 183 { 184 delNode->parent->rchild = delNode->lchild; 185 } 186 delNode = NULL; 187 return ; 188 } 189 else if(IsHasOneChlid(delNode) == ISRCHILD) 190 { 191 delNode->rchild->parent = delNode->parent; 192 /*judge the del is the left or right*/ 193 if(IsLchild(delNode->parent, delNode->data)) 194 { 195 delNode->parent->lchild = delNode->rchild; 196 197 } 198 else 199 { 200 delNode->parent->rchild = delNode->rchild; 201 } 202 203 delNode = NULL; 204 return ; 205 } 206 //有左右孩子节点,找出左/右中的最大/小的,替换删除的节点 207 /*I chose the left max to replace the delnode*/ 208 if(IsHasTwoChlid(delNode)) 209 { 210 #if 0 211 printf("TTTTTTTTTTTTTTTTTTTTTTTB "); 212 PrintBTree((BTREE*) &delNode);//here I forget the sybol & 213 printf("TTTTTTTTTTTTTTTTTTTTTTTE "); 214 #else 215 TreeNode* maxTreeNode = GetMaxNodePos((BTREE*)&delNode); 216 printf("MaxTreeNode[%d] ", maxTreeNode->data); 217 maxTreeNode->parent->rchild = NULL;//here = writes to == then ^ ^ 218 maxTreeNode->parent = NULL; 219 delNode->data = maxTreeNode->data; 220 maxTreeNode = NULL; 221 #endif 222 return ; 223 } 224 } 225 226 void PrintNTab(int num) 227 { 228 int i = 0; 229 230 while(i<num) 231 { 232 printf(" "); 233 i++; 234 } 235 } 236 237 void PrintViewTreeNode(TreeNode* treeNode, int num) 238 { 239 num++; 240 printf("%d", treeNode->data); 241 if(treeNode->lchild == NULL) 242 { 243 printf(" "); 244 PrintNTab(num); 245 printf("*"); 246 } 247 else 248 { printf(" "); 249 PrintNTab(num); 250 PrintViewTreeNode(treeNode->lchild, num); 251 } 252 if(treeNode->rchild == NULL) 253 { 254 printf(" "); 255 PrintNTab(num); 256 printf("&"); 257 258 } 259 else 260 { 261 printf(" "); 262 PrintNTab(num); 263 PrintViewTreeNode(treeNode->rchild, num); 264 265 } 266 267 268 } 269 270 /*这个看不出来树的结构了,需要重新写打印方法。*/ 271 void PrintTreeNode(TreeNode* treeNode) 272 { 273 if((treeNode->lchild == NULL) 274 &&(treeNode->rchild == NULL)) 275 { 276 printf("%d ", treeNode->data); 277 } 278 else 279 { 280 if((treeNode->lchild != NULL) 281 || (treeNode->rchild != NULL)) 282 { 283 printf("%d ", treeNode->data); 284 if(treeNode->lchild != NULL) 285 { 286 printf("--->"); 287 PrintTreeNode(treeNode->lchild); 288 } 289 printf("%d ", treeNode->data); 290 if(treeNode->rchild != NULL) 291 { 292 printf("===>"); 293 PrintTreeNode(treeNode->rchild); 294 } 295 } 296 } 297 return ; 298 } 299 300 void PrintBTree(BTREE* btree) 301 { 302 int num = 0; 303 if(btree==NULL) 304 { 305 printf("empty tree. "); 306 } 307 printf("TreeView Rule---若一个节点有左右孩子节点,则父节点一行一列,左右孩子不同行同一列,若无做孩子,则打印的数据用*代替,如果无有孩子则打印的数据用&代替" 308 "另外树的层次用4个空格来体现,比如第1列代表第一层,第5列代表第二层。 " 309 ); 310 printf("***********TREE View BEGIN*********** "); 311 //PrintTreeNode((*btree)); 312 PrintViewTreeNode(*btree, num); 313 printf(" "); 314 printf("***********TREE View END *********** "); 315 printf(" "); 316 317 printf("***********TREE View BEGIN*********** "); 318 printf("rules: ---> lchild. ===> rchild "); 319 PrintTreeNode(*btree); 320 printf(" "); 321 printf("***********TREE View END *********** "); 322 323 } 324 325 326 TreeNode* InitBTree(DATATYPE oriData[], int size) 327 { 328 BTREE* btree = NULL; 329 btree = (BTREE*)malloc(sizeof(BTREE)); 330 *btree = (TreeNode*)malloc(sizeof(TreeNode)); 331 int pos = size; 332 GetRootNode(oriData[0], *btree); 333 TreeNode *posNode = (TreeNode*)malloc(sizeof(TreeNode)); 334 while(pos>1) 335 { 336 printf("********begin one************* "); 337 printf("pos = [%d] index =[%d] data[%d] ", pos, size-pos+1, oriData[size-pos+1]); 338 posNode = GetFixNode(btree, oriData[size-pos+1]); 339 printf("Parent = [%d] Insert data=[%d] ", posNode->data, oriData[size-pos+1] ); 340 InsertNode(posNode, oriData[size-pos+1]); 341 pos--; 342 printf("********end one************* "); 343 344 } 345 346 printf("********btree data %d************* ", (*btree)->data); 347 348 return *btree; 349 350 } 351 352 TreeNode * GetRootNode(DATATYPE data, TreeNode* newTreeNode) 353 { 354 //newTreeNode = (TreeNode*)malloc(sizeof(TreeNode)); 355 newTreeNode->data = data; 356 newTreeNode->parent = NULL; 357 newTreeNode->lchild = NULL; 358 newTreeNode->rchild = NULL; 359 return newTreeNode; 360 } 361 //将一个值插入节点的L/R子树上 362 TreeNode *InsertNode(TreeNode* parNode, DATATYPE data) 363 { 364 if(data == parNode->data) 365 { 366 printf("invaild data %d ", data); 367 printf("invaild para here at line %d. ", __LINE__); 368 return NULL; 369 } 370 TreeNode* sonTreeNode = (TreeNode*)malloc(sizeof(TreeNode)); 371 sonTreeNode->data = data; 372 sonTreeNode->lchild = NULL; 373 sonTreeNode->rchild = NULL; 374 sonTreeNode->parent = parNode;//这里要不要考虑这个链接??? 375 if(data < parNode->data) 376 { 377 parNode->lchild = sonTreeNode; 378 } 379 else{ 380 parNode->rchild = sonTreeNode; 381 } 382 return sonTreeNode; 383 } 384 //查找合适的位置来插入新元素(find parent) 385 TreeNode *GetFixNode(BTREE *btree, DATATYPE data) 386 { 387 if((btree == NULL )) 388 { 389 return NULL; 390 } 391 392 if(((*btree)->lchild == NULL) 393 &&((*btree)->rchild == NULL)) 394 { 395 //InsertNode(*btree ,data); 396 printf("insert under root "); 397 return *btree; 398 } 399 TreeNode* curTreeNode = (TreeNode*)malloc(sizeof(TreeNode)); 400 curTreeNode = *btree; 401 while( (curTreeNode->lchild != NULL) 402 ||(curTreeNode->rchild !=NULL) ) 403 { 404 if(data > curTreeNode->data) 405 { 406 //printf("insert R "); 407 printf(" data=[%d] curData=[%d] insert R ", data, curTreeNode->data); 408 if(curTreeNode->rchild != NULL) 409 { 410 printf("curTreeNode->rchild != NULL rchild[%d] ", curTreeNode->rchild->data); 411 curTreeNode = curTreeNode->rchild; 412 413 }else{ 414 415 break; 416 } 417 } 418 else if(data < curTreeNode->data) 419 { 420 printf(" data=[%d] curData=[%d] insert L ", data, curTreeNode->data); 421 if(curTreeNode->lchild != NULL) 422 { 423 curTreeNode = curTreeNode->lchild; 424 425 }else{ 426 427 break; 428 } 429 } 430 else 431 { 432 printf("invaild elem here at line %d. ", __LINE__); 433 return NULL; 434 } 435 436 } 437 return curTreeNode; 438 439 } 440 441 int main(void) 442 { 443 printf(" Hello World! "); 444 int arr[12]={4, 5, 2, 1,3, 6, 8, 9, 7, 22, 11, 33}; 445 446 //int arr[5]={22, 11, 33, 15, 9}; 447 BTREE *btree = NULL; 448 btree = (BTREE*)malloc(sizeof(BTREE)); 449 *btree = (TreeNode*)malloc(sizeof(TreeNode)); 450 *btree = InitBTree(arr, 12); 451 //*btree = InitBTree(arr, 5); 452 PrintBTree(btree); 453 TreeNode* curTreeNode = (TreeNode*)malloc(sizeof(TreeNode)); 454 455 DeleteNode(btree, 11); 456 PrintBTree(btree); 457 printf("中序遍历: "); 458 PreTravel(btree); 459 460 461 return 0; 462 }
运行结构也贴上来:
Hello World!
********begin one*************
pos = [12] index =[1] data[5]
insert under root
Parent = [4] Insert data=[5]
********end one*************
********begin one*************
pos = [11] index =[2] data[2]
data=[2] curData=[4] insert L
Parent = [4] Insert data=[2]
********end one*************
********begin one*************
pos = [10] index =[3] data[1]
data=[1] curData=[4] insert L
Parent = [2] Insert data=[1]
********end one*************
********begin one*************
pos = [9] index =[4] data[3]
data=[3] curData=[4] insert L
data=[3] curData=[2] insert R
Parent = [2] Insert data=[3]
********end one*************
********begin one*************
pos = [8] index =[5] data[6]
data=[6] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
Parent = [5] Insert data=[6]
********end one*************
********begin one*************
pos = [7] index =[6] data[8]
data=[8] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
data=[8] curData=[5] insert R
curTreeNode->rchild != NULL rchild[6]
Parent = [6] Insert data=[8]
********end one*************
********begin one*************
pos = [6] index =[7] data[9]
data=[9] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
data=[9] curData=[5] insert R
curTreeNode->rchild != NULL rchild[6]
data=[9] curData=[6] insert R
curTreeNode->rchild != NULL rchild[8]
Parent = [8] Insert data=[9]
********end one*************
********begin one*************
pos = [5] index =[8] data[7]
data=[7] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
data=[7] curData=[5] insert R
curTreeNode->rchild != NULL rchild[6]
data=[7] curData=[6] insert R
curTreeNode->rchild != NULL rchild[8]
data=[7] curData=[8] insert L
Parent = [8] Insert data=[7]
********end one*************
********begin one*************
pos = [4] index =[9] data[22]
data=[22] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
data=[22] curData=[5] insert R
curTreeNode->rchild != NULL rchild[6]
data=[22] curData=[6] insert R
curTreeNode->rchild != NULL rchild[8]
data=[22] curData=[8] insert R
curTreeNode->rchild != NULL rchild[9]
Parent = [9] Insert data=[22]
********end one*************
********begin one*************
pos = [3] index =[10] data[11]
data=[11] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
data=[11] curData=[5] insert R
curTreeNode->rchild != NULL rchild[6]
data=[11] curData=[6] insert R
curTreeNode->rchild != NULL rchild[8]
data=[11] curData=[8] insert R
curTreeNode->rchild != NULL rchild[9]
data=[11] curData=[9] insert R
curTreeNode->rchild != NULL rchild[22]
Parent = [22] Insert data=[11]
********end one*************
********begin one*************
pos = [2] index =[11] data[33]
data=[33] curData=[4] insert R
curTreeNode->rchild != NULL rchild[5]
data=[33] curData=[5] insert R
curTreeNode->rchild != NULL rchild[6]
data=[33] curData=[6] insert R
curTreeNode->rchild != NULL rchild[8]
data=[33] curData=[8] insert R
curTreeNode->rchild != NULL rchild[9]
data=[33] curData=[9] insert R
curTreeNode->rchild != NULL rchild[22]
data=[33] curData=[22] insert R
Parent = [22] Insert data=[33]
********end one*************
********btree data 4*************
TreeView Rule---若一个节点有左右孩子节点,则父节点一行一列,左右孩子不同行同一列,若无做孩子,则打印的数据用*代替,如果无有孩子则打印的数据用&代替另外树的层次用4个空格来体现,比如第1列代表第一层,第5列代表第二层。
***********TREE View BEGIN***********
4
2
1
*
&
3
*
&
5
*
6
*
8
7
*
&
9
*
22
11
*
&
33
*
&
***********TREE View END ***********
***********TREE View BEGIN***********
rules:
---> lchild.
===> rchild
4 --->2 --->1
2 ===>3
4 ===>5 5 ===>6 6 ===>8 --->7
8 ===>9 9 ===>22 --->11
22 ===>33
***********TREE View END ***********
delNode is leaf node,del directly.
TreeView Rule---若一个节点有左右孩子节点,则父节点一行一列,左右孩子不同行同一列,若无做孩子,则打印的数据用*代替,如果无有孩子则打印的数据用&代替另外树的层次用4个空格来体现,比如第1列代表第一层,第5列代表第二层。
***********TREE View BEGIN***********
4
2
1
*
&
3
*
&
5
*
6
*
8
7
*
&
9
*
22
*
33
*
&
***********TREE View END ***********
***********TREE View BEGIN***********
rules:
---> lchild.
===> rchild
4 --->2 --->1
2 ===>3
4 ===>5 5 ===>6 6 ===>8 --->7
8 ===>9 9 ===>22 22 ===>33
***********TREE View END ***********
中序遍历:
1 2 3 4 5 6 7 8 9 22 33