可解问题
题目中正儿八经构造一颗树的题目不多,但关于运用树的思想却很多,一定要熟练掌握!尤其是树结构在并查集,堆,这些数据结构实用且高效。
- 树的基本操作:
A1115 Counting Nodes in a BST - 树的遍历:
树的前中后层序遍历(已知两种遍历求其他遍历结果)
树的深搜广搜
二叉树的建立 - 二叉搜索树:
二叉搜索树的遍历
二叉搜索树中序遍历的性质 - 完全二叉树:
完全二叉树的静态存储和性质
完全二叉树的判断 - 平衡二叉树:
平衡二叉树的基本操作 - 并查集:查找合并的用途
并查集的基本操作 && 树结构节点与边的数量关系
并查集的优化,高效 - 堆:常用来实现优先队列,优先队列可实现哈夫曼树
堆排序
大小顶堆
专题要点:
- 树的动态结构和静态结构,以及子树表示(二叉树:左右子节点,一般树:vector子节点序列)
- 完全二叉树的性质:
- 可以使用一维数组顺序存放(直接按规律递归访问即可,无需使用结构体指明左右子节点和数据域,而且不需要用-1来代表空树!)
- 一维数组顺序存放的序列,即为完全二叉树层序遍历的结果
- 判断完全二叉树的叶子节点:root * 2 > n(下标为root的左子节点大于节点总个数n)
原因:因为右子节点下标一定大于左子节点,且所有叶子节点均在n内,若该节点左子节点已经超出数据范围,则右子节点一定也超出了 - 判断完全二叉树的空节点:root > n(当前节点下标大于节点总个数n)
原因:叶子节点即二叉树的最后一层节点一定在数据范围n内,若当前节点root超出n,说明连叶子节点都不是,则必为空树。
- 平衡二叉树的左旋右旋和树型的关系:左旋右旋是调整树型的措施。根据具体根节点和子节点的平衡因子,判断当前二叉搜索树的树型,采用对应的左旋右旋操作来调整树结构,使其达到平衡二叉树的结构。(由于内容较多,另写了一篇做详细介绍)
- 并查集:高效查找合并(由于内容较多,另写了一篇做详细介绍)
- 树与堆与优先队列:优先队列的本质是堆,堆的本质是树
- 哈夫曼树与堆:哈夫曼树的实现要借助于小顶堆
几点注意:
- root在二叉树的静态结构和动态结构的区别:
- 数据类型的区别:动态结构为结构体指针(Node*);静态结构中为int类型
- 含义的区别:动态结构中,root为节点在内存中的地址;静态结构中root为节点在结构体数组中的下标。
- 访问内部元素的区别:动态结构中,结构体指针可直接访问内部元素(root->lchild),静态结构中只能通过数组访问元素(nodes[root].lchild)
- 结构体指针变量,root == NULL与 *root == NULL的区别:
root == NULL:表示地址为NULL,代表空树
*root == NULL:表示地址所包含的内容为空,也许节点地址存在,但内容为空(地址存在就不能说明是空树了) - root在递归代码中的含义:在代码中,root并非一个树真正的根节点,root指代递归后,所访问到的当前节点
- 树的基本操作:
- 静态实现root初始化为-1,动态时声明的全局变量*root自动为NULL
- 静态新建节点返回值为结构体数组下标的自增变量
- insert递归建树
- search操作含义:找到在二叉树中所有数据域为x的节点,将其修改为newdata
- 结构体指针变量的构造函数: 必须使用初始化表赋值
struct node
{
int v;
int height;
node*lchild, *rchild;
node(){}
node(int x):v(x),height(1),lchild(NULL),rchild(NULL){}
//要用初始化表,直接赋值不知道为什么会出错
/*//!!!!!!!!!报错!!!!!!!
node(int x)
{
v = x;
height = 1;
lchild = NULL;
rchild = NULL;
}
*/
};
node* root = new node(x);//root仍为结构体指针变量,因此构造函数前要加new
- 插入,删除,左旋,右旋等操作的形参需要引用:因为这些操作是需要直接修改节点的内部元素或结构。
- 遍历:树的dfs等价于先根遍历,bfs等价于层序遍历