树型结构是一类重要的非线性结构
树型结构是一对多的关系
结点个数 = 边数 + 1
树 = 根节点 + 子树 子树 = 根节点 + 子树 子树 = 根节点 + 子树
树是用递归来定义的结构
父节点:直接前驱,根节点没有父节点
结点的度:就是孩子的数量
树的度:就是所有结点中,度的最大值
树的高度:一共有多少层
两个结点之间的路径:两个结点之间的最短路径
树可以分为有序树和无序树:有序树:结点的子树按照从左往右的顺序排列,不能更改。无序树:结点的子树没有顺序,随意更改
树还可以分为有根树和无根树:有根树:树的根是固定的。无根树:树的根结点是不固定的,谁都可以是根结点
无根数会导致父子关系不明确,在存储的时候需要注意
孩子表示法:对于每个结点,只存储所有孩子的信息,但是问题是对于无根树来说父子关系不明确的情况下怎么办------把与孩子相连的结点都存下来
孩子表示法 解决方法一:vector实现:先创建一个大小足够的vector数组 vector<int> edgei; 对于i的孩子,直接edgei.push_back 进去即可 i 括号里面存这i号结点的所有孩子
const int N = 1e5 + 10;
int n;
int main()
{
cin >> n;
for(int i = 1; i < n; i++)
{
int a,b;
cin >> a >> b;
//表示a和b之间有1条边
edgea.push_back(b);
edgeb.push_back(a);
}
return 0;
}
解决方法二:链式前向星:本质是用链表示存储所有的孩子,其中链表是可以用数组模拟实现的
1、创建一个足够大的数组h,作为所有结点的哨兵位
2、创建两个足够大的数组e和ne,一个作为数据域,一个作为指针域
3、一个变量id,标记新来结点存储的位置
当x有一个孩子y的时候,就把y头插到x的链表中
int hN,eN\*2,id;
int n;
//其实就是把b头插到a所在的链表后面
void add(int a,int b)
{
id++;
eid = b;
neid = ha;
ha = id;
}
int main()
{
cin >> n;
for(int i = 1; i < n; i++)
{
int a,b;
cin >> a >> b;
//a和b之间有一条边
add(a,b);
add(b,a);
}
return 0;
}
树的遍历:树的遍历就是要不重不漏的将树中所有的点都扫描一遍
树的深度优先遍历DFS:是一种用于遍历或搜索树图的算法,这种方法中特点是 --- 每次都尝试向更深的结点走,一条道走到黑,走到不能再走为止,这个时候就回去,去找别的路。从根节点开始 ---- 找到一个没有访问过的孩子,以孩子为根 (这是一种递归形式的遍历)
//用链式向前存储后遍历
const int N = 1e5 + 10;
int hN,eN\*2,neN,id;
int n;
void add(int a,int b)
{
id++;
eid = b;
neid = ha;
ha = id;
}
void dfs(int u)
{
cout << u << " ";
stu = true;
for(int i = hu; i; i = nei)
{
int v = ei;
if(!stv)
{
dfs(v);
}
}
}
int main()
{
//建图
cin >> n;
for(int i = 1; i < n; i++)
{
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
//深度优先遍历
dfs(1);
return 0;
}
//用vector存储后遍历
const int N = 1e5 + 10;
int n;
vector<int> edgeN; //存储图
bool stN; //标记那些已经访问过了的
void dfs(int u)
{
cout << u << " ";
stuu = true; //当前u这个点已经访问过了
for(auto v : edgeu)
{
if(!stv)
{
dfs(v);
}
}
}
int main()
{
//建图
cin >> n;
for(int i = 1; i < n; i++)
{
int a,b;
cin >> a >> b;
edega.push_back(b);
edgeb.push_back(a);
}
//深度优先遍历
dfs(1);
return 0;
}
宽度优先遍历:又名广度优先遍历或层序优先遍历BFS:就是每次都尝试访问同一层的结点,如果同一层访问完了,就再访问下一层
1、创建一个队列,辅助BFS
2、根节点入队
3、若队列不为空,对头结点出队并访问该结点,然后将该结点的孩子依次入队
4、重复3过程,直到队列为空
//用vector
const int N = 1e5 + 10;
int n;
vector<int> edgeN; // 存树
void dfs()
{
queue<int> q;
q.push(1);
st1 = true;
while(q.size())
{
int u = q.front();
q.pop();
cout << u << " ";
for(auto v:edgesu)
{
if(!stv)
{
q.push(v);
stv = true;
}
}
}
}
int main()
{
cin >> n;
for(int i = 1; i < n; i++)
{
int a,b;
cin >> a >> b;
edgesa.push_back(b);
edgesb.push_back(a);
}
dfs();
return 0;
}
//用链式前向星
const int N = 1e5 + 10;
int n;
int hN,eN \* 2,neN\*2,id;
void add(int a,int b)
{
id++;
eid = b;
neid = ha;
ha = id;
}
void dfs()
{
queue<int> q;
q.push(1);
st1 = true;
while(q.size())
{
int u = q.front();
q.pop();
cout << u << " ";
for(int i = hu;i;i = nei)
{
int v = ei;
if(!stv)
{
q.push(v);
stv = true;
}
}
}
}
int main()
{
cin >> n;
for(int i = 1; i < n; i++)
{
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
return 0;
}
//斐波那契数列
int fib(int n)
{
if(n == 0 || n == 1)
return n;
else
return fib(n - 1) + fib(n - 2);
}
int main()
{
return 0;
}