书写是为了更好地思考

导航

 
  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 }

 

posted on 2015-04-14 10:55  lwhile  阅读(144)  评论(0)    收藏  举报