

两个结点之间的路径只能是 从上往下



把森林通过结点连起来就是一棵树
























线索二叉树之后讲解

root->data直接赋值了{1},是因为 data是结构体 ElemType类型的,给ElemType类型的赋值{1},相当于给结构体类型的ElemType整体赋值。











以下占用了函数调用栈的空间,随着深度h的变化,函数调用栈被占用的空间越多。












由上面中序、前序、后序、层序可知给出 遍历序列 并不能直接还原唯一的二叉树形态。

对前+中 、后+中、层+中都适用:找到树的根节点,并根据中序序列划分左右子树,再找到左右子树根节点。











将二叉树 线索化 后,查找结点的前驱、后继就更方便、容易了。







如:中序前驱就是,如果按照中序进行遍历,他的前驱是哪个。



如图位置后,q指向C,q->lchild != null,不执行下面红框1 的程序,

pre指向F,pre!=null && pre->rchild=null,所以建立F右边那条紫色的连接。执行红框2的程序。
之后执行红框3 pre=q。



如图,q指向D,q->lchild=null,q->lchild=pre,q->ltag=1后,本来q的左孩子是空,但是当执行PreThread(T->lchild)时,T->lchild由于刚才线索化了,此时等于之前的 pre指向的B,T->lchild等于B 不等于null,所以又回去执行visit(B)了,这是不好的。

为解决上面问题,在下图中添加箭头指的一句代码 if(T->ltag==0)来判断他有无 真正的左子树,而不是线索。


后序线索化中不会出现先序线索化中转圈的问题。因为是后序先访问左子树,右子树,最后访问根,所以当我们访问一个结点q的时候,这个结点他左孩子那条路已经处理完了,右孩子那条路也处理完了,所以我们访问完这个结点后,不会回头去重新访问左孩子所指向的那棵子树和右孩子所指向的那棵子树了,所以也就不会出现转圈的问题了。





根节点p的前驱 应该是左子树中按照中序遍历最后一个结点。即左子树中最右下的结点





下面改为在三叉列表的情况下,多一个指向父结点的指针。

最右边图示的解释:
根左右,
左子树的最右下边,
如果最右下那个结点有左子树,那么在取该左子树,
如果该左子树有右子树,那么该取最右下边右子树,
总之就是沿着最右边往下走,遇到左边沿着最左边往下走,遇到右边沿着最右边往下走。。。。。。



下面改为在三叉列表的情况下,多一个指向父结点的指针。








找孩子很方便,找双亲不方便

用孩子兄弟表示法存储的树 在物理上 呈现出“二叉树”的样子。







通过孩子兄弟表示法 转化为二叉树(左孩子右兄弟)


通过孩子兄弟表示法 转化为二叉树(左孩子右兄弟)

森林转化为树后,森林的中序遍历转化为树的后根遍历;
森林转化为二叉树后,森林的中序遍历转化为二叉树的中序遍历。





利用 可变长度编码 可以压缩数据,用更少的比特表示同样多的数据

如果A不用10来编码,用1来编码,那么A就不是叶子节点了,会造成解码的误解。如下图右边所示,
比如111不知道是3个A还是1个B了。


并查集本质上是表示一种集合的逻辑关系,而这个集合要实现的基本操作是并和查。





双亲表示法更有效:
查就是一路向上找到根节点,可以通过比较根节点是否相同来判断是否是同一个集合。
并就是将其中一棵树的根节点指向另一棵树的根节点。








上图说明要想时间复杂度低,树就不能太高太长,
优化思路:在每次Union操作构建树的时候,尽可能让树不长高高








