UVA122

Posted torettorui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA122相关的知识,希望对你有一定的参考价值。

这道题目是一道很好的内存管理的题目,

我的实现方式是直接使用数组来实现二叉树的动态构建,其中node[0]是根节点。

刘汝佳的两种实现方式:第一种是采用动态分配内存的方式(这种方式适合于所需要的节点数目不明确的情况)

第二种也是采用数组的方式,但是它将newtree()   和newnode()   写成了一种函数,这种程序结构更清晰一些,下面贴上三种不同版本的代码,分别进行分析

//这道题不好弄啊
//使用数组实现链式二叉树
#include<string>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;

int Node[256],Left[256],Right[256];
//0代表树节点
bool error = false;

int pos=0;//代表申请节点到了第几个

void print_tree()
{
    for(int i = 0;i <= pos;i++)
    {
        printf("%d  ",Node[i]);
    }
    printf("
");
    for(int i = 0;i <= pos;i++)
    {
        printf("%d  ",Left[i]);
    }
    printf("
");
    for(int i = 0;i <= pos;i++)
    {
        printf("%d  ",Right[i]);
    }
    printf("
");
}

bool read_tree()
{
    string pair;
    memset(Node,0,sizeof(Node));
    memset(Left,0,sizeof(Left));
    memset(Right,0,sizeof(Right));
    error = false;
    pos = 0;
    while(cin >> pair)
    {
//cout<<pair<<endl;
        if(pair == "()")
        {
            return true;
        }
        int x = pair.find(,);
//printf("%d
",x);
        int index;
        sscanf(pair.substr(1,x-1).c_str(),"%d",&index);
//printf("%d
",index);
        for(int i = x + 1,cur = 0;;i++)
        {
//printf("%c
",pair[i]);
            if(pair[i]==))
            {
                if(Node[cur])
                    error = true;
                Node[cur] = index;
                break;
            }
            else if(pair[i] == L)
            {
                if(Left[cur] == 0)
                {
                    Left[cur] = ++pos;//新申请的节点
                }
                cur = Left[cur];
//printf("cur=%d
",cur);
            }
            else if(pair[i] == R)
            {
                if(Right[cur] == 0)
                {
                    Right[cur] = ++pos;
                }
                cur = Right[cur];
            }
        }
//print_tree();

    }
    return false;
}

void level_order()
{
    vector<int>Vector;
    queue<int>queue;
    queue.push(0);
    while(!queue.empty())
    {
        int cur = queue.front();
        queue.pop();
        if(Node[cur] == 0)//如果有没有赋值的情况
        {
            printf("not complete
");
            return;
        }
        else
        {
            if(Left[cur])
                queue.push(Left[cur]);
            if(Right[cur])
                queue.push(Right[cur]);
            Vector.push_back(Node[cur]);
        }
    }
    for(int i = 0;i < Vector.size();i++)
    {
        if(i)
            printf(" ");
        printf("%d",Vector[i]);
    }
    printf("
");
}


int main()
{
#ifdef local
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
#endif
    while(read_tree())
    {
        if(error)
        {
            printf("not complete
");
        }
        else
        {
            level_order();
        }
    }
    return 0;
}

第一种是我写的代码,其中要注意的两个地方是:string的使用,刘汝佳使用的是数组,当我决定输入的那么pair的长度是不确定的,所以应该使用string。而且还有一点就是不可以使用sstream。另外,这道题目虽然在输入的过程中可以判断出是否合法,但是不可以中途断掉,只能使用一个数据结构error来保存是否有错误

 

第二种是刘汝佳的动态申请的版本

// UVa122 Trees on the level
// Rujia Liu
//此代码值得学习的地方,1》输入的处理 2》设立一个flag来表示本组数据有没有错误 3》将new node直接编写成一个函数。
//4》各个输出数据需要空一格,但最后一个数据没有空格的处理
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;

const int maxn = 256 + 10;

struct Node{
  bool have_value;
  int v;
  Node* left, *right;
  Node():have_value(false),left(NULL),right(NULL){}
};

Node* root;

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

bool failed;
void addnode(int v, char* s) {
  int n = strlen(s);
  Node* u = root;
  for(int i = 0; i < n; i++)//建立一颗完整的树,u最后表示要插入数据的那个节点
    if(s[i] == L) {
      if(u->left == NULL) u->left = newnode();
      u = u->left;
    } else 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;
}

void remove_tree(Node* u) {
  if(u == NULL) return;
  remove_tree(u->left);
  remove_tree(u->right);
  delete u;
}

char s[maxn];
bool read_input() {
  failed = false;
  remove_tree(root);//释放原来的那棵树
  root = newnode();//新创建一颗树
  for(;;) {
    if(scanf("%s", s) != 1) return false;//输入结束
    if(!strcmp(s, "()")) break;//本组数据输入结束,但整个输入还没有结束
    int v;
    sscanf(&s[1], "%d", &v);
    addnode(v, strchr(s, ,)+1);//开始建立节点
  }
  return true;//输入完毕后开始层次遍历
}

bool bfs(vector<int>& ans) {//将遍历的结果保存早ans当中
  queue<Node*> q;
  ans.clear();
  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;//结束后
}

int main() {
    freopen("input.txt","r",stdin);
freopen("out刘汝佳.txt","w",stdout);
  vector<int> ans;//这个也可以用队列实现,都可以无所谓
  while(read_input()) {
    if(!bfs(ans)) failed = 1;
    if(failed) printf("not complete
");//如果本组数据输入失败,或者在层次遍历的时候,有的节点的数据没有输入
    else {
      for(int i = 0; i < ans.size(); i++) {
        if(i != 0) printf(" ");//这个比first还好用哎,在i不等于0的前面加空格
        printf("%d", ans[i]);
      }
      printf("
");
    }
  }
  return 0;
}

这段代码需要注意的地方就是释放内存的哪一个地方,需要先判断当前节点是否有值,否则会出错

 

 

第三段代码是使用了内存池技术的代码,这个想法非常的不错

// UVa122 Trees on the level
// Rujia Liu
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;

const int maxn = 256 + 10;

struct Node{
  bool have_value;
  int v;
  Node* left, *right;
  Node():have_value(false),left(NULL),right(NULL){}
};

Node* root;

queue<Node*> freenodes; // 空闲列表
Node node[maxn]; // 内存池

//将节点都放入那个队列中去
void init() {
  for(int i = 0; i < maxn; i++)
    freenodes.push(&node[i]);
}

Node* newnode() {
  Node* u = freenodes.front();
  u->left = u->right = NULL; u->have_value = false; // 重新初始化该结点
  freenodes.pop();
  return u;
}

void deletenode(Node* u) {
  freenodes.push(u);
}

bool failed;
void addnode(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;
    } else 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;
}

void remove_tree(Node* u) {
  if(u == NULL) return;
  remove_tree(u->left);
  remove_tree(u->right);
  deletenode(u);
}

char s[maxn];
bool read_input() {
  failed = false;
  remove_tree(root);
  root = newnode();
  for(;;) {
    if(scanf("%s", s) != 1) return false;
    if(!strcmp(s, "()")) break;
    int v;
    sscanf(&s[1], "%d", &v);
    addnode(v, strchr(s, ,)+1);
  }
  return true;
}

bool bfs(vector<int>& ans) {
  queue<Node*> q;
  ans.clear();
  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;
}

int main() {
  vector<int> ans;
  init();
  while(read_input()) {
    if(!bfs(ans)) failed = 1;
    if(failed) printf("not complete
");
    else {
      for(int i = 0; i < ans.size(); i++) {
        if(i != 0) printf(" ");
        printf("%d", ans[i]);
      }
      printf("
");
    }
  }
  return 0;
}

在newnode的时候,每次都是去queue的头节点来操作

以上是关于UVA122的主要内容,如果未能解决你的问题,请参考以下文章

UVA 122 Trees on the level

UVA122 二叉树的层次遍历

Uva122 Trees on the level

uva 122 trees on the level——yhx

UVa 122 树的层次遍历

6-7 树的层次遍历 uva122