算法基础——树

发布于:2025-03-30 ⋅ 阅读:(106) ⋅ 点赞:(0)

一、树的概念

1. 树的定义

       树型结构是⼀类重要的⾮线性数据结构。

2. 树的基本术语 

3. 有序树和⽆序树

4. 有根树和⽆根树

注意

        如果是⽆根树,⽗⼦关系不明确,此时我们需要把所有的情况都存下来。⽐如a和b之间有⼀条 边,我们不仅要存a有⼀个孩⼦b,也要存b有⼀个孩⼦a。

        甚⾄有的时候,在有根树的题⽬⾥,也要这样存储。

二、树的存储

1. 孩⼦表⽰法

2. 实现⽅式⼀:⽤vector数组实现

#include <iostream>
#include <vector>

using namespace std;

const int N = 1e5 + 10;

int n;
vector<int> edges[N]; // 存储树

int main()
{
    cin >> n;
    for(int i = 1; i < n; i++)
    {
        int a, b; cin >> a >> b;
        // a 和 b 之间有一条边
        edges[a].push_back(b);
        edges[b].push_back(a);
    }


    return 0;
}

3. 实现⽅式⼆:链式前向星

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

// 链式前向星
int h[N], e[N * 2], ne[N * 2], id;
int n;

// 其实就是把 b 头插到 a 所在的链表后面
void add(int a, int b)
{
    id++;
    e[id] = b;
    ne[id] = h[a];
    h[a] = 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;
}

关于vector数组以及链式前向星:

  • 前者由于⽤到了容器vector,实际运⾏起来相⽐较于后者更耗时,因为vector是动态实现的。
  • 但是在如今的算法竞赛中,⼀般不会⽆聊到卡这种常数时间。也就是vector虽然慢,但不会因此⽽超时。

三、树的遍历 

1. 深度优先遍历-DFS

间复杂度:

简单估计⼀下,在 dfs   整个过程,会把树所有的边扫描量两遍。边的数量为n 1 ,因此间复度为O(N)

空间复杂度:

最差况下,结点个数为  的树,⾼度也是 n 也就是变成⼀个链表。此递归的深度也是  n 此时的空间度为O(N)

 

2. 宽度优先遍历-BFS

间复杂度:

所有结点只会次,然后出队次,因此度为 O(N)

空间复杂度:

最坏情况下,所有的根结点都在同⼀层,此队列⾥⾯多有 n 个元素,空间杂度为 O(N)

 3. 练习

(1)题目描述 

题⽬描述:

定⼀棵树,该树⼀共 个结点,编号分别是 1 ∼ n

描述:

⼀⾏⼀个整数 n 表⽰ n 结点。

来 n ⾏,每⾏两个整数 u, v 表⽰ u 之间有条边。

测试例:

 11
 1 3
 7 3
 3 10
 1 5
 4 5
 2 1
 11 2
 6 11
 11 8
 11 9

(2)实现代码

深度优先遍历——DFS

// // 用 vector 数组存储树

// #include <iostream>
// #include <vector>

// using namespace std;

// const int N = 1e5 + 10;

// int n;
// vector<int> edges[N]; // 存储图
// bool st[N]; // 标记哪些点已经访问过了

void dfs(int u)
{
    cout << u << " ";
    st[u] = true; // 当前这个点已经访问过了

    // 访问所有的孩子
    for(auto v : edges[u])
    {
        if(!st[v])
        {
            dfs(v);
        }
    }
}

// int main()
// {
//     // 建树
//     cin >> n;
//     for(int i = 1; i < n; i++)
//     {
//         int a, b; cin >> a >> b;
//         edges[a].push_back(b);
//         edges[b].push_back(a);
//     }

//     // 深度优先遍历
//     dfs(1);

//     return 0;
// }

// 用链式前向星存储
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

// 存图
int h[N], e[N * 2], ne[N * 2], id;
int n;

bool st[N]; // 标记哪些点已经访问过了

void add(int a, int b)
{
    id++;
    e[id] = b;

    ne[id] = h[a];
    h[a] = id;
}

void dfs(int u)
{
    cout << u << " ";
    st[u] = true;

    for(int i = h[u]; i; i = ne[i])
    {
        int v = e[i]; // 孩子
        if(!st[v])
        {
            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;
}


// 斐波那契数列
int fib(int n)
{
    if(n == 0 || n == 1) return n;

    return fib(n - 1) + fib(n - 2);
}

 宽度优先遍历——BFS

// 用 vector 数组存树
// #include <iostream>
// #include <queue>
// #include <vector>

// using namespace std;

// const int N = 1e5 + 10;

// int n;
// vector<int> edges[N]; // 存树
// bool st[N]; // 标记哪些节点已经访问过了

// void bfs()
// {
//     queue<int> q;
//     q.push(1);
//     st[1] = true;

//     while(q.size())
//     {
//         int u = q.front(); q.pop();
//         cout << u << " ";

//         for(auto v : edges[u])
//         {
//             if(!st[v])
//             {
//                 q.push(v);
//                 st[v] = true;
//             }
//         }
//     }
// }

// int main()
// {
//     // 建树
//     cin >> n;
//     for(int i = 1; i < n; i++)
//     {
//         int a, b; cin >> a >> b;
//         edges[a].push_back(b);
//         edges[b].push_back(a);
//     }

//     bfs();

//     return 0;
// }


// 用链式前向星存储树
#include <iostream>
#include <queue>

using namespace std;

const int N = 1e5 + 10;

int n;
int h[N], e[N * 2], ne[N * 2], id;
bool st[N];

void add(int a, int b)
{
    id++;
    e[id] = b;
    ne[id] = h[a];
    h[a] = id;
}

void bfs()
{
    queue<int> q;
    q.push(1);
    st[1] = true;

    while(q.size())
    {
        int u = q.front(); q.pop();
        cout << u << " ";

        for(int i = h[u]; i; i = ne[i])
        {
            int v = e[i];
            if(!st[v])
            {
                q.push(v);
                st[v] = true;
            }
        }
    }
}

int main()
{
    cin >> n;
    for(int i = 1; i < n; i++)
    {
        int a, b; cin >> a >> b;
        add(a, b); add(b, a);
    }

    bfs();

    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到