C++ 树

树型结构是一类重要的非线性结构

树型结构是一对多的关系

结点个数 = 边数 + 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;

}

相关推荐
C^h5 小时前
c++ string
开发语言·c++
raindayinrain5 小时前
c++高性能--原子操作,无锁编程,操作顺序
开发语言·c++·性能优化
学逆向的5 小时前
C++ 合并命名空间
开发语言·c++·网络安全
Zhao-Jichao6 小时前
VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具
开发语言·c++
小徐不徐说7 小时前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
大都督会赢的7 小时前
C++第一节课
开发语言·c++
UIU1147 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
论文复现现场7 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi7 小时前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
TMedical8 小时前
MedPlanning 截骨模拟矫形功能
c++·图像处理·人工智能·qt·健康医疗