突发奇想的想写一些关于树的用法,以后把经常用到的或者觉得重要的用法都给整理下来,好复习用。
因为用得比较多的是二叉树,所以先说一些二叉树的性质:
性质1:二叉树第i层上的结点数目最多为2i-1(i >= 1);
性质2:深度为k的二叉树至多有2k-1个结点(k >= 1);
性质3:包含n个结点的二叉树的高度(k)至少为(log2n)+1(k >= 1);
性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0 = n2 +1。
二叉树的遍历:
前序遍历:根——左——右
中序遍历:左——根——右
后序遍历:左——右——根
满二叉树、完全二叉树
一、满二叉树
定义:高度为k(k >= 1),且节点个数为2k-1的二叉树,称为满二叉树。
特点:最高层全为叶子节点。
二、完全二叉树
定义:若设二叉树的深度为k,除第k层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k层所有的结点都连续集中在最左边,这就是完全二叉树。
特点:完全二叉树中节点的度为1的节点个数为1或0。
用法:
①根据边(无向图)的关系来建立二叉树(将边的权值问题转换为节点的权值问题):
edgeweight[x][y] 保存节点x、y之间权值 tree[x][0]/[1]表示根节点x的左孩子/右孩子结点 pointweight[p]表示节点p的权值
build(root, c, lor):建立根节点root与孩子节点c的关系,lor == 0表示左孩子, lor == 1表示右孩子
在建立结点关系的时候,可以将root与c之间边的权值保存到子节点c中,这样就实现了将边的权值问题转换为节点的权值问题了
make_tree(root):以root为根节点建立二叉树,遍历edgeweight[root][k(0~end)]
如果遇到root与k有边的关系,则让k成为root的孩子节点(第一次为左孩子,第二次为右孩子(根据题目需求来))
需要注意的是在用build建立关系时,需要在建立完成后让edgeweight[root][k] 与 edgeweight[k][root] 的权值无效化,防止形成环
#define ineffective -1
vector<vector<int> > edgeweight, tree;
vector<int> pointweight;
void make_tree(int root);
void build(int root, int c, int lor) {
tree[root][lor] = c;
pointweight[c] = edgeweight[root][c]; //边权值转换为点权值
//使边的权值无效化,防止再次建立关系
edgeweight[root][c] = edgeweight[c][root] = ineffective;
make_tree(c); //递归建树
}
void make_tree(int root) {
int lor = 0;
for (size_t i = 0; i < edgeweight[root].size(); ++i) {
if (edgeweight[root][i] != ineffective) {
build(root, i, lor++);
if (lor > 1) break;
}
}
}