为什么最近总是想敲代码,因为从书上学到的比如数据结构和算法设计等总是没有编程实现过,趁着这段时间较有空,所以练一练,尤其可以顺便练练指针和递归的写法(C两大难点)。
碰到第一个题目叫“树的基本操作”,是一道二叉排序树的建立和递归输出。
关于二叉排序树的概念就理解很久,才发现,原来每次插入都是从根比较起而分左右,而不是和其上一个父节点比较。和标准输入输出对应后验证理解正确开始写代码。
对于树的题目,还是习惯用struct构造,并添加newnode()、deletenode()等框架性的东西,习惯用指针来操作而不是用数组(虽然也可以)。按照题目,一次编写了newnode()、buildtree()、printtree_1()、printtree_2()、printtree_3()、deletenode()函数。
其实,我只是想记下容易出错的地方:
1、构造Node结构体时,在构造函数中会用到this,注意它是指针不是实例,所以应该this->a而不是this.a。
2、为什么newnode函数中需要new,因为它返回的是指针,所以需要用new创建一个地方提供给指针返回,而不是直接例化就行的。
3、关于二叉排序树,注意与结点相等时应该怎么处理,根据实际需求。由于建树有递归的概念,因为是依次比较结点(从根节点,到左或右结点,再到下一层左或右结点)。其实递归调用函数只需要把函数当成一个相同功能不同参数的盒子,反而重点是如何确定结束递归的条件。
void buildtree(Node* p,int m){ //务必理解过程
if(m<(p->a) ){
if(p->left!=NULL ) buildtree(p->left,m);
else p->left=newnode(m);}
if(m>=(p->a) ){
if(p->right!=NULL ) buildtree(p->right,m);
else p->right=newnode(m);}
}
4、我定义的left和right都是指针,所以还是那个问题,用->而不是.。
5、当然也可以不用递归,那就用for或者while呗。但是注意循环和递归不能同时用,否则就停不下来了,一般递归是和if一起用的。
6、关于三种遍历的方法没啥好说的,就是记住顺序就行还有递归的写法就行了。注意是if,不是while。
void printtree_2(Node* p){ //中序,左根右
if(p->left!= NULL) printtree_2(p->left); //不是while,递归已经包含循环的概念
cout<<p->a<<"";
if(p->right!= NULL) printtree_2(p->right);
}
7、delete的使用是和new一起的,以防内存泄漏。用oj的时候的确发现用delete会减少内存,只是直观上,养成习惯吧。删除结点也是用的递归(看成盒子),注意先删子节点再网上删父节点,否则删不干净。
8、关于二叉排序树还有个删除结点的问题,这个问题还比较复杂...找本严蔚敏看看吧...