POJ2003 多叉树模拟
题意
首先输入是一个头结点;
之后存在三个操作:
- [existing member] hires [new member]
- fire [existing member]
分别表示插入、删除、打印。
删除一个节点会让他的第一个子节点往上移顶替他位置,并对这个子节点也进行重复的删除操作(最左边的一系列节点依次上移)。
每个节点前需要打印N个+表示N层,最后以------------------------------------------------------------结束
思路
没啥思路可言,就是模拟而已,但是对Java来说是一种挑战。特别注意删除操作,每次删除一个节点要同时考虑他的父、子节点,而当改变一个节点位置要把他周围受影响的节点信息也要变,仔细就好。
注意
开始用标准输入输出报超时,后来去搜了Java快速输入输出得到一个输入:StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
但是并不如hasNext()好用,只有先存储输入,依旧爆运行时错误。
后来输入继续用Scanner,输出换成了PrintWriter成功AC,虽然时间还是很多但好在AC了,以后就都用PrintWriter吧。
最后说两点:
- 定义ArrayList等容器,new xxx<>()时,<>中要填写参数,不然会爆编译错误。
- PrintWriter的println是把输出放入缓冲区,最后要flush()才能取出。
代码
/*
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
*/
import java.io.*;
import java.util.*;
/**
* @Author Yuri
* @Date 2020/11/24 15:49
* @Version 1.0
* @Description:
*/
class Tree {
String name;
Integer dad;
ArrayList<Integer> children;
public Tree(String name, Integer dad) {
this.name = name;
this.dad = dad;
children = new ArrayList<Integer>();
}
@Override
public String toString() {
return "Tree{" +
"name='" + name + '\'' +
", dad=" + dad +
'}';
}
}
public class Main {
// static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static Scanner in = new Scanner(System.in);
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static String a, b, temp;
static ArrayList<Tree> treeArrayList = new ArrayList<Tree>();
static Integer index = 0;
static Map<String, Integer> map = new HashMap<String, Integer>();
static Tree headNode = null;
static Integer pos = 0;
static ArrayList<String> putIn = new ArrayList<String>();
public static void hires() throws IOException {
// in.nextToken();
temp = putIn.get(pos++);
// in.nextToken();
b = putIn.get(pos++);
treeArrayList.add(new Tree(b, map.get(a))); //增加节点
treeArrayList.get(map.get(a)).children.add(index); //添加到父节点的孩子数组
map.put(b, index++); //添加映射
}
public static void fire() throws IOException {
// in.nextToken();
b = putIn.get(pos++);
Integer selfIndex = map.get(b);
Integer dadIndex = treeArrayList.get(selfIndex).dad;
if (!treeArrayList.get(selfIndex).children.isEmpty()) { //判断孩子是否为空
int childIndex = treeArrayList.get(selfIndex).children.get(0);
update(childIndex); //要递归到叶子节点,才能开始改变自己的孩子节点为父节点的孩子节点
treeArrayList.get(childIndex).dad = dadIndex; //将子节点的父节点改为自己的父节点--->孙子指向爷爷,因为爸爸没了
if (dadIndex != -1) { //如果自己存在父节点,就要把父节点中的孩子数组中的自己的改为子节点
int ix = treeArrayList.get(dadIndex).children.indexOf(selfIndex);
treeArrayList.get(dadIndex).children.set(ix, childIndex);
} else { //不存在那么子节点就变为头结点了
headNode = treeArrayList.get(childIndex);
}
} else if (dadIndex != -1) { //如果自己不存在子节点但存在父节点 则直接在父节点中移除
int ix = treeArrayList.get(dadIndex).children.indexOf(selfIndex);
treeArrayList.get(dadIndex).children.remove(ix);
} else { //子,父节点都不存在就表示没节点了
headNode = null;
}
}
public static void update(Integer selfIndex) {
Integer dadIndex = treeArrayList.get(selfIndex).dad;
ArrayList<Integer> children = treeArrayList.get(dadIndex).children;
if (!treeArrayList.get(selfIndex).children.isEmpty()) {
int childIndex = treeArrayList.get(selfIndex).children.get(0);
update(childIndex);
children.set(0, childIndex); //把父节点数组中第一个值(本身是自己)换为自己的孩子
} else {
children.remove(selfIndex); //没有孩子就直接移除自己
}
treeArrayList.get(selfIndex).children = children;
for (int i = 0; i < children.size(); i++) {
treeArrayList.get(children.get(i)).dad = selfIndex; //自己变成了曾经兄弟姐妹的父节点
}
}
public static void print(Tree node, int floor) {
for (int i = 0; i < node.children.size(); i++) {
Tree tree = treeArrayList.get(node.children.get(i));
for (int j = 0; j < floor; j++) {
out.printf("+");
}
out.println(tree.name);
print(tree, floor + 1); //每次递归进一层
}
}
public static String op[] = new String[]{"hires", "fire", "print"};
public static void main(String[] args) throws IOException {
//本来是为了StreamTokenizer类准备的
while (in.hasNext()) {
putIn.add(in.next());
}
temp = putIn.get(pos++);
headNode = new Tree(temp, -1); //头结点
treeArrayList.add(headNode);
map.put(temp, index++); //记录String和Index的映射
while (pos < putIn.size()) {
temp = putIn.get(pos++);
if (temp.equals("fire")) {
fire();
} else if (temp.equals("print")) {
if (headNode != null) { //要考虑节点被删完的情况
out.println(headNode.name);
print(headNode, 1);
}
out.println("------------------------------------------------------------");
} else {
a = temp;
hires();
}
}
out.flush();//输出
}
}