簡體   English   中英

Java 中的 BinaryTree - 構建單詞並顯示它

[英]BinaryTree in Java - build words and display it

我對大學有一個我想不通的問題。 我有一個文件,其中包含構建二叉樹的說明

r a
rr b
rl c
rrr h
rrl i
rlr j
rll k
d
l e
ll f
lr g
lll l
llr m
lrl n
lrr o

r - 右,l - 左,要打印的內容。 “d”是根

我加載文件,將每一行分成指令和一個值,但我不知道下一步該做什么——我被卡住了。

我必須構建一棵樹並使用遞歸來解決它......並打印來自樹狀“hbad”、“kcad”、“lfed”等的所有單詞......

我現在的代碼:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        int i = 0;
        String key[] = new String[2];
        String root = "";
        ArrayList<String> lineFile = new ArrayList<String>();

        Scanner scan = null;
        try {
            scan = new Scanner(new File("tree.txt"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        while (scan.hasNextLine()) {
            lineFile.add(scan.nextLine());
        }

        for (i = 0; i < lineFile.size(); i++) {
            if (lineFile.get(i).length() > 1) {
                key = lineFile.get(i).split(" ");
                System.out.print(key[0] + " " + key[1]);
            } else {
                root = lineFile.get(i);
            }
            System.out.println(" " + lineFile.get(i).length());
        }
        System.out.println(root);
    }
}

請幫助...任何示例實現,鏈接或其他...

如上所述,二叉樹由一組節點組成。 每個節點有兩個子節點,left 和 right,它們也是節點。 一個簡單的節點實現可能如下所示:

public class BinaryTreeNode<T> {
    private final T value;
    private BinaryTreeNode<T> left;
    private BinaryTreeNode<T> right;

    public BinaryTreeNode(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public BinaryTreeNode<T> getLeft() {
        return left;
    }

    public void setLeft(BinaryTreeNode<T> left) {
        this.left = left;
    }

    public BinaryTreeNode<T> getRight() {
        return right;
    }

    public void setRight(BinaryTreeNode<T> right) {
        this.right = right;
    }
}

這個版本是通用的,但您可以將 value 設置為 String 並讓生活更輕松。 從根值創建樹的基礎:

    BinaryTreeNode<String> tree = new BinaryTreeNode<>(root); 

解析您的輸入並將其添加到樹中比較棘手。 為了簡化一點,我創建了一條新指令 class,每行的兩部分(位置和值)分開。 為了方便起見,我做了一個內部 class (不需要getter/setter),但這不是必需的:

private class Instruction {
    String node;
    String value;

    public Instruction(String node, String value) {
        this.node = node;
        this.value = value;
    }
}

創建指令列表:

List<Instruction> instructions = new ArrayList<>();

並將其填充到您的循環中:

    instructions.add(new Instruction(key[0], key[1]));

現在進行遞歸加載。 這可能不是最好的解決方案,但它有效:

private void buildSubTree(BinaryTreeNode node, List<Instruction> instructions) {
    // Get the left branch
    List<Instruction> left = instructions.stream()
            .filter(i -> i.node.startsWith("l"))
            .collect(Collectors.toList());
    // Get the right branch
    List<Instruction> right = instructions.stream()
            .filter(i -> i.node.startsWith("r"))
            .collect(Collectors.toList());

    // Find the first left instruction
    Instruction firstLeft = left.stream().filter(i -> i.node.length() == 1).findFirst().orElse(null);
    // Find the first right instruction
    Instruction firstRight = right.stream().filter(i -> i.node.length() == 1).findFirst().orElse(null);

    if (firstLeft != null) {
        // Set the left child
        node.setLeft(new BinaryTreeNode(firstLeft.value));
        // Find left children by reducing instruction node String (remove first character)
        List<Instruction> leftChildren = left.stream().map(i -> new Instruction(i.node.substring(1), i.value)).collect(Collectors.toList());
        // Recursively build left branch
        buildSubTree(node.getLeft(), leftChildren);
    }

    if (firstRight != null) {
        // Set the right child
        node.setRight(new BinaryTreeNode(firstRight.value));
        // Find right children by reducing instruction node String (remove first character)
        List<Instruction> rightChildren = right.stream().map(i -> new Instruction(i.node.substring(1), i.value)).collect(Collectors.toList());
        // Recursively build right branch
        buildSubTree(node.getRight(), rightChildren);
    }
}

構建樹:

buildSubTree(tree, instructions);

該方法將在給定節點(第一次調用中的根節點)下構建兩個子樹,並使用每個子節點和每一側的簡化指令集遞歸調用自身。 可以在此處進行一些改進,使指令 class 更有幫助。

從列表中構建單詞更容易:

private List<String> buildWordsFromTreeLeafUp(BinaryTreeNode<String> startNode) {
    // List of words to return
    List<String> words = new ArrayList<>();

    // First populate the list with words from each child branch
    if (startNode.getLeft() != null) {
        words.addAll(buildWordsFromTreeLeafUp(startNode.getLeft()));
    }

    if (startNode.getRight() != null) {
        words.addAll(buildWordsFromTreeLeafUp(startNode.getRight()));
    }

    // Add the startNodes value to each word
    words = words.stream().map(s -> s + startNode.getValue()).collect(Collectors.toList());
    // Add the value as a word of it's own
    words.add(startNode.getValue());

    return words;
}

我敢打賭,這不是最優雅的實現,但它完成了工作。

如果您只想要完整長度(4 個字母)的單詞,這里是單詞構建方法最后一部分的替代方法:

if (words.isEmpty()) {
    // Add the value as a word of it's own
    words.add(startNode.getValue());
} else {
    // Add the startNodes value to each word
    words = words.stream().map(s -> s + startNode.getValue()).collect(Collectors.toList());
}

編輯

上面的最后一個代碼塊可以替換 buildWordsFromTreeLeafUp() 中的等效行。 這是它的工作原理:

  • 如果當前節點是葉子節點(即在沒有子節點(左或右)的分支末端的節點,那么此時單詞列表將為空。如果是,我們添加 this 的值(字母)節點作為一個詞。
  • 如果列表中已經有單詞,則意味着至少有一個子節點。 在這種情況下,我們不會將當前字母添加為新單詞。 取而代之的是我們 append 已經在列表中的每個單詞末尾的當前字母。 這樣,當遞歸一次返回一步時,我們只寫完整的四個字母單詞。

該方法寫入所有單詞,一次一個字母,但針對每個單詞。

在上面的第一個實現中,我們也將當前字母添加為新單詞。 這樣,除了所有 4 個字母的單詞之外,我們還將獲得所有 3 個和 2 個字母的單詞(從樹的中間某處開始)以及一個僅包含根元素的 1 個字母的單詞 ('d')。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM