Java家庭树程序开发需求:亲属关系校验与层级遍历实现
Alright, let's build out this family tree Java program with all the features you need—relationship parsing, validation tests, and level-order traversal. Here's a step-by-step breakdown with code examples:
1. Core Data Structure Design
First, we'll define a Person class to store individual details and their family connections, plus a FamilyTree class to manage the overall structure, parse input, and handle relationship queries.
Person Class
This class tracks a person's name, their father, and their list of children (with bidirectional association to avoid redundant setup):
import java.util.ArrayList; import java.util.List; public class Person { private final String name; private Person father; private final List<Person> children; public Person(String name) { this.name = name; this.children = new ArrayList<>(); } // Getters and setters public String getName() { return name; } public Person getFather() { return father; } public void setFather(Person father) { this.father = father; } public List<Person> getChildren() { return children; } public void addChild(Person child) { children.add(child); child.setFather(this); } }
FamilyTree Class
This class handles input parsing, relationship validation, and will later include traversal logic:
import java.util.HashMap; import java.util.Map; public class FamilyTree { private final Map<String, Person> personMap; public FamilyTree() { personMap = new HashMap<>(); } // Parse statements like "A is father of B" public void parseRelationship(String statement) { String[] parts = statement.split(" "); // Validate input format if (parts.length != 5 || !parts[1].equals("is") || !parts[2].equals("father") || !parts[3].equals("of")) { throw new IllegalArgumentException("Invalid statement format: " + statement); } String fatherName = parts[0]; String childName = parts[4]; // Create persons if they don't exist yet Person father = personMap.computeIfAbsent(fatherName, Person::new); Person child = personMap.computeIfAbsent(childName, Person::new); father.addChild(child); } // Check if X is a child of Y public boolean isChildOf(String childName, String parentName) { Person child = personMap.get(childName); Person parent = personMap.get(parentName); if (child == null || parent == null) return false; return parent.getChildren().contains(child); } // Check if X is an ancestor of Y (traverse up the father line) public boolean isAncestorOf(String ancestorName, String descendantName) { Person descendant = personMap.get(descendantName); Person ancestor = personMap.get(ancestorName); if (descendant == null || ancestor == null) return false; Person current = descendant.getFather(); while (current != null) { if (current.equals(ancestor)) { return true; } current = current.getFather(); } return false; } }
2. JUnit Test Cases
Let's write tests to verify our relationship logic works as expected. We'll use JUnit 5 for this:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class FamilyTreeTest { private FamilyTree familyTree; @BeforeEach void setUp() { familyTree = new FamilyTree(); familyTree.parseRelationship("A is father of B"); familyTree.parseRelationship("B is father of C"); familyTree.parseRelationship("A is father of D"); } @Test void testIsChildOf() { assertTrue(familyTree.isChildOf("B", "A")); assertTrue(familyTree.isChildOf("C", "B")); assertFalse(familyTree.isChildOf("C", "A")); // C is a grandchild, not direct child assertFalse(familyTree.isChildOf("X", "A")); // Non-existent person } @Test void testIsAncestorOf() { assertTrue(familyTree.isAncestorOf("A", "C")); assertTrue(familyTree.isAncestorOf("B", "C")); assertFalse(familyTree.isAncestorOf("C", "A")); assertFalse(familyTree.isAncestorOf("D", "C")); } }
3. Level-Order (Left-to-Right) Traversal
Add a breadth-first search (BFS) method to FamilyTree to output the tree in hierarchical order:
import java.util.LinkedList; import java.util.Queue; // Add this method to the FamilyTree class public String levelOrderTraversal() { if (personMap.isEmpty()) return ""; // Find root node(s) (persons with no father) Queue<Person> queue = new LinkedList<>(); for (Person person : personMap.values()) { if (person.getFather() == null) { queue.add(person); break; // Adjust if you need to support multiple root nodes } } StringBuilder sb = new StringBuilder(); while (!queue.isEmpty()) { Person current = queue.poll(); sb.append(current.getName()).append(" "); // Add children in the order they were added (left-to-right) queue.addAll(current.getChildren()); } return sb.toString().trim(); }
Test the traversal method:
@Test void testLevelOrderTraversal() { // Expected order: A (level 1), B & D (level 2), C (level 3) assertEquals("A B D C", familyTree.levelOrderTraversal()); }
4. Extension Ideas
- Support More Relationships: Add mother, sibling, or grandparent checks by extending the
Personclass andFamilyTreequery methods. - File Input Handling: Add a
loadFromFile(String filePath)method usingBufferedReaderto parse relationships from a text file. - Cycle Detection: Add validation to catch impossible relationships (e.g., "A is father of B" and "B is father of A").
内容的提问来源于stack exchange,提问作者sakshi

