主要写知识结构
1.树
1.1树的定义、性质
1)n个结点的树有n-1条边、即度数为n-1.
2)度m某层最多节点、高度h度m最大结点数、度m结点n最大高度
1.2结点类型及其关系
1.3数据存储结构
双亲(顺序)
孩子(顺序结构存储单链表)
孩子兄弟(二叉链表)(转换为二叉树)
2.二叉树
2.1二叉树的定义
2.1.1特点
4.1.2特殊二叉树(斜树、满二叉树、完全二叉树
完全二叉树度1结点数为0/1.
2.2.二叉树的性质
1)i层至多结点数、k深度至多结点数、n个结点完全二叉树的深度、n个结点的完全二叉树第i个结点与其双亲、左右孩子的下标的关系
2)树的度数之和(分支数)+1=总结点数
3)n0=n2+1:终端结点数和度为2的结点数关系
4)n空=n+1:n个结点二叉表有n+1个空链域
2.3.二叉树的存储结构(顺序存储、二叉链表(链式存储))以及不同存储方法的前中后序、层序遍历
中+前/后可确定一棵二叉树
2.3.1顺序存储
//将二叉树按照完全二叉树的层序存储在数组中,缺点是浪费存储空间
//先序、中序、后序遍历
void PreTraverse(SqBiTree T,int e) {
//根左右、先序
visit(T[e]);//中序、后序修改访问顺序即可
if (T[2 * e + 1] != Nil)
PreTraverse(T, 2 * e + 1);
if (T[2 * e + 2] != Nil)
PreTraverse(T, 2 * e + 2);
}
Status PreOrderTraverse(SqBiTree T) {
if (T[0] != Nil)
//若为空则不操作
PreTraverse(T, 0);
printf("\n");
return OK;
}
2.3.2链式存储
typedef struct BiTNode
{
//二叉树结点结构
TElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode,*BiTree;
//前序中序后序遍历
void PreOrderTraverse(BiTree T) {
if(T==NULL)
return;
visit(T->data);//中序后序变个位置即可
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
对于链式存储,前序创建(根据扩展二叉树)、后序销毁
//前序非递归
void PreOrderTraverse2(BiTree T) {
InitStack(S);//初始化一个栈
BiTree p=T;
while (p||!IsEmpty(S)) {
if (p) {
push(S,p);
visit(p->data);//中序就在pop(S, p);之后visit
p = p->lchild;
}
else {
//后序在这里需要判断栈顶元素右孩子是否存在且未被访问并进行后续操作
pop(S, p);
p = p->rchild;
}
}
}
链式存储的前中后序遍历非递归算法需要用到栈,并且前序序列相当于入栈顺序,中序序列相当于出栈顺序(分析代码可知),故根据确定的前序序列可以根据卡罗尔公式计算出确定数量的中序序列,即决定一定数量的二叉树。1/(n+1)*C(n 2n)
后序遍历的非递归算法可以使用栈存储两节点间的路径,前序中序可能提前出栈,当子孙结点在祖先结点的右子树上时。王道数据结构p151
层序遍历用到队列
3.线索二叉树,一种物理结构
左前驱右后继
//线索二叉树
typedef struct BiThrNode
{
TElemType data;
struct BiThrNode* lchild, * rchild;
PointerTag LTag, RTag;
}BiThrNode,* BiThrTree;
中序遍历可线索化为线索二叉树
根据其线索可实现非递归的中序遍历算法(找左下结点、根据rchild访问后继,右孩子的左下结点或者是线索)
以及前序、后序的线索化,其中,后序由于度为2的结点右孩子和其后继结点不同,故其遍历后序线索二叉树时还需要知道额外的信息(结点的双亲),需要栈的支持。
4.树、森林、二叉树的转换
树的遍历:前根后根对应二叉树前序中序
森林的遍历:前序、中序对应二叉树前序中序
森林和树中非终端结点数+1等于相应二叉树中右指针域为空结点数,叶结点数等于相应二叉树左孩子为空结点数
5.树与二叉树的应用
哈夫曼树、哈夫曼编码
哈夫曼树度为m。结点数n的非叶结点个数为(n-1)/(m-1):根据度数等于分支数等于总结点数-1推算出。
并查集