家谱构建第一步,就是要理解内存。树实际上就是一个多叉链表,一个数据域,几个指向跟自己有关系的元素的指针域,就
构成了树的结点。而要建立链表,把一个一个结点赋值,就要传指向它们的指针BiTree了,这样才能修改结点的值。因为通过
子函数来建立一棵树,每开辟一个新节点,就malloc动态申请一块内存区域,这块区域在堆区,子函数结束时不会销毁。
但在主函数里定义一棵树,一定要把树的地址传到子函数里,这样才能修改即给树添加结点建立一棵树,在子函数里给树的
根节点(*T)动态申请一块内存,把输入的值赋过去,就构造好了根节点。而之后的结点,就通过不断地malloc构造新节点,
然后利用结点的各种指针域,赋值,把它们连接起来。连接的过程用到的是在子函数里定义的临时BiTree指针变量,只是通过
它们实现链接。而我们刚开始已经抓住了“绳子的头”(*T),就可以把树直接拿来操作啦。
理解了子函数的参数类型,就剩下思路了。刚开始我没有父亲节点,几个子函数勉强写出了,可是到删除某人的时候实在做不
下去了,后来加上父亲节点发现再缕思路的时候真是得心应手。历时三天半,我的第一棵树终于告一段落啦。
这里关键是建树和遍历,完成这两部分,基本就算写完了。建树,家谱要用层序建树,这里用到队列,利用它先进先出的排队
性质,从根节点开始,每一层从左到右遍历着赋值,先根节点入队列,用一个BiTree类型的变量接收根节点出队列,循环从此
展开,手动判断有无孩子,若有,连到lchild域,判断有没有孩子也是一个循环,设定一个标志,若一直有,则循环把新孩子
尾插到rsib兄弟结点,同时当把新结点连到旧结点的时候,新节点入队列,直到输入不再有孩子。这时候第一个入队列的节点
即左孩子出队列,重复以上先判断有无左孩子,把孩子们链接到上一个对应结点并入队列的过程,队列实现了每一层从左到右
的顺序插入,遍历,实现了层序。
然后,插入删除增加查询,查询时可以升级到查出一个人连带他的祖宗们兄弟们儿子们,还有问有没有孩子的时候,记得把当前
结点的名字打印出来,更只能人性化一点。
查询,在遍历的基础上,找到这个人,若是祖先,只打印儿子们;若不是,利用父亲指针找到父亲,循环找到祖宗,再找兄弟,
两种情况,若是父亲的左孩子,依次打印右兄弟,若不是左孩子,则从左孩子开始依次打印父亲的孩子,通过判断跳过本身。
再找儿子,依次遍历打印。
增加儿子,在遍历的基础上,找到要增加儿子的父亲节点,若没有左孩子,。。。若有左孩子,尾插。
增加兄弟,在遍历的基础上,找到要增加兄弟的节点,新节点尾插到最后那个兄弟的右兄弟域。
删除儿子,在遍历的基础上,找到要删除的儿子指针,若本身是父亲左孩子,,,,若不是,,,,。
删除兄弟,在遍历的基础上,找到要删除的兄弟结点,若是父亲左孩子,,,,若不是,,,,。
删除某个人,在遍历的基础上,找到要删除的结点,若是祖宗,,,若是父亲左孩子,,,若不是,,,。
注意删除某个人要把他的子子孙孙都删掉。
删除添加操作都要改变一棵树,所以需要传树的地址,二级指针。把树的根节点地址传进去,中间的临时变量不用设为指针类型。
free()括号里是指针变量,销毁指向部分的内存。
释放一棵子树的时候,要提前把它的右兄弟置为NULL,否则无法通过后序遍历释放节点空间。
主函数:
#include<stdio.h>
#include"B