树
基本定义:
树是一种非线性数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。
与树相关的常见概念:
空集合也是树,称为空树。空树中没有节点;
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
节点的度:一个节点含有的子节点的个数称为该节点的度;
叶节点或终端节点:度为0的节点称为叶节点;
非终端节点或分支节点:度不为0的节点;
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
兄弟节点:具有相同父节点的节点互称为兄弟节点;
树的度:一棵树中,最大的节点的度称为树的度;
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次;
堂兄弟节点:双亲在同一层的节点互为堂兄弟;
节点的祖先:从根到该节点所经分支上的所有节点;
子孙:以某节点为根的子树中任一节点都称为该节点的子孙;
森林:由m(m>0)棵互不相交的树的集合称为森林。
树的深度:离根节点最远的点到根节点的最短路程
节点深度:离该点最远的点到该点的最短路程
二叉树
定义:
所有节点的度不超过2的树称为二叉树
因为每个二叉树的节点最多只会有2个子节点,它的两个子节点一般会被称为左右儿子,两棵子树一般被称为左右子树。左右儿子或根节点可以缺失(一个节点也没有可以被称为空二叉树)。
两种特殊的二叉树:
完全二叉树:除最后一层外其它层的节点个数全满,且最后一层的节点从左到右排满直到最后一个节点(深度为h的完全二叉树节点个数在区间[,
]内)。
满二叉树:所有层的节点全满(深度为h的满二叉树有个节点)。
完全二叉树的存储:
顺序存储:
void Build(int t)
{
//添加数据
UpdateData(t);
//如果子节点存在
Build(t+t);
Build(t+t+1);
}
struct TreeNode{
int value;
int l,r,fa;
};
以指针的形式存储:
struct TreeNode{
int value;
TreeNode *l,*r,*fa;
}
TreeNode *root;
新建节点:
struct TreeNode{
int value;
TreeNode *l,*r,*fa; //初始化为NULL
TreeNode(int x){value = x;}
}
TreeNode *p = new TreeNode(x);
根节点初始化:
TreeNode *root;
root = new TreeNode(v);
插入子节点:
void insert(TreeNode *fa,TreeNode *p,int flag) //falg=0则插入到左边,否则则插入到右边
{
if(!flag)
fa->l=p;
else
fa->r=p;
p->fa=fa;
}
TreeNode *p=new TreeNode(v);
Insert(fa,p,flag);
二叉树的遍历:
先序遍历(根左右):
//先序遍历(DLR)
void PreOrder(TreeNode *p)
{
cout << p->value << endl;
if(p->l) PreOrder(p->l);
if(p->r) PreOrder(p->r);
}
PreOrder(root);
中序遍历(左根右):
//中序遍历(LDR)
void InOrder(TreeNode *p)
{
if(p->l) InOrder(p->l);
cout << p->value << endl;
if(p->r) InOrder(p->r);
}
InOrder(root);
后序遍历(左右根):
//后序遍历(LRD)
void PostOrder(TreeNode *p)
{
if(p->l) PostOrder(p->l);
if(p->r) PostOrder(p->r);
cout << value << endl;
}
PostOrder(root);
层级遍历(BFS序列):
TreeNode *q[N];
void Bfs(TreeNode *root)
{
int front = 1,rear = 1;
q[1] = root;
while(front <= rear)
{
TreeNode *p = q[front++];
cout << p->value << endl;
if(p->l) q[++rear] = p->l;
if(p->r) q[++rear] = p->r;
}
}
Bfs(root);
例题:
最近公共祖先问题(LCA):
简单解法:
#include<bits/stdc++.h>
#define rep(i,l,r) for(int i = l;i < r; i++)
#define per(i,r,l) for(int i = r - 1;i >= l;i--)
#define ll long long
using namespace std;
struct TreeNode
{
int l, r, fa;
}a[1001];
int main()
{
int n;
cin >> n;
rep(i, 1, n+1)
{
int l, r;
cin >> l >> r;
if (l)
{
a[i].l = l, a[l].fa = i;
}
if (r)
{
a[i].r = r, a[r].fa = i;
}
}
int u, v;
cin >> u >> v;
int b[1001], c[1001], l1=0, l2=0;
while (u!=1)
{
b[++l1] = u, u = a[u].fa;
}
b[++l1] = 1;
while (v!=1)
{
c[++l2] = v, v = a[v].fa;
}
c[++l2] = 1;
int ans = 0;
for (int i=l1,j=l2;i&&j;i--,j--)
{
if (b[i] == c[j])
ans = b[i];
else
break;
}
cout << ans;
return 0;
}
复杂解法(BFS):
#include<bits/stdc++.h>
using namespace std;
struct TreeNode
{
int depth;
int l, r, fa;
}a[1001];
int main()
{
int n;
cin >> n;
for (int i = 1; i < n+1; i++)
{
int x, y;
cin >> x >> y;
if (x)
a[i].l = x, a[x].fa = i;
if (y)
a[i].r = y, a[y].fa = i;
}
int q[1001], rear=1, front;
q[1] = 1, front = 1, a[1].depth = 1;
while (front<=rear)
{
int p = q[front++];
if (a[p].l)
q[++rear] = a[p].l, a[a[p].l].depth = a[p].depth + 1;
if (a[p].r)
q[++rear] = a[p].r, a[a[p].r].depth = a[p].depth + 1;
}
int u, v;
cin >> u >> v;
if (a[u].depth < a[v].depth)
swap(u, v);
int x = a[u].depth - a[v].depth;
for (int i = 1; i <= x; i++)
u = a[u].fa;
while (u!=v)
u = a[u].fa, v = a[v].fa;
cout << u;
}
二叉树的子树和:
#include<bits/stdc++.h>
#define rep(i,l,r) for(int i = l;i < r; i++)
#define per(i,r,l) for(int i = r - 1;i >= l;i--)
#define ll long long
using namespace std;
struct TreeNode
{
int value;
int l, r, fa;
};
int ans[1000002];
TreeNode a[1000002];
inline int PreOrder(int t)
{
int x = a[t].value;
if (a[t].l)
x += PreOrder(a[t].l);
if(a[t].r)
x += PreOrder(a[t].r);
ans[t] = x;
return x;
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
int x, y;
cin >> x >> y;
if (x)
a[i].l = x, a[x].fa = i;
if (y)
a[i].r = y, a[y].fa = i;
}
for (int i = 1; i <= n; i++)
{
int v;
cin >> v;
a[i].value = v;
}
memset(ans, 0, sizeof(ans));
PreOrder(1);
for (size_t i = 1; i <= n; i++)
{
cout << ans[i] << " ";
}
return 0;
}