I want to convert a tree that represents a math expression into the actual math expression (a string like "a+b/c")
The tree representation is the simplest you could imagine:
A+B/C would be this tree:
OperationNode(+, A, OperationNode(/, B, C))
And (A+B)/C would be this tree:
OperationNode(/, OperationNode(+, A, B), C)
In order to convert the tree into the string, I'm using the Visitor pattern. The problem comes with parentheses.
My current Visitor implementation ALWAYS adds parentheses to the nodes, so every tree I generate turns into a string like this:
(((A+B)+C)+D)
Notice the redundant parentheses.
So the question is: how could I make my Visitor generate the string with no redundant parentheses?
As NelFeal wrote while walking the tree you just need to check if precedence of suboperation less than a precedence of the current operation.
I implemented visitor pattern for you, hope it helps.
enum Operation
{
Add,
Multiply,
Power,
UnaryMinus,
None,
}
static class OperationExtensions
{
public static string ToFriendlyString(this Operation me)
{
switch (me)
{
case Operation.None:
return "";
case Operation.Add:
return "+";
case Operation.Multiply:
return "*";
case Operation.Power:
return "^";
case Operation.UnaryMinus:
return "-";
default:
throw new ArgumentException();
}
}
}
class OperationNode
{
public Operation Op;
public OperationNode(Operation op)
{
Op = op;
}
}
interface IVisitor
{
void Visit(OperationNodeLeaf node);
void Visit(OperationNode1 node);
void Visit(OperationNode2 node);
}
sealed class Visitor : IVisitor
{
public string Text { get; set; }
private void Enclose(OperationNode subNode, Operation op)
{
if (subNode.Op < op)
{
Text = Text + "(";
Visit((dynamic)subNode);
Text = Text + ")";
}
else
{
Visit((dynamic)subNode);
}
}
public void Visit(OperationNodeLeaf node)
{
Text = Text + node.Op.ToFriendlyString();
Text = Text + node.Value.ToString();
}
public void Visit(OperationNode1 node)
{
Text = Text + node.Op.ToFriendlyString();
Enclose(node.SubNode, node.Op);
}
public void Visit(OperationNode2 node)
{
Enclose(node.LeftSubNode, node.Op);
Text = Text + node.Op.ToFriendlyString();
Enclose(node.RightSubNode, node.Op);
}
}
class OperationNodeLeaf : OperationNode
{
public int Value;
public OperationNodeLeaf(int v, Operation op = Operation.None) : base(op)
{
Value = v;
}
void Accept(IVisitor v)
{
v.Visit(this);
}
}
class OperationNode1 : OperationNode
{
public OperationNode SubNode;
public OperationNode1(OperationNode sn, Operation op) : base(op)
{
SubNode = sn;
}
void Accept(IVisitor v)
{
v.Visit(this);
}
}
class OperationNode2 : OperationNode
{
public OperationNode LeftSubNode;
public OperationNode RightSubNode;
public OperationNode2(OperationNode lsn, OperationNode rsn, Operation op) : base(op)
{
LeftSubNode = lsn;
RightSubNode = rsn;
}
void Accept(IVisitor v)
{
v.Visit(this);
}
}
class Program
{
static void Main(string[] args)
{
var tree =
new OperationNode2(
new OperationNode2(
new OperationNode2(new OperationNodeLeaf(5), new OperationNodeLeaf(6), Operation.Add),
new OperationNode2(new OperationNodeLeaf(5), new OperationNodeLeaf(6), Operation.Multiply),
Operation.Power
),
new OperationNode2(
new OperationNode2(new OperationNodeLeaf(1), new OperationNodeLeaf(2), Operation.Multiply),
new OperationNode1(new OperationNodeLeaf(7, Operation.None), Operation.UnaryMinus),
Operation.Add
),
Operation.Multiply
);
var visitor = new Visitor();
visitor.Visit(tree);
System.Diagnostics.Debug.WriteLine(visitor.Text);
}
}
(5+6)^(5*6)*(1*2+-7)
You need a operator precedence table. Simply assign precedence values to every operator you support (and maybe to the topmost no-op that gives you the outermost pair of parentheses). Then, for each operation node, if its operation has a higher precedence than the parent node operation, you don't need parentheses.
Related
I am using JavaParser library (https://github.com/javaparser/javaparser) for parsing Java method declarations. I want to identify different method declarations from different packages, classes, scopes, etc. so that I can precisely identify every method declarations.
For example:
Here is a Java file called MainClass.java:
package com.company.packA.packB;
public class MainClass {
void doTask(int x, int y) {
//...
}
private class InnerClass {
void doTask(int x, int y) {
//...
}
}
}
class AnotherClassSameFile {
void doTask(int x, int y) {
//...
}
}
Notice that the above example contains three void doTask(int x, int y) methods:
com.company.packA.packB→MainClass→doTask(int x, int y)
com.company.packA.packB→MainClass→InnerClass→doTask(int x, int y)
com.company.packA.packB→AnotherClassSameFile→doTask(int x, int y)
To identify different method declarations with the same method signatures, I need to traverse all parent nodes until the root node.
So far I have tried this code (simplified) using JavaParser library:
class MethodStruct { // the second example will be:
String parentNodes; // com.company.packA.packB#MainClass#InnerClass
String returnType; // void
String methodName; // doTask
String parameters; // int,int
}
class JavaParserTest {
// this is the method to be called from outside
static List<MethodStruct> getMethodStructs(Reader reader) {
CompilationUnit cu = JavaParser.parse(reader);
List<MethodStruct> methodStructs = new LinkedList<>();
cu.accept(new MethodVisitor(), methodStructs);
return methodStructs;
}
static class MethodVisitor extends VoidVisitorAdapter<List<MethodStruct>> {
#Override
public void visit(MethodDeclaration methodDeclaration, List<MethodStruct> methodStructs) {
super.visit(methodDeclaration, methodStructs);
// adding individual methodStruct into the list
methodStructs.add(getMethodStruct(methodDeclaration));
}
static MethodStruct getMethodStruct(MethodDeclaration methodDeclaration) {
return new MethodStruct(
getParents(methodDeclaration),
methodDeclaration.getTypeAsString(),
methodDeclaration.getNameAsString(),
getParameterAsString(methodDeclaration.getParameters()));
}
// it is the method to be concerned for my question
static String getParents(MethodDeclaration methodDeclaration) {
StringBuilder parents = new StringBuilder();
Node currentNode = methodDeclaration;
while (currentNode.getParentNode().isPresent()) {
// goto parent node
currentNode = currentNode.getParentNode().get();
//TODO: I'm stuck here. Help me please!
//TODO: How to identify each node whether
// it is a package, innerClass, etc?
}
// convert StringBuilder into String and return the String
return parents.toString();
}
static String getParameterAsString(NodeList<Parameter> parameters) {
// easy task! convert parameter string list
// into a single string (comma separated)
}
}
}
I am facing difficulties in defining my getParents(MethodDeclaration methodDeclaration) method. How can I solve it (i.e., identify every parent nodes)? I can't find any useful method of Node class for my goal. I might have missed something in JavaParser library.
You should try to use walk method to find all scopes of concrete method declaration:
static String getParents(fina MethodDeclaration methodDeclaration) {
final StringBuilder parents = new StringBuilder();
methodDeclaration.walk(Node.TreeTraversal.PARENTS, node -> {
if (node instanceof ClassOrInterfaceDeclaration) {
path.insert(0, ((ClassOrInterfaceDeclaration) node).getNameAsString());
path.insert(0, '$');
}
if (node instanceof ObjectCreationExpr) {
path.insert(0, ((ObjectCreationExpr) node).getType().getNameAsString());
path.insert(0, '$');
}
if (node instanceof MethodDeclaration) {
path.insert(0, ((MethodDeclaration) node).getNameAsString());
path.insert(0, '#');
}
if (node instanceof CompilationUnit) {
final Optional<PackageDeclaration> pkg = ((CompilationUnit) node).getPackageDeclaration();
if (pkg.isPresent()) {
path.replace(0, 1, ".");
path.insert(0, pkg.get().getNameAsString());
}
}
});
// convert StringBuilder into String and return the String
return parents.toString();
}
Sometimes methods have the only difference somwhere in the middles of their bodies and it's difficult to generalize them or extract common part of code to a single method.
Question itself: How would you refactor the following implementations of interface methods to avoid duplicate code around for loop body?
interface MyInterface {
Integer myInterfaceMethod(String inputStr);
Integer myInterfaceOtherMethod(String inputStr)
}
class MyClass implements MyInterface {
public Integer myInterfaceMethod(String inputStr) {
#Override
try {
List<String> listDependingOnString = getListByString(inputStr);
Integer result = -1;
if (inputStr != null) {
result = 0;
for (String str : listDependingOnString) {
// Some different code, given just for example
result += str.length();
}
}
return result;
} catch (Exception e) {
exceptionProcessing(e);
return null;
}
}
#Override
public Integer myInterfaceOtherMethod(String inputStr) {
try {
List<String> listDependingOnString = getListByString(inputStr);
Integer result = -1;
if (inputStr != null) {
result = 0;
for (String str : listDependingOnString) {
// Some different code, given just for example
System.out.println(str);
++result;
}
}
return result;
} catch (Exception e) {
exceptionProcessing(e);
return null;
}
}
}
For this particular example, a lambda would work nicely:
private Integer computeStringFunction(String inputStr, BiFunction<Integer,String,Integer> accumulator) {
try {
List<String> listDependingOnString = getListByString(inputStr);
Integer result = -1;
if (inputStr != null) {
result = 0;
for (String str : listDependingOnString) {
result = accumulator.apply(result, str);
}
}
return result;
} catch (Exception e) {
exceptionProcessing(e);
return null;
}
public Integer myInterfaceMethod(String inputStr) {
return computeStringFunction(inputStr,
(Integer oldValue, String str) -> oldValue + str.length());
}
public Integer myInterfaceOtherMethod(String inputStr) {
return computeStringFunction(inputStr,
(Integer oldValue, String str) -> {
System.out.println(str);
return oldValue + 1;
});
}
"accumulator" here is a function that takes an integer and a string and returns another integer, and whose intent is to keep a "running total" of some sort.
BiFunction documentation
Note: not tested
The key to remove duplicate pattern in codes is to abstract the common part to one place and then find a way to pass the different part of "code pieces" as parameters to execute, for languages in which function is first class citizen(JavaScript, Python), you can always wrap the "code pieces" as functions. But it's not applicable for Java because method in Java is not a value, one way to resolve it is to define interfaces, and then pass the instance of a class which implements the interface as parameters, with lambda expression in Java 8 it can be more simpler.
Take the code in question as example, the common pattern is:
iterate the list and process each item
accumulate the result of each item and return
Then we can define two interfaces:
#FunctionalInterface
public interface ItemHandler<T, R> {
/**
* Takes input item of type T, then returns result of type R
*/
R handle(T t);
}
And another interface to accumulate the result:
#FunctionalInterface
public interface ItemResultAccumulator<T> {
T accumulate(T t1, T t2);
}
and then your code could be refactored as(I removed all exception handling and null checking code, to make the code less verbose to view):
public class MyClass implements MyInterface {
private static final ItemResultAccumulator<Integer> ADDER = (t1, t2) -> t1 + t2;
#Override
public Integer myInterfaceMethod(String inputStr) {
return processList(getListByString(inputStr), s -> s.length(), ADDER);
}
#Override
public Integer myInterfaceOtherMethod(String inputStr) {
return processList(getListByString(inputStr), s -> {
System.out.println(s);
return Integer.valueOf(1);
}, ADDER);
}
private Integer processList(List<String> list, ItemHandler<String, Integer> handler, ItemResultAccumulator<Integer> accumulator) {
Integer result = 0;
if (list != null && list.size() > 0) {
for (String item : list) {
result = accumulator.accumulate(result, handler.handle(item));
}
}
return result;
}
private List<String> getListByString(String inputStr) {
// Your logic to generate list by input
return Lists.newArrayList(inputStr.split(","));
}
}
This is a little of my thinking of this problem, hope this could be helpful:-)
Is there an elegant way to obtain multiple dispatch for methods with 2 parameters (or even more) in OO languages with (single) dynamic dispatch?
Example of a possible problem:
This is a Java-inspired example. (the problem is not language related!)
// Visitable elements
abstract class Operand {
}
class Integer extends Operand {
int value;
public int getValue() {
return value;
}
}
class Matrix extends Operand {
int[][] value;
public int[][] getValue() {
return value;
}
}
// Visitors
abstract class Operator {
// Binary operator
public Operand eval(Operand a, Operand b) {
return null; // unknown operation
}
}
class Addition extends Operator {
public Operand eval(Integer a, Integer b) {
return new Integer(a.getValue() + b.getValue());
}
}
class Multiplication extends Operator {
public Operand eval(Integer a, Integer b) {
return new Integer(a.getValue() * b.getValue());
}
// you can multiply an integer with a matrix
public Operand eval(Integer a, Matrix b) {
return new Matrix();
}
}
I have many Operator and Operand concrete types but only refer to them through their abstract types:
Operand a = new Integer()
Operand b = new Matrix();
Operand result;
Operator mul = new Multiplication();
result = mul.eval(a, b); // Here I want Multiplication::eval(Integer, Matrix) to be called
I decided to add to this since the above two answers are somewhat incomplete. I was myself curious about this issue but couldn't find an answer so had to do my own analysis. In general there are two approaches that can be used to implement multi-methods in languages like C++ or Java that support both single dynamic dispatch and something like typeof or runtime type identification.
For the double dispatch case the visitor pattern is most common (for Arg1->foo(Arg2) ) and I gather in most cases is preferred to using RTTI and switches or if statements. One can also generalize the visitor approach to the n case by i.e. Arg1->foo(Arg2,Arg3..ArgN) by chaining a series of single dispatches that call methods in a treelike structure that differentiate on the type of the arguments up to some k and split the number of ways of the k+1 argument. For example for a simple case of triple dispatch and only two instances of each type:
interface T1 {
public void f(T2 arg2, T3 arg3);
}
interface T2 {
public void gA(A a, T3 arg3)
public void gB(B b, T3 arg3)
}
interface T3 {
public void hAC(A a,C c);
public void hAD(A a,D d);
public void hBC(B b,C c);
public void hBD(B b,D d);
}
class A implements T1 {
public void f(T2 arg2, T3 arg3) {
arg2->gA(this,arg3);
}
}
class B implements T1 {
public void f(T2 arg2, T3 arg3) {
arg2->gB(this,arg3);
}
}
class C implements T2 {
public void gA(A a,T arg3) {
arg3->hAC(a, this);
}
public void gB(B b,T arg3) {
arg3->hBC(b, this);
}
}
class D implements T2 {
public void gA(A a,T arg3) {
arg3->hAD(a, this);
}
public void gB(B b,T arg3) {
arg3->hBD(b, this);
}
}
class E implements T3 {
public void hAC(A a,C c) {
System.out.println("ACE");
}
public void hAD(A a,D d) {
System.out.println("ADE");
}
public void hBC(B b,C c) {
System.out.println("BCE");
}
public void hBD(B b,D d) {
System.out.println("BDE");
}
}
class F implements T3 {
public void hAC(A a,C c) {
System.out.println("ACF");
}
public void hAD(A a,D d) {
System.out.println("ADF");
}
public void hBC(B b,C c) {
System.out.println("BCF");
}
public void hBD(B b,D d) {
System.out.println("BDF");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
C c = new C();
E e = new E();
a.f(c,e);
}
}
Though the approach generalizes the problem are quite obvious. For each endpoint function in the worse case one has to write n-1 dispatch functions.
One can achieve something similar with runtime type identification via the instanceOf operator:
class Functions
{
static void f(A a,C c,E e) {
System.out.println("ACE");
}
static void f(A a,C c,F f) {
System.out.println("ACF");
}
static void f(A a,D d,E e) {
System.out.println("ADE");
}
static void f(A a,D d,F f) {
System.out.println("ADF");
}
static void f(B b,C c,E e) {
System.out.println("BCE");
}
static void f(B b,C c,F f) {
System.out.println("BCF");
}
static void f(B b,D d,E e) {
System.out.println("BDE");
}
static void F(B b,D d,F f) {
System.out.println("BDF");
}
static void dispatch(T1 t1, T2 t2, T3 t3) {
if( t1 instanceOf A)
{
if(t2 instance of C) {
if(t3 instance of E) {
Function.F( (A)t1, (C)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (A)t1, (C)t2, (F)t3 );
}
}
else if(t2 instance of D) {
if(t3 instance of E) {
Function.F( (A)t1, (D)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (A)t1, (D)t2, (F)t3 );
}
}
}
else if(t1 instanceOf B) {
if(t2 instance of C) {
if(t3 instance of E) {
Function.F( (B)t1, (C)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (B)t1, (C)t2, (F)t3 );
}
}
else if(t2 instance of D) {
if(t3 instance of E) {
Function.F( (B)t1, (D)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (B)t1, (D)t2, (F)t3 );
}
}
}
}
}
The second solution can probably be further simplified using reflection.
I am not sure that I will answer your question, but I hope I can add a bit to the discussion. I will try to come back later with a more general answer, but in this one I will focus only on your example above.
The problem with the example given in the question is that it is based on arithmetical operations and that makes it inherently complex because the implementation of a given operator changes depending on the types of its operands.
I think that the problem obscures the question a little bit, e.g. we could spend time trying to make your example work instead of dealing with multiple dispatch issues.
One way to make your code work would be to think from a different point of view. Instead of defining an abstraction called Operator what we could do is to recognize the inherent nature of the operands, namely that they must provide an implementation of every possible operation that can affect them. In object-oriented terms, every operand packs a bunch of actions that can affect them.
And so, imagine I have an interface Operand like this, that defines every possible operation an operand supports. Notice that I not only defined one method variance per every possible known operand but also one method for a general case of another unknown operand:
interface Operand {
Operand neg();
Operand add(Int that);
Operand add(Decimal that);
Operand add(Operand that);
Operand mult(Int that);
Operand mult(Decimal that);
Operand mult(Operand that);
Operand sub(Int that);
Operand sub(Decimal that);
Operand sub(Operand that);
}
Then now consider that we had two implementations of this: Int and Decimal (I will use decimal instead of the matrix of your example for simplicity).
class Int implements Operand {
final int value;
Int(int value) { this.value = value; }
public Int neg(){ return new Int(-this.value); }
public Int add(Int that) { return new Int(this.value + that.value); }
public Decimal add(Decimal that) { return new Decimal(this.value + that.value); }
public Operand add(Operand that) { return that.add(this); } //!
public Int mult(Int that) { return new Int(this.value * that.value); }
public Decimal mult(Decimal that) { return new Decimal(this.value * that.value); }
public Operand mult(Operand that) { return that.mult(this); } //!
public Int sub(Int that) { return new Int(this.value - that.value); }
public Decimal sub(Decimal that) { return new Decimal(this.value - that.value); }
public Operand sub(Operand that) { return that.neg().add(this); } //!
public String toString() { return String.valueOf(this.value); }
}
class Decimal implements Operand {
final double value;
Decimal(double value) { this.value = value; }
public Decimal neg(){ return new Decimal(-this.value); }
public Decimal add(Int that) { return new Decimal(this.value + that.value); }
public Decimal add(Decimal that) { return new Decimal(this.value + that.value); }
public Operand add(Operand that) { return that.add(this); } //!
public Decimal mult(Int that) { return new Decimal(this.value * that.value); }
public Decimal mult(Decimal that) { return new Decimal(this.value * that.value); }
public Operand mult(Operand that) { return that.mult(this); } //!
public Decimal sub(Int that) { return new Decimal(this.value - that.value); }
public Decimal sub(Decimal that) { return new Decimal(this.value - that.value); }
public Operand sub(Operand that) { return that.neg().add(this); } //!
public String toString() { return String.valueOf(this.value); }
}
Then I can do this:
Operand a = new Int(10);
Operand b = new Int(10);
Operand c = new Decimal(10.0);
Operand d = new Int(20);
Operand x = a.mult(b).mult(c).mult(d);
Operand y = b.mult(a);
System.out.println(x); //yields 20000.0
System.out.println(y); //yields 100
Operand m = new Int(1);
Operand n = new Int(9);
Operand q = m.sub(n);
Operand t = n.sub(m);
System.out.println(q); //yields -8
System.out.println(t); //yeilds 8
The key points here are:
Every operand implementation works in a similar way to a visitor pattern, in the sense that every operand implementation contains a dispatch function for every possible combination that you can get.
The tricky part is the method that acts on any Operand. This is the place where we exploit the visitor dispatch power, because we know the exact type of this, but not the exact type of that, so we force the dispatch by doing that.method(this) and problem solved!
However, since we invert the order of the evaluation, this has a problem with arithmetic operations that are not commutative, like the subtraction. That's why I do subtraction using addition instead (i.e. 1-9 equates to 1 + -9). Since addition is commutative.
And there you have it. Now I kind of found a solution to the specific example, but I have not provided a good solution to the multiple dispatch problem you originally had. That's why I said the example was not good enough.
Perhaps you could provide a better example, like the one in the Wikipedia page for Multiple Dispatch.
However, I think the solution will probably always be, reduce the problem to a series of single dispatches solved with some sort of visitor pattern like the one I did. If I have time, I will try to give it a shot later to a more general answer and not just this specific example.
But hopefully this post helps to foster further discussion and with luck it is step in the direction of the actual answer.
uncle bob did this:
// visitor with triple dispatch. from a post to comp.object by robert martin http://www.oma.com
/*
In this case, we are actually using a triple dispatch, because we have two
types to resolve. The first dispatch is the virtual Collides function which
resolves the type of the object upon which Collides is called. The second
dispatch is the virtual Accept function which resolves the type of the
object passed into Collides. Now that we know the type of both objects, we
can call the appropriate global function to calculate the collision. This
is done by the third and final dispatch to the Visit function.
*/
interface AbstractShape
{
boolean Collides(final AbstractShape shape);
void Accept(ShapeVisitor visitor);
}
interface ShapeVisitor
{
abstract public void Visit(Rectangle rectangle);
abstract public void Visit(Triangle triangle);
}
class Rectangle implements AbstractShape
{
public boolean Collides(final AbstractShape shape)
{
RectangleVisitor visitor=new RectangleVisitor(this);
shape.Accept(visitor);
return visitor.result();
}
public void Accept(ShapeVisitor visitor)
{ visitor.Visit(this); } // visit Rectangle
}
class Triangle implements AbstractShape
{
public boolean Collides(final AbstractShape shape)
{
TriangleVisitor visitor=new TriangleVisitor(this);
shape.Accept(visitor);
return visitor.result();
}
public void Accept(ShapeVisitor visitor)
{ visitor.Visit(this); } // visit Triangle
}
class collision
{ // first dispatch
static boolean Collides(final Triangle t,final Triangle t2) { return true; }
static boolean Collides(final Rectangle r,final Triangle t) { return true; }
static boolean Collides(final Rectangle r,final Rectangle r2) { return true; }
}
// visitors.
class TriangleVisitor implements ShapeVisitor
{
TriangleVisitor(final Triangle triangle)
{ this.triangle=triangle; }
public void Visit(Rectangle rectangle)
{ result=collision.Collides(rectangle,triangle); }
public void Visit(Triangle triangle)
{ result=collision.Collides(triangle,this.triangle); }
boolean result() {return result; }
private boolean result=false;
private final Triangle triangle;
}
class RectangleVisitor implements ShapeVisitor
{
RectangleVisitor(final Rectangle rectangle)
{ this.rectangle=rectangle; }
public void Visit(Rectangle rectangle)
{ result=collision.Collides(rectangle,this.rectangle); }
public void Visit(Triangle triangle)
{ result=collision.Collides(rectangle,triangle); }
boolean result() {return result; }
private boolean result=false;
private final Rectangle rectangle;
}
public class MartinsVisitor
{
public static void main (String[] args)
{
Rectangle rectangle=new Rectangle();
ShapeVisitor visitor=new RectangleVisitor(rectangle);
AbstractShape shape=new Triangle();
shape.Accept(visitor);
}
}
So I can really get this I was wondering if anyone could help me out, the object of this program is to use the visitor pattern to generate a list of strings from the name of people in a given binary tree, if not really sure how to go about using an append function to do so. How would I append the person with its parents?
import tester.Tester;
//Representation for an ancestor tree
interface IAT {
<R> R accept(IATVisitor<R> visitor);
//Append two lists
IList<String> append(IList<String> l);
}
//-------------------------------------------------------------------------------------------------
//Unknown person
class Unknown implements IAT {
Unknown() {
}
public <R> R accept(IATVisitor<R> visitor) {
return visitor.visitUnknown(this);
}
//append two an unknown
public IList<String> append(IList<String> l) {
return l;
}
}
//-------------------------------------------------------------------------------------------------
//Representation for a person
class Person implements IAT {
String name;
int yob;
boolean isMale;
IAT mom;
IAT dad;
//Constructor
Person(String name, int yob, boolean isMale, IAT mom, IAT dad) {
this.name = name;
this.yob = yob;
this.isMale = isMale;
this.mom = mom;
this.dad = dad;
}
public <R> R accept(IATVisitor<R> visitor) {
return visitor.visitPerson(this);
}
//append parent and children of tree
public IList<String> append(IList<String> l) {
//
}
}
//-------------------------------------------------------------------------------------------------
interface IATVisitor<R> {
R visitUnknown(Unknown u);
R visitPerson(Person p);
}
//-------------------------------------------------------------------------------------------------
//IAT Visitor that returns a list of the names of all people
class IATVisitGetNames implements IATVisitor<IList<String>> {
public IList<String> visitUnknown(Unknown u) {
return new MT<String>();
}
public IList<String> visitPerson(Person p) {
return new Cons<String>(p.name, new MT<String>());
}
}
//Examples
class ExamplesIATV {
//persons
Unknown a = new Unknown();
Person ralph = new Person("Ralph", 1995, true, a, a);
Person kevin = new Person("Kevin", 1994, true, a , a);
Person julia = new Person("Julia", 1991, false, ralph, a);
Person lily = new Person("Lily", 1990, false, kevin, julia);
Person who = new Person("?", 1738, false, lily, a);
//Visitor
IATVisitor<IList<String>> byName = new IATVisitGetNames();
//test Vistior
boolean testGetNames(Tester t) {
return
t.checkExpect(who.accept(byName), new MT<String>());
}
}
First - you want collect all names from tree. You need traversal function, for example:
public void traverse(Node root) {
//do somesing with node
System.out.println(root.value);
if (root.left != null) {
traverse(root.left);
}
if (root.right != null) {
traverse(root.right);
}
}
Second - you want to use Visitor pattern. How wikipedia says:
Visitor - is a way of separating an algorithm from an object structure
on which it operates.
So visitor is not suitable for travers/itereate logic. With visitor we can only incapsulate some logic on node:
public void traverseWithVisitor(Node root, IVisitor v) {
root.accept(v);
if (root.left != null) {
traverseWithVisitor(root.left, v);
}
if (root.right != null) {
traverseWithVisitor(root.right, v);
}
}
Now incapsulate our collecting names logic in visitor:
class AggregateNamesVisitor implements IVisitor {
public List<Integer> names = new ArrayList<>();
#Override
public void visit(Node node) {
names.add(node.value);
}
}
We can use it like this:
AggregateNamesVisitor aggregateVisitor = new AggregateNamesVisitor();
traverseWithVisitor(root, aggregateVisitor);
aggregateVisitor.names.forEach(name -> System.out.print(" " + name));
I'm creating a (atypical)tree in Java that will be composed of three classes: node, branch and leaf
Each node stores the branches it is connected to in a HashSet. The branch is supposed to lead to a descendent node or a leaf, but I'm not sure how to code that. Would I just have two separate variables, one Node and one Leaf in the branch class, along with two sets of getters and setters, even though I will never use both? Is there a best practice in this regard?
I was thinking maybe make node and leaf subclasses of the same superclass, but they have absolutely nothing in common in terms of code(i.e. different variable types, functions, etc.).
EDIT:
Node references branches and
each Branch references a Node or a Leaf
I'd probably go with something like this:
interface BranchDestination {
boolean isLeaf();
}
class Node implements BranchDestination {
private Set branches;
public boolean isLeaf() {
return false;
}
...
}
class Leaf implements BranchDestination {
public boolean isLeaf() {
return true;
}
...
}
class Branch {
BranchDestination destination;
...
}
I do like the idea of defining an interface for the leaf / node classes, and implement that interface in each. I would define a simple function in that interface (syntax might be wrong below, but it's pseduo-ish code):
interface BranchItem {
public object[] GetVals();
}
public class Branch
{
public BranchItem item;
}
public class Leaf implements BranchItem
{
private object myVal = <your data here>;
public object[] GetVals() {
return new object[] { myVal };
}
}
public class Node implements BranchItem
{
private myBranches[] = <List of Branches>;
public object[] GetVals() {
object[] myArray = new object[];
foreach (BranchItem b in myBranches)
{
myArray.addTo(b.item.GetVals());
}
return myArray;
}
}
When traversing your node, simply iterate over the Branches and call GetVals().
The Leaf class will simply returns it's stored value.
The Node Class will recursively loop over it's branches, calling GetVals() on each and add it to it's own returned array.
This is but a simple implementation. If you want sort order, handle collisions or duplicate data, or anything of that nature it could get more complicated.
Make the Leaf class with the basic information.
Make the Branch class which holds references to Leafs.
Make the Node class which holds references to Brahces.
Then try look up Recursion and how to use it to make such constructs :)
Here is my go at it. Though not very elegant, it gets the job done.
Here is the Leaf class:
public class Leaf {
private String text;
public Leaf(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setString(String newString) {
text = newString;
}
#Override
public String toString() {
return text;
}
}
And here is the Branch class:
public class Branch<T> {
private String text;
private HashSet<T> list;
public Branch(String text) {
this.text = text;
list = new HashSet<>();
}
public String getText() {
return text;
}
public void setText(String newText) {
text = newText;
}
public HashSet<T> getHashSet() {
return list;
}
public void setHashSet(HashSet<T> newList) {
list = newList;
}
public String getAllLeaves() {
StringBuilder sb = new StringBuilder();
sb.append(text).append("\n");
for(T t : list) {
sb.append("\t\t");
sb.append(t.toString()).append("\n");
}
return sb.toString();
}
#Override
public String toString() {
return text;
}
}
Lastly the Node class:
public class Node<T> {
private String text;
private HashSet<T> list;
public Node(String text) {
this.text = text;
list = new HashSet<>();
}
public String getText() {
return text;
}
public void setText(String newText) {
text = newText;
}
public HashSet<T> getHashSet() {
return list;
}
public void setHashSet(HashSet<T> newList) {
list = newList;
}
}
Little test program to try it out:
public class TreeConstruct {
public static void main(String[] args) {
Leaf l1 = new Leaf("Leaf 1");
Leaf l2 = new Leaf("Leaf 2");
Leaf l3 = new Leaf("Leaf 3");
Leaf l4 = new Leaf("Leaf 4");
Branch<Leaf> b1 = new Branch("Branch 1");
Branch<Leaf> b2 = new Branch("Branch 2");
Node<Branch> n1 = new Node("Node 1");
b1.getHashSet().add(l1);
b1.getHashSet().add(l2);
b1.getHashSet().add(l3);
b2.getHashSet().add(l4);
n1.getHashSet().add(b1);
n1.getHashSet().add(b2);
System.out.println(printNodeTree(n1));
}
public static String printNodeTree(Node<Branch> n) {
StringBuilder sb = new StringBuilder();
sb.append(n.getText()).append("\n");
for(Branch b : n.getHashSet()) {
sb.append("\t");
sb.append(b.getAllLeaves());
}
return sb.toString();
}
}
The output will be:
Node 1
Branch 1
Leaf 1
Leaf 3
Leaf 2
Branch 2
Leaf 4
Hope this helps!