数据结构:树
结点拥有的子树数目称为结点的度
要判断是否是一个链:每个点的度数不超过2
多叉树转化为二叉树/森林转化为二叉树:根节点的第一个子节点作为左节点,其他子节点作为新左节点的右子节点。其他树放到上一棵树根节点右子节点的位置上。
二叉树
二叉树的性质:
1)在二叉树的第i层上最多有2i-1 个节点 (i>=1)
2)二叉树中如果深度为k,那么最多有2k-1个节点。(k>=1)
3)n0=n2+1,n0表示度数为0的节点数,n2表示度数为2的节点数。
4)在完全二叉树中,具有n个节点的完全二叉树的深度为[logn]+1,其中[logn]是向下取整。这也是求具有n个节点二叉树最小深度的方法
满二叉树:在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
完全二叉树:对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。有特点:1)叶子结点只能出现在最下层和次下层 2)如果结点度为1,则该结点只有左孩子,即没有右子树 3)同样结点数目的二叉树,完全二叉树深度最小
对于完全二叉树,还有额外的性质:(1) 若 i=1,则该结点是二叉树的根,无双亲, 否则,编号为 [i/2] 的结点为其双亲结点 (2) 若 2*i>n,则该结点无左孩子, 否则,编号为 2*i 的结点为其左孩子结点 (3) 若 2*i+1>n,则该结点无右孩子结点, 否则,编号为2*i+1 的结点为其右孩子结点。
需要额外注意的是,通过包括中序排序在内的两种排序,可以唯一确定一棵树。例题洛谷P1030,根据中序后序求前序,涉及到二叉树的主要操作:
#include<bits/stdc++.h> using namespace std; string str1,str2; struct node { node *l,*r; char c; }tree[50]; int len; void preorder(node *root) { printf("%c",root->c); if(root->l!=NULL){ preorder(root->l); } if(root->r!=NULL){ preorder(root->r); } } node *create(char c) { node *root=&tree[len++]; root->c=c; root->l=root->r=NULL; return root; } node *build(int s1,int e1,int s2,int e2) { node *root=create(str2[e2]); int rootloc=str1.find(str2[e2],s1); if(rootloc>s1){ root->l=build(s1,rootloc-1,s2,s2+rootloc-s1-1); } if(rootloc<e1){ root->r=build(rootloc+1,e1,s2+rootloc-s1,e2-1); } return root; } int main() { cin>>str1>>str2; node *root=build(0,str1.size()-1,0,str2.size()-1); preorder(root); printf("\n"); return 0; }
还有是二叉排序树。二叉排序树按中序遍历,得到的序列恰好是从小到大的排序。因此不同的数字序列得到的不同二叉排序树,最后的中序可能一样。二叉排序树特殊之处在于构建树的过程中。STL中的set,内核就是基于二叉排序树
无根树,无根树指的是无环联通无向图。任意选取某个点为根,可以将无根树转换为有根树。
哈夫曼树
哈夫曼树是一种二叉树,能够使树的带权路径长度和最小。节点的带权路径长度是指节点权值*到根的距离。哈夫曼树可能不唯一,所以大部分问题最后会求最短路径,这种情况下就没有必要构造树的结构,优先队列杠杠的。注意:priority_queue<int>是大顶堆,priority_queue<int,vector<int>,greater<int>>是小顶堆。但是要求具体的编码,可能需要构建二叉树。
还有拓展,k叉哈夫曼树,一次合并k个。原理是一样的,只不过需要预先处理一下,补足0元素,否则会出现前几层有空余的情况。如果还要求哈夫曼树深度最小,排序时以深度作为第二权值,优先选择深度更深的。例题洛谷P2168


浙公网安备 33010602011771号