考虑具有以下属性的二叉树:
- 如果内部节点(非叶节点)有两个子节点,则其值为 1。
- 叶节点的值为 0,因为它没有子节点。
树上的级别顺序遍历将生成一串 1 和 0(通过在每个节点被访问时打印奇怪的值)。现在给定这个字符串构造二叉树并在树上执行后序遍历。后订单字符串应该是程序的输出。
例如:输入字符串是
111001000
. 以此创建二叉树。然后在树上执行后序遍历,这将导致输出:001001011
问题的“症结”是仅从级别顺序字符串创建二叉树。我该怎么做?
考虑具有以下属性的二叉树:
树上的级别顺序遍历将生成一串 1 和 0(通过在每个节点被访问时打印奇怪的值)。现在给定这个字符串构造二叉树并在树上执行后序遍历。后订单字符串应该是程序的输出。
例如:输入字符串是
111001000
. 以此创建二叉树。然后在树上执行后序遍历,这将导致输出:001001011
问题的“症结”是仅从级别顺序字符串创建二叉树。我该怎么做?
一种可能的解决方案(不到一小时):
import java.util.ArrayList;
import java.util.List;
public class Main {
private static class Node {
private Node left;
private Node right;
}
private static Node buildTree(String input) {
char chars[] = input.toCharArray();
if (chars.length == 0) {
return null;
} else {
Node root = new Node();
List<Node> nodeList = new ArrayList<Node>();
nodeList.add(root);
int pos = 0;
while (!nodeList.isEmpty()) {
List<Node> nextList = new ArrayList<Node>();
for (Node n: nodeList) {
if (pos >= chars.length) {
throw new RuntimeException("Invalid input string");
}
char c = chars[pos++];
if (c == '1') {
n.left = new Node();
n.right = new Node();
nextList.add(n.left);
nextList.add(n.right);
} else if (c != '0') {
throw new RuntimeException("Invalid input string");
}
}
nodeList = nextList;
}
return root;
}
}
private static String postTraverse(Node n) {
if (n == null) {
return "";
} else if (n.left == null && n.right == null) {
return "0";
} else {
return postTraverse(n.left) + postTraverse(n.right) + "1";
}
}
public static void main(String[] args) {
Node tree = buildTree(args[0]);
System.out.println(postTraverse(tree));
}
}
以您的级别顺序遍历为例 - 111001000 树将如下所示
A
/ \
B C
/\ /\
D E F G
/\
H I
逻辑如下。
1)如果它的 1 (根)取第一位 - 然后下一个 2^1 是该父项的子项的值。所以第 2 位和第 3 位是 A(根)的子节点。
2) 转到下一位(B 为 1),因为它的值也是 1,它也有 2 个孩子,然后下一位(C 为 1)也有 2 个孩子。第二级结束了,因为我们有 2 个 1,所以 2^2 下一个位用于第 3 级。
3) 111 001000 所以我们已经遍历了这个,接下来的 4 位是第三级的孩子。第 4 位和第 5 位为 0(D 和 E 是叶节点并且没有子节点 - 这些将是 B 的子节点)然后 F 的位值为 1,因此 1110010 00(粗体数字)将是 F 的子节点。第 7 位为 0所以 G 也将是叶节点。
4) 再次循环或尝试 recusion - 从第 4、5、6 和 7 位开始,只有一位为 1,因此接下来的 2^1 位将在下一级,这些将是 F 的子级。
制作好树后,转换为 PostFix 就很容易了。
如果允许,我会在这里使用二进制堆作为助手。在使用标准表实现的二进制堆中,给定元素的索引,我们可以轻松计算其父元素的索引int parent = (index-1)/2;
:知道了这一点,我们需要从表格的开头开始并执行以下操作:
对于输入流中的所有剩余元素:
do{
binaryHeap[heapIndex] = -1;
if (parent(heapIndex) = 1)
binaryHeap[heapIndex] = nextElementFromTheInputStream;
heapIndex++;
}
while(binaryHeap[heapIndex - 1] == 0);
所以基本上,我们在桌子上移动。我们将每个字段(除了 0 的根)初始化为 -1,这意味着那里没有节点。然后我们检查该字段的父级是否为 1。如果是,则我们将输入流中的下一个元素放在堆中的当前索引 (heapIndex) 上。如果当前字段的父级为 0,我们就走得更远,因为这意味着我们的父级是一片叶子,不应该有任何子级。
然后我们可以在堆上运行后排序算法(可能值得实现一些安全代码,这样就不会在输出流中放置带有“-1”的元素。只需解释 leftChild(heapIndex) == -1;或 rightChild(heapIndex) == -1; 为 NULL)。
这个算法在内存方面可能效率很低,但我希望它很容易理解。
首先,我假设你level order traversal
基本上是一个 BFS。
现在,让我们看一下字符串。执行 BFS,如果当前节点有两个儿子,我们打印“1”。否则,它是一个叶子,我们打印 0,终止当前分支的处理。
因此,在反向任务期间,我们可以记住打开分支的最后一个节点的列表,并将传入的节点添加到那里。
让我们通过一个例子来演示这种方法:
Level 1:
Tree :
1 - id 0
Open branches : 0 0 (left and right son)
Remaining string : 11001000
*********
Level 2:
Tree :
1
1 1
Open branches : 1 1 2 2
Remaining string : 001000
*********
Level 3:
Tree :
1
1 1
0 0 1 0
Open branches : 5 5
Remaining string : 00
Level 4:
Tree :
1
1 1
0 0 1 0
0 0
No more input, we're done.
有了树,后序遍历是微不足道的。
和代码(它假设树非常密集,否则它的内存效率不是很高):
import java.util.ArrayDeque;
import java.util.Queue;
public class Main {
static final int MAX_CONST = 50;
public static void main(String[] args) {
String evilString = "111001000"; // Assuming this string is a correct input
char[] treeRepr = new char[MAX_CONST];
Queue<Integer> q = new ArrayDeque<Integer>();
q.add(0);
for (int i = 0; i < evilString.length(); ++i) {
int index = q.remove();
char ch = evilString.charAt(i);
if (ch == '1') {
q.add(2*(index+1)-1);
q.add(2*(index+1));
}
treeRepr[index] = ch;
// System.out.println(q.size());
}
System.out.println(arrToString(treeRepr, 0, new StringBuilder()));
}
public static StringBuilder arrToString(char[] array, int index, StringBuilder sb) {
if (array[index] == '1')
{
arrToString(array, 2*(index+1)-1, sb);
arrToString(array, 2*(index+1), sb);
}
sb.append(array[index]);
return sb;
}
}
这是一个非常简单的解决方案。
虽然就内存而言并不是真正的最佳选择 ,因为我首先构建了一个完整/完整的树
,然后我标记了哪些节点实际存在于我们的树中。所以这
可以优化一点,我猜。
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
class Node {
public Node left;
public Node right;
public Integer id;
public boolean exists;
}
public class Test32 {
public static void main(String[] args) {
HashMap<Integer, Node> mp = new HashMap<Integer, Node>();
String str = "110101000";
int sz = (int)Math.pow(2, str.length() + 1);
for (int i=0; i<sz; i++){
Node nd = new Node();
nd.id = i;
mp.put(nd.id, nd);
}
for (int i=0; i<sz; i++){
Node nd = mp.get(i);
if (2*i < sz) nd.left = mp.get(2*i + 1);
if (2*i + 1 < sz) nd.right = mp.get(2*i + 2);
}
Queue<Integer> visit = new LinkedList<Integer>();
visit.add(0); // id = 0;
int j = 0;
int id = -1;
while (!visit.isEmpty()){
id = visit.poll();
if (str.charAt(j) == '1'){
mp.get(id).exists = true;
visit.add(2*id + 1);
visit.add(2*id + 2);
}else{
mp.get(id).exists = true;
}
j++;
}
System.out.println("NODES:");
for (int i=0; i<sz; i++){
if (mp.get(i).exists){
System.out.println(i);
}
}
System.out.println();
System.out.println("EDGES:");
for (int i=0; i<sz; i++){
if (mp.get(i).exists){
if (mp.get(2 * i + 1).exists){
System.out.println(i + " --> " + (2*i+1));
}
if (mp.get(2 * i + 2).exists){
System.out.println(i + " --> " + (2*i+2));
}
}
}
}
}
这是相同的解决方案简化版。
没有树或地图,只是一个布尔数组。如果某个节点
k 有孩子,这些孩子是 2*k+1 和 2*k+2。
在打印边缘的最后一个循环中,还可以
构造一个实际的二叉树。
import java.util.LinkedList;
import java.util.Queue;
public class Test32 {
public static void main(String[] args) {
String str = "110101000";
int sz = (int)Math.pow(2, str.length() + 1);
boolean exists[] = new boolean[sz];
Queue<Integer> visit = new LinkedList<Integer>();
visit.add(0); // id = 0;
if (str.charAt(0) == '1'){
exists[0] = true;
}
int j = 0;
int id = -1;
while (!visit.isEmpty()){
id = visit.poll();
if (str.charAt(j) == '1'){
exists[id] = true;
visit.add(2*id + 1);
visit.add(2*id + 2);
}else{
exists[id] = true;
}
j++;
}
// System.out.println("");
System.out.println("NODES:");
for (int i=0; i<sz; i++){
if (exists[i]){
System.out.println(i);
}
}
System.out.println("");
System.out.println("EDGES:");
for (int i=0; i<sz; i++){
if (exists[i]){
if (exists[2*i+1]){
System.out.println(i + " --> " + (2*i+1));
}
if (exists[2*i+2]){
System.out.println(i + " --> " + (2*i+2));
}
}
}
}
}
我认为在概念上更简单。
import java.util.LinkedList;
import java.util.Queue;
class WeirdBinaryTree
{
static class Node
{
private Node right;
private Node left;
private int weirdValue;
public void setWeirdValue(int value)
{
weirdValue=value;
}
}
private static Node makeTree(String str)throws Exception
{
char[] array=str.toCharArray();
Node root=new Node();
Queue<Node> list=new LinkedList();
list.add(root);
int i=0;
Queue<Node> nextList=new LinkedList<Node>();
while(!list.isEmpty())
{
if(array[i++]=='1')
{
Node temp=list.poll();
temp.left=new Node();
temp.right=new Node();
temp.setWeirdValue(1);
nextList.add(temp.left);
nextList.add(temp.right);
}
else
{
list.poll();
}
if(list.isEmpty())
{
list=nextList;
nextList=new LinkedList<Node>();
}
}
return root;
}
private static void postTraversal(Node localRoot)
{
if(localRoot!=null)
{
postTraversal(localRoot.left);
postTraversal(localRoot.right);
System.out.print(localRoot.weirdValue);
}
}
public static void main(String[] args)throws Exception
{
postTraversal(makeTree("111001000"));
}
}