2013-03-09 7 views
4

Я пытаюсь найти способ, которым я мог бы взять двоичный древовидный класс и пройти через его узлы,
, выполняя X количество встроенных действий на каждом узле, не переписывая один и тот же код обхода снова и снова.
я бы себе, если Java разрешено указатели на функции, это было бы намного проще для меня, чтобы выяснить ...

Обобщение действий для обхода двоичного дерева?

В принципе, то, что мне нужно что-то вроде следующего:

public class BinaryTreeNode { 

    //... 

    public void inOrderTraversalFrom(BinaryTreeNode node, /* ??? */ actions) { 
     if(node.left != null) 
      inOrderTraversalFrom(node.left); 

     /* do something with "actions" here */ 

     if(node.right != null) 
      inOrderTraversalFrom(node.right); 
    } 
} 


... где действия могут допускать выполнение различных методов, , принимая различные параметры в зависимости от типа действия (действий), которое должно выполняться на каждом узле.

Хорошим примером этого может быть класс, предназначенный для рисования этих узлов, который может быть передан, принимая объект Graphics как один из его параметров, по сравнению с классом, который предназначен для выполнения ряда других действий, t требуется объект Graphics в качестве параметра, а вместо него - совершенно другой набор параметров.

Как это возможно? Каким будет наиболее динамичный способ выполнения этого?

+2

http://stackoverflow.com/questions/122407/whats-the-nearest-substitute-for-a-function- pointer-in-java –

+0

@MitchWheat очень интересно, мне придется использовать это когда-нибудь ... но он все еще не решает проблему перезаписи того же метода inOrderTraversalFrom' d принимать разные интерфейсы. Возможно, использование дженериков может быть каким-то образом объединено здесь? – RectangleEquals

ответ

1

Один из способов сделать это будет:

action может быть экземпляром класса, который получает Node и применяет действие к нему:

public interface Action{ 
    public void apply(Node node){ 
    // To be done in the classes that will implement 
    // this interface. If it's a graphic-display of the nodes, the apply 
    // method will call draw(node.value), for example 
    } 
} 

линии:

/* do something with "actions" here */ 

следует заменить на

action.apply(node); 

Сигнатура метода должен быть изменен на:

public void inOrderTraversalFrom(BinaryTreeNode node, Action action) 

и рекурсивный вызов должен быть:

inOrderTraversalFrom(node.left, action); 
+0

Это было очень близко к тому, что я собирался, но не принимает переменный набор параметров для определенного действия, которое необходимо выполнить. – RectangleEquals

+0

Ответ, который вы опубликовали, очень близок к моему предложению: Preform - это другое имя для применения. Единственное различие заключается в том, что ваше решение предлагает еще один уровень абстракции, который необходим, когда вы хотите использовать внешние библиотеки в своем решении (что не упоминалось в вопросе). Пока вы выполняете графические действия - вы можете реализовать метод apply() 'непосредственно в своем классе, и вам не нужен этот дополнительный уровень абстракции. – alfasin

+0

Я ушел от ссылки, предоставленной Митчем Пшеницей ранее о указателях функций в Java. Наш код связан по совпадению, так как я опубликовал мой до обновления страницы. И я понимаю, что вы имеете в виду сейчас, но это не позволяет выполнять действия _inline_ (что-то, что мой вопрос _does_ спрашивает). Например, если «BinaryTreeView» должен был реализовать «BinaryTreeActions», как бы передать объект _Graphics_ в «DrawNode»? Пропустить не будет, пока он не будет передан в BinaryTreeView.DrawNodes, поскольку DrawNodes вызывается из переопределенного метода 'paint' ... – RectangleEquals

1

Я нашел решение, хотя оно не может быть лучшим ...

BinaryTreeNode.java:

public void inOrderTraversalFrom(BinaryTreeNode rootNode, BinaryTreeActions actions) 
{ 
    if(rootNode.left != null) 
     inOrderTraversalFrom(rootNode.left, actions); 

    if(actions != null) 
     actions.Perform(rootNode); 

    if(rootNode.right != null) 
     inOrderTraversalFrom(rootNode.right, actions); 
} 


BinaryTreeActions.java:

public interface BinaryTreeActions { 
    public void Perform(BinaryTreeNode node); 
} 


BinaryTreeGraphicsActions.java:

public interface BinaryTreeGraphicsActions extends BinaryTreeActions { 
    void DrawNode(BinaryTreeNode node, Graphics g); 
} 


BinaryTreeView.Java:

private void DrawNodes(final Graphics graphics) 
{ 
    BinaryTreeNode node = root; 
    root.inOrderTraversalFrom(node, new BinaryTreeGraphicsActions() { 
     @Override 
     public void DrawNode(BinaryTreeNode node, Graphics g) { 
      // draw the node 
     } 

     @Override 
     public void Perform(BinaryTreeNode node) { 
      DrawNode(node, graphics); 
     } 
    }); 
} 


... и в любое время вам нужен новый набор действий, вы можете создать новый интерфейс для него, следуя той же идеи в BinaryTreeGraphicsActions и BinaryTreeView. Это позволяет выполнять любой набор действий в зависимости от интерфейса, который вы им разработали.


#edit: Я принял подобный ответ после обнаружения нет необходимости BinaryTreeGraphicsActions, так как вы можете сделать то же встроенный код просто с помощью BinaryTreeActions как так:

private void DrawNodes(final Graphics graphics) 
{ 
    BinaryTreeNode node = root; 
    root.inOrderTraversalFrom(node, new BinaryTreeActions() { 
     @Override 
     public void Perform(BinaryTreeNode node) { 
      /* draw the node, using any local vars (providing they are final) */ 
     } 
    }); 
} 
+0

+1 для ответа и редактирования! – alfasin

0

Читает решение довольно похоже на другие, предложенные здесь. Но с некоторыми обледенениями дизайна, если вы занимаетесь этими вещами.

Идея состоит в том, чтобы отделить не только действия, но и обход. Это можно сделать с помощью следующих 2 абстракций.

  • BinaryTreeNodeTraversalStrategy
  • BinaryTreeNodeVisitor


public interface Visitable<T extends Visitor> { 

    public void accept(T visitor); 
} 

public interface Visitor<T extends Visitable> { 

    public void visit(T visitable); 
} 

public interface BinaryTreeNode implements Visitable<BinaryTreeNodeVisitor> { 

    public void accept(BinaryTreeNodeVisitor visitor); 
} 

public interface BinaryTreeNodeVisitor implements Visitor<BinaryTreeNode> { 

    public void visit(BinaryTreeNode visitable); 
} 

public interface BinaryTreeNodeTraversalStrategy { 

    public void traverse(BinaryTreeNode root); 
} 
Смежные вопросы