1 /* ZQU OJ 1377 二叉查找树 2 插入、查找(包含找最小数)、删除、遍历四大模块 3 */ 4 #include "stdafx.h" 5 #include <iostream> 6 #include <cstdlib> 7 #include <string> 8 #include <cstring> 9 #include <stack> 10 bool FLAG = false; 11 using namespace std; 12 typedef int key_type; 13 typedef struct SerachTree { 14 key_type key; 15 struct SerachTree *LChild, *RChild; 16 }SerachTree, *PNode; //记住结构体这种typedef用法 17 18 /*INSER函数这里,因为需要以一个节点的地址作为实参,所以这里是没必要把Root作为全局变量来使用的*/ 19 void INSERT(key_type insert_num, PNode *root) { //用二级指针作为函数参数,用来修改从主函数传过来的Root指针指向的地址。 20 //初始化一个临时节点 21 PNode tmp = (PNode)malloc(sizeof(SerachTree)); 22 tmp->key = insert_num; 23 tmp->LChild = tmp->RChild = NULL; //tmp的作用是临时节点 24 //当为空树时 25 if ((*root) == NULL) { //root是Root的地址,*root = x 用来修改Root的指向 //当然用Root也行,但是这里是通过函数传递的形式来完成的 26 *root = tmp; 27 return; 28 } 29 //树非空 30 //root是二级指针,没有被分配一个SerachTree单位,所用*root指向Root,&(*root)->x 传入地址 31 else { 32 if (insert_num < (*root)->key) //递归,以左儿子做新的根节点 33 INSERT(insert_num, &(*root)->LChild); 34 if (insert_num >(*root)->key) //递归,以右儿子做新的根节点 35 INSERT(insert_num, &(*root)->RChild); 36 } 37 return; 38 } 39 40 PNode FIND(key_type find_num, PNode point) { //这里没有涉及到对数据的修改,不需要二级指针 41 //PNode res = NULL; 42 //cout << "point:" << endl; 43 // cout << point->key << ' ' << (point->LChild) << ' ' << point->RChild <<endl; 44 //point = (PNode)malloc(sizeof(SerachTree)); //不能再分配内存(传入一个地址,这个地址指向已有的结构体,不需要开新内存) 45 //cout << "@" << endl; 46 /* 47 这里要注意不能cout出空指针指向的单元,不然会引发segmentation fault,切记。 48 可以cout空指针的地址,但不能cout"空指针指向的内容“。 49 */ 50 if (point == NULL) //节点为空时,返回一个NULL。这里作为递归基 51 return NULL; 52 if (find_num == point->key) { 53 //cout << "point->key=" << point->key << " point->LChild=" << point->LChild << " point->RChild=" << point->RChild <<endl; 54 return point; //如果找到了相等的元素,就返回这个节点的地址 55 } 56 else { 57 //往左边走 58 if (find_num < point->key /*&& point->LChild != NULL*/) 59 FIND(find_num, point->LChild); 60 //往右边走 61 else if (find_num > point->key /*&& point->RChild != NULL*/) 62 FIND(find_num, point->RChild); 63 else return NULL; 64 /*判断左右儿子是否为空可不下*/ 65 } 66 67 //return res; 68 } 69 70 //遍历二叉树,中序 71 void TRAVERSE(PNode N) { 72 /*背代码,不解释。*/ 73 74 //如果该树为空 75 //cout << "N->key=" << N->key <<endl; 76 //N = (PNode)malloc(sizeof(SerachTree) ); 77 // cout << N->LChild << ' ' << N->RChild << endl; 78 //FLAG = false; 79 80 if (N != NULL) { 81 //if(N->LChild != NULL) 82 //FLAG = true; 83 TRAVERSE(N->LChild); 84 // else return; 85 cout << N->key << ' '; 86 //if(N->RChild != NULL) 87 TRAVERSE(N->RChild); 88 //else return; 89 } 90 else return; 91 } 92 PNode FindMin(PNode T) { //FindMin用来查找当前树中最小的元素,注意返回形式是一个PNode类型的指针,指向这个最小元素的地址 93 if (T == NULL) 94 return NULL; 95 if (T->LChild == NULL) 96 return T; 97 else 98 FindMin(T->LChild); 99 } 100 void DELETE(key_type delete_num, PNode *N) { //设计到树中元素的修改,用二级指针 101 PNode TmpCell; //也是一个临时节点,需要的时候直接赋值用 102 TmpCell = (PNode)malloc(sizeof(SerachTree)); //因为要往里面放入一个SerachTree类型数据,开辟新内存是必须的 103 //空树 104 if ((*N) == NULL) //如果这棵树是空的,那就无所谓删除了,直接返回 105 return; 106 107 /*下面这两个else if语句都是用来不断递归,直到定位到那个要被删除的元素为止*/ 108 else if (delete_num < (*N)->key) { 109 DELETE(delete_num, &(*N)->LChild); 110 } 111 else if (delete_num >(*N)->key) { 112 DELETE(delete_num, &(*N)->RChild); 113 } 114 115 /*被删除的节点有一个儿子或者是叶节点,和它有两个儿子的删除方式是不一样的*/ 116 117 //如果被删除的节点有两个儿子(此时已近定位到那个被删除元素了) 118 else if ((*N)->LChild && (*N)->RChild) { 119 TmpCell = FindMin((*N)->RChild); /*调用FindMin函数,找到右儿子树最小的节点 120 为什么是右儿子?右儿子可以保证它所有的元素都能被插入到待会要被删除的节点,而不违反二叉树的定义*/ 121 (*N)->key = TmpCell->key; //把找到的最小元素放进此时定位的那个节点 122 DELETE((*N)->key, &(*N)->RChild); //此时不断递归。以那个被找到右子树最小元素作为被删除的节点 123 //为什么这么做?为了让这棵树能够符合二叉树的定义。 124 } 125 //一个儿子||叶节点 126 //坑了我好久的亮点来了! 127 else { 128 TmpCell = *N; //先把要删除的节点赋值给TmpCell 129 if ((*N)->LChild == NULL/* && (*N)->RChild != NULL*/) 130 *N = (*N)->RChild; //如果左节点为空,则把右节点赋给*N 131 else if ((*N)->RChild == NULL/* && (*N)->LChild != NULL*/) 132 (*N) = (*N)->LChild; //如果右节点为空,则把左节点赋给*N 133 134 /* 135 else 一定要加!一定要!。因为如果进入前面的if语句意味着LChild是空的,不能在下面再赋值一次。 136 至于后面被注释掉&&的内容,也是同样类型的错误 137 */ 138 139 free(TmpCell); //free释放TmpCell指向那个内存单元的内容(注意是指向的那个内存单元) 140 //(*N )= NULL; 141 TmpCell = NULL; //释放后TmpCell还是存在的,定义为NULL防止野指针的出现 142 return; 143 } 144 145 } 146 int main() 147 { 148 /*main函数的形式主要是为了过我们学校的OJ题*/ 149 string command; 150 int command_num; 151 PNode Root; //创建根节点,此时为空 152 Root = (SerachTree*)malloc(sizeof(SerachTree)); //为其分配内存,这一步必须要! 153 Root = NULL; //将根节点指向空,这一步必须要! 154 //Root->LChild = Root->RChild = NULL; 这一步不能下,Root此时为空,不存在LChild和RChild,使用会引起段错误 155 while (cin >> command) { 156 //getchar(); 157 if (command != "traverse") { 158 //cout << '!'; 159 cin >> command_num; 160 //cout << command << endl; 161 if (command == "insert") 162 INSERT(command_num, &Root); //调用插入函数(注意传入的是地址) 163 //cout <<Root; 164 if (command == "find") { 165 string find_res[2] = { "yes", "no" }; 166 if (FIND(command_num, Root) != NULL) { 167 cout << find_res[0] << endl; 168 } 169 else cout << find_res[1] << endl; 170 } 171 if (command == "delete") { 172 DELETE(command_num, &Root); 173 } 174 } 175 else if (command == "traverse") { 176 //cout << command <<endl; 177 FLAG = false; 178 TRAVERSE(Root); 179 if (FLAG) 180 cout << endl; 181 } 182 } 183 }
浙公网安备 33010602011771号