题解 UVA122 【树的层次遍历 Trees on the level】

1|0By《算法竞赛入门经典》

前几天终于自学到树了,这道题作为例题自然是比较需要重点掌握了。

感觉这道题我在怎么讲解肯定也没有lrj讲得好,所以我这篇题解主要是lrj的思想。

1|1最重要的是树的存储

可以用两种方法

  1. 结构体+指针

    struct Node{ bool have_value;//是否被赋值过,这个是针对本题要求设定的 int v;//结点的值 Node* left, *right; Node():have_value(false),left(NULL),right(NULL){}//构造函数(大概就是初始化的意思吧) }*root;//二叉树的根结点

    由于二叉树是递归定义的,其左右子结点类型都是“指向结点类型的指针”。换句话说, 如果结点的类型为Node,则左右子结点的类型都是Node *。

    每次需要一个新的Node时,都要用new运算符申请内存,并执行构造函数。下面把申请 新结点的操作封装到newnode函数中:

    Node* newnode() { return new Node(); }

    还有这里lrj还提到了一个问题,当每次执行root=newnode()之后,之后这些内存就变成无法访问的内存垃圾了,因此最好写一个递归函数专门来清理这些内存。

    下面是释清理内存的代码,请在“root = newnode()”之前加一 行“remove_tree(root)”:

    void remove_tree(Node* u) { if(u == NULL) return;//提前判断比较稳妥 remove_tree(u->left);//递归释放左子树的空间 remove_tree(u->right);//递归释放右子树的空间 delete u;//调用u的析构函数并释放u结点本身的内存 }
  2. 数组+下标

    首先还是给每个结点编号, 但不是按照从上到下从左到右的顺序,而是按照结点的生成顺序。用计数器cnt表示已存在的 结点编号的最大值,因此newnode函数需要改成这样:

    const int root = 1; void newtree() { left[root] = right[root] = 0; have_value[root] = false; cnt = root; } int newnode() { int u = ++cnt; left[u] = right[u] = 0; have_value[root] = false; return u; }

    上面的newtree()是用来代替前面的“remove_tree(root)”和“root = newnode()”两条语句的: 由于没有了动态内存的申请和释放,只需要重置结点计数器和根结点的左右子树了。 接下来,把所有的Node类型改成int类型,然后把结点结构中的成员变量改成全局数组 (例如,u->left和u->right分别改成left[u]和right[u]),除了char外,整个程序就没有任何指 针了。

存储完树之后,这道题就没什么难点了,直接BFS就可以了。

1|2my−code

#include <cstdio> #include <vector> #include <queue> #include <cstring> #define maxn 1001000 using namespace std; struct Node { bool have_value; int v; Node *left,*right; Node():have_value(false),left(NULL),right(NULL){} }; int v; bool failed; char s[maxn]; Node* root; Node* newnode(){return new Node();} inline void remove_tree(Node *p) { if(p == NULL) { return ; } remove_tree(p->left); remove_tree(p->right); delete p; } inline bool BFS(vector<int> &ans) { ans.clear(); queue<Node* > Q; Q.push(root); while(!Q.empty()) { Node* u=Q.front();Q.pop(); if(!u->have_value) { return false; } ans.push_back(u->v); if(u->left != NULL) { Q.push(u->left); } if(u->right != NULL) { Q.push(u->right); } } return true; } inline void add_Node(int v,char *s) { int n=strlen(s); Node *u=root; for(int i=0; i<n; i++) { if(s[i] == 'L') { if(u->left == NULL) { u->left=newnode(); } u=u->left; } if(s[i] == 'R') { if(u->right == NULL) { u->right=newnode(); } u=u->right; } } if(u->have_value) { failed=true; } u->v=v; u->have_value=true; } inline bool read_input() { failed=false; remove_tree(root); root=newnode(); for( ;; ) { if(scanf("%s", s) != 1) { return false; } if(strcmp(s,"()") == 0) { break; } sscanf(&s[1],"%d",&v); add_Node(v,strchr(s,',')+1); } return true; } int main() { vector<int> ans; while(read_input()) { if(failed || !BFS(ans)) { printf("not complete"); }else { for(vector<int>::iterator t=ans.begin(); t!=ans.end(); t++) { if(t != ans.end()-1) { printf("%d ",*t); }else { printf("%d",*t); } } } printf("\n"); } return 0; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17776991.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(14)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示