I'm using Swing and have a JTree in my GUI. During execution, I parse through the nodes of the tree to determine what action to perform. Here's a snippet:
// action to modify node
public void modifyMenuItem(DefaultMutableTreeNode node)
{
// if node is node 1 in the tree
if(node.equals(treeNodes.node1))
{
// perform action 1
}
// if node is node 2 in the tree
else if(node.equals(treeNodes.node2))
{
// perform action 2
}
// if node is node 3 in the tree
else if(node.equals(treeNodes.node3))
{
// perform action 3
}
etc.
}
Problem is, I have close to 50 nodes in my tree and I'm afraid that I'm really hurting performance by having this type of implementation. I have similar if-statements throughout my code. What is the preferred method for handling large if-statements of Objects like this? Obviously I can't use a switch statement since these aren't Integer values, so should I create a Hashmap and then use a switch based off the Hash keys?
I would use polymorphism:
public void modifyMenuItem(DefaultMutableTreeNode node) {
((MyUserObject) node.getUserObject()).doAction();
}
For this to work, all the user objects of your nodes must be instances of the same MyUserObject interface.
Not knowing more what you are trying to do, I'd suggest you use polymorphism. You create subclasses of DefaultMutableTreeNode that also implement an interface of yours, let's call it ActionPerfomer with a method performAction(). You use instances of those classes as Nodes in your Tree and then can simply write:
// I suppose you can't change the signature?
public void modifyMenuItem(DefaultMutableTreeNode node) {
if (node instanceof ActionPerfomer) {
ActionPerfomer ap = (ActionPerfomer) node;
ap.performAction();
} else {
logger.log("How did that get here?");
}
}
Can you use a map with 50 items, keyed on the different treenodes (or treenode names), and returning an 'Action' that can be performed on the node?
Map<String, Action> map = new HashMap<String, Action>();
// populate the map with items and Actions
Action action = map.get(node.getName());
action.perform(node);
Either the treenodes need to implement equals and hashcode correctly... or you can just use the node name (given it is unique).
Good luck!
Related
I'm trying to find and remove from a main object a certain number of sub//sub/sub//..(unknown nested level) elements. My situation is like this:
Root object:
public class Root {
public int id;
public int type;
public String name;
public List<Son> sons;
....
}
The main object (Root) has a list of Son that can have N nested lists of Son objects.
Son object shares the same 3 variables names like root, plus other properties.
Since I'm not able to know how deep nesting would be, I'm trying to find a way to find inside this nested Son objects, the multiple elements I want to remove that matches a specified property (int type==1).
I've tried with stream, but maybe I'm not capable enough to fit the right commands upon the code.
Something like this:
List<Son> firstNode = root.getSons();
firstNode.stream()
.forEach(c -> {
if(c.geType()==1){
firstNode.remove(c);
logger.info("###############################>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+c.getName());
}
});
However, this doesn't work.
I've tried with a while too, counting the deepest node of the object, but nodes may vary from subnode to subnode.
Any suggestions?
Trying to make you understand more the situation, I've made a diagram about how the object may be and where the type==1 are:
https://i.imgur.com/az3iCRj.png
Ok, try this. I had to make some assumptions. It will remove all of a given type except the root. Also, you should make the root an instance of Son for this to work. You don't really need a separate root class.
Simply call this with the root instance of Son and the type to be removed.
public static void remove(Son son, int type) {
if (son == null) {
return;
}
Iterator<Son> iter = son.sons.iterator();
while(iter.hasNext()) {
Son s = iter.next();
if (s.type == type) {
iter.remove();
} else {
if (s.sons != null) {
remove(s, type);
}
}
}
}
Because that the number is not known , you need to use a recursive method to visit all the Tree.
Recursion is the technique of making a function call itself. This technique provides a way to break complicated problems down into simple problems which are easier to solve.
you need to fix a return condition first : for example
if ( listOfSon.isEmpty()) return;
And then you need to do your business logic.
After that the method need to call itself for all the Sons like that you garantee that your method will visit all existent node.
you can search for : recursion in java , Traversing through all nodes of a Tree in java . that will really give you a great idea about what you need
You may change the class Node to extends from the class Root to avoid writing another conditions
static void removeNode(Root r) {
if (r.sons!=null && !r.sons.isEmpty()) {
for (Son s : r.sons) {
if (s.type == 1) {
removeNode(s);
}
}
for (Son s : r.sons) {
if (s.type == 1) {
r.sons.remove(s);
}
}
}
}
Be carefull with deleting element from an ArrayList when iterating the ArrayList because it can cause a ConcurrentModificationException.
I'm trying to implement a binary search tree class in Java with a method that can rebalance the tree if there's a difference in height. I'm trying to do it by first storing the value of the nodes in an List (an attribute of the class).
I then want to take the middle element of this list and assign this to the root of the tree. After this I take the left- and right part of the list and do the same thing recursively to the left- and right children of the root and so on.
My algorithm doesn't seem to work though and I don't understand what I'm doing wrong. I wonder if someone can take a look at my code and explain what the problem is? What I do is basically pass the ordered list of elements of the tree (an attribute of the class) and the root into the function below:
public void build(BinaryNode<E> n,List<E> list) {
int idx = (int)Math.floor(list.size()/2);
if(n!=null) {
n.element = list.get(idx);
} else if(n==null) {
n = new BinaryNode<E>(list.get(idx));
}
if(!list.subList(0,idx).isEmpty()) {
build(n.left,list.subList(0,idx));
}
if(!list.subList(idx+1,list.size()).isEmpty() ){
build(n.right,list.subList(idx+1,list.size()));
}
return;
}
Kind regards,
Java method calls are "call by value". This means changing a parameter (like n in your case) has no effect outside of the method.
Try to define your method like this
public BinaryNode<E> build(List<E> list) { ... }
Try investigating about AVL tree
Some useful links:
https://en.wikipedia.org/wiki/AVL_tree
https://www.geeksforgeeks.org/avl-tree-set-1-insertion/
I need to write a piece of code using the Kruskal algorithm, which in turn needs the Union-Find algorithm.
This includes the methods Make-Set(x), Find-Set(x) and Union(x, y).
I need to implement them using linked lists, but I am not sure of how to start with the Make-Set method.
The Make-Set Method should create a set and make the first element into a key (to compare sets). How exactly would I declare a key using linked lists?
Shortly put: How do I implement this pseudo code for linked lists in Java?
Make-Set(x)
x.p = x
x.rank = 0
Thanks for your help in advance!
I've heard this referred to in the past not as "Union-Find" but as a disjoint set. It isn't exactly a linked list, since the nodes do have a link, but they aren't necessarily linked up in a linear fashion. It's more like a tree where each node has a pointer to its parent and you can walk up the tree to the root.
I don't have much time right now, but here's a quick sketch of how I would implement it in Java:
class Disjoint {
Disjoint next;
Disjoint findSet() {
Disjoint head = this;
if (next != null) {
head = next.findSet();
next = head;
}
return head;
}
void union(Disjoint other) {
Disjoint us = this.findSet();
Disjoint them = other.findSet();
us.next = them;
}
}
Creating an instance is your Make-Set. What you call Find-Set I would call find head or find leader, maybe find identity. I've called it findSet here, though. It walks the chain to find the root of the tree. It also performs an optional operation; it snaps all the links on the way back out of the recursive call so that they all point directly at the root. This is an optimization to keep the chains short.
Finally, Union is implemented just by assigning one root's next pointer to point at the other set. I'm not sure what you intended with rank; if it's the size of the set, you can add a field for that and simply sum them when you union two sets. But you initialize it to 0 for a new set when I would expect it to be initialized to 1.
Two nodes a and b belong to the same set if a.findSet() == b.findSet(). If you need the nodes to carry some data, make the class generic and provide the data to the constructor, and add a getter:
class Disjoint<T> {
Disjoint<T> next;
T data;
public Disjoint(final T data) {
this.data = data;
}
public T getData() {
return data;
}
// rest of class identical except Disjoint replaced with Disjoint<T> everywhere
}
I've an ArrayList which contains my nodes. A node has a source, target and costs. Now I have to iterate over the whole ArrayList. That lasts for for over 1000 nodes a while. Therefore I tried to sort my List by source. But to find the corresponding pair in the List I tried the binary search. Unfortunately that works only if I want to compare either source or target. But I have to compare both to get the right pair. Is there another possibility to search an ArrayList efficient?
Unfortunately, no. ArrayLists are not made to be efficiently searched. They are used to store data and not search it. If you want to merely know if an item is contained, I would suggest you use HashSet as the lookup will have a time complexitiy of O(1) instead of O(n) for the ArrayList (assuming that you have implemented a functioning equals method for your objects).
If you want to do fast searches for objects, I recommend using an implementation of Dictionnary like HashMap. If you can afford the space requirement, you can have multiple maps, each with different keys to have a fast lookup of your object no matter what key you have to search for. Keep in mind that the lookup also requires implementing a correct equals method. Unfortunately, this requires that each key be unique which may not be a brilliant idea in your case.
However, you can use a HashMapto store, for each source, a List of nodes that have the keyed source as a source. You can do the same for cost and target. That way you can reduce the number of nodes you need to iterate over substantially. This should prove to be a good solution with a scarcely connected network.
private HashMap<Source, ArrayList<Node>> sourceMap = new HashMap<Source, ArrayList<Node>>();
private HashMap<Target, ArrayList<Node>> targetMap = new HashMap<Target, ArrayList<Node>>();
private HashMap<Cost, ArrayList<Node>> costMap = new HashMap<Cost, ArrayList<Node>>();
/** Look for a node with a given source */
for( Node node : sourceMap.get(keySource) )
{
/** Test the node for equality with a given node. Equals method below */
if(node.equals(nodeYouAreLookingFor) { return node; }
}
In order to be sure that your code will work, be sure to overwrite the equals method. I know I have said so already but this is a very common mistake.
#Override
public boolean equals(Object object)
{
if(object instanceof Node)
{
Node node = (Node) object;
if(source.equals(node.getSource() && target.equals(node.getTarget()))
{
return true;
}
} else {
return false;
}
}
If you don't, the test will simply compare references which may or may not be equal depending on how you handle your objects.
Edit: Just read what you base your equality upon. The equals method should be implemented in your node class. However, for it to work, you need to implement and override the equals method for the source and target too. That is, if they are objects. Be watchful though, if they are Nodes too, this may result in quite some tests spanning all of the network.
Update: Added code to reflect the purpose of the code in the comments.
ArrayList<Node> matchingNodes = sourceMap.get(desiredSourde).retainAll(targetMap.get(desiredTarget));
Now you have a list of all nodes that match the source and target criteria. Provided that you are willing to sacrifice a bit of memory, the lookup above will have a complexity of O(|sourceMap| * (|sourceMap|+|targetMap|)) [1]. While this is superior to just a linear lookup of all nodes, O(|allNodeList|), if your network is big enough, which with 1000 nodes I think it is, you could benefit much. If your network follows a naturally occurring network, then, as Albert-László Barabási has shown, it is likely scale-free. This means that splitting your network into lists of at least source and target will likely (I have no proof for this) result in a scale-free size distribution of these lists. Therefore, I believe the complexity of looking up source and target will be substantially reduced as |sourceMap| and |targetMap| should be substantially lower than |allNodeList|.
You'll need to combine the source and target into a single comparator, e.g.
compare(T o1, T o2) {
if(o1.source < o2.source) { return -1; }
else if(o1.source > o2.source) { return 1; }
// else o1.source == o2.source
else if(o1.target < o2.target) { return -1; }
else if(o1.target > o2.target) { return 1; }
else return 0;
}
You can use the .compareTo() method to compares your nodes.
You can create two ArrayLists. The first sorted by source, the second sorted by target.
Then you can search by source or target using binarySearch on the corresponding List.
You can make a helper class to store source-target pairs:
class SourceTarget {
public final Source source; // public fields are OK when they're final and immutable.
public final Target target; // you can use getters but I'm lazy
// (don't give this object setters. Map keys should ideally be immutable)
public SourceTarget( Source s, Target t ){
source = s;
target = t;
}
#Override
public boolean equals( Object other ){
// Implement in the obvious way (only equal when both source and target are equal
}
#Override
public int hashCode(){
// Implement consistently with equals
}
}
Then store your things in a HashMap<SourceTarget, List<Node>>, with each source-target pair mapped to the list of nodes that have exactly that source-target pair.
To retrieve just use
List<Node> results = map.get( new SourceTarget( node.source, node.target ) );
Alternatively to making a helper class, you can use the comparator in Zim-Zam's answer and a TreeMap<Node,List<Node>> with a representative Node object acting as the SourceTarget pair.
I'm working on a small UML editor project, in Java, that I started a couple of months ago. After a few weeks, I got a working copy for a UML class diagram editor.
But now, I'm redesigning it completely to support other types of diagrams, such a sequence, state, class, etc. This is done by implementing a graph construction framework (I'm greatly inspired by Cay Horstmann work on the subject with the Violet UML editor).
Redesign was going smoothly until one of my friends told me that I forgot to add a Do/Undo functionnality to the project, which, in my opinion, is vital.
Remembering object oriented design courses, I immediately thought of Memento and Command pattern.
Here's the deal. I have a abstract class, AbstractDiagram, that contains two ArrayLists : one for storing nodes (called Elements in my project) and the other for storing Edges (called Links in my projects). The diagram will probably keep a stack of commands that can be Undoed/Redoed. Pretty standard.
How can I execute these commands in a efficient way? Say, for example, that I want to move a node (the node will be an interface type named INode, and there will be concrete nodes derived from it (ClassNode, InterfaceNode, NoteNode, etc.)).
The position information is held as an attribute in the node, so by modying that attribute in the node itself, the state is changed. When the display will be refreshed, the node will have moved. This is the Memento part of the pattern (I think), with the difference that the object is the state itself.
Moreover, if I keep a clone of the original node (before it moved), I can get back to its old version. The same technique applies for the information contained in the node (the class or interface name, the text for a note node, the attributes name, and so on).
The thing is, how do I replace, in the diagram, the node with its clone upon undo/redo operation? If I clone the original object that is referenced by the diagram (being in the node list), the clone isn't reference in the diagram, and the only thing that points to is the Command itself! Shoud I include mechanisms in the diagram for finding a node according to an ID (for example) so I can replace, in the diagram, the node by its clone (and vice-versa) ? Is it up to the Memento and Command patterns to do that ? What about links? They should be movable too but I don't want to create a command just for links (and one just for nodes), and I should be able to modify the right list (nodes or links) according to the type of the object the command is referring to.
How would you proceed? In short, I am having trouble representing the state of an object in a command/memento pattern so that it can be efficiently recovered and the original object restored in the diagram list, and depending on the object type (node or link).
Thanks a lot!
Guillaume.
P.S.: if I'm not clear, tell me and I will clarify my message (as always!).
Edit
Here's my actual solution, that I started implementing before posting this question.
First, I have an AbstractCommand class defined as follow :
public abstract class AbstractCommand {
public boolean blnComplete;
public void setComplete(boolean complete) {
this.blnComplete = complete;
}
public boolean isComplete() {
return this.blnComplete;
}
public abstract void execute();
public abstract void unexecute();
}
Then, each type of command is implemented using a concrete derivation of AbstractCommand.
So I have a command to move an object :
public class MoveCommand extends AbstractCommand {
Moveable movingObject;
Point2D startPos;
Point2D endPos;
public MoveCommand(Point2D start) {
this.startPos = start;
}
public void execute() {
if(this.movingObject != null && this.endPos != null)
this.movingObject.moveTo(this.endPos);
}
public void unexecute() {
if(this.movingObject != null && this.startPos != null)
this.movingObject.moveTo(this.startPos);
}
public void setStart(Point2D start) {
this.startPos = start;
}
public void setEnd(Point2D end) {
this.endPos = end;
}
}
I also have a MoveRemoveCommand (to... move or remove an object/node). If I use the ID of instanceof method, I don't have to pass the diagram to the actual node or link so that it can remove itself from the diagram (which is a bad idea I think).
AbstractDiagram diagram;
Addable obj;
AddRemoveType type;
#SuppressWarnings("unused")
private AddRemoveCommand() {}
public AddRemoveCommand(AbstractDiagram diagram, Addable obj, AddRemoveType type) {
this.diagram = diagram;
this.obj = obj;
this.type = type;
}
public void execute() {
if(obj != null && diagram != null) {
switch(type) {
case ADD:
this.obj.addToDiagram(diagram);
break;
case REMOVE:
this.obj.removeFromDiagram(diagram);
break;
}
}
}
public void unexecute() {
if(obj != null && diagram != null) {
switch(type) {
case ADD:
this.obj.removeFromDiagram(diagram);
break;
case REMOVE:
this.obj.addToDiagram(diagram);
break;
}
}
}
Finally, I have a ModificationCommand which is used to modify the info of a node or link (class name, etc.). This may be merged in the future with the MoveCommand. This class is empty for now. I will probably do the ID thing with a mechanism to determine if the modified object is a node or an edge (via instanceof or a special denotion in the ID).
Is this is a good solution?
I think you just need to decompose your problem into smaller ones.
First problem:
Q: How to represent the steps in your app with the memento/command pattern?
First off, I have no idea exactly how your app works but hopefully you will see where I am going with this. Say I want to place a ClassNode on the diagram that with the following properties
{ width:100, height:50, position:(10,25), content:"Am I certain?", edge-connections:null}
That would be wrapped up as a command object. Say that goes to a DiagramController. Then the diagram controller's responsibility can be to record that command (push onto a stack would be my bet) and pass the command to a DiagramBuilder for example. The DiagramBuilder would actually be responsible for updating the display.
DiagramController
{
public DiagramController(diagramBuilder:DiagramBuilder)
{
this._diagramBuilder = diagramBuilder;
this._commandStack = new Stack();
}
public void Add(node:ConditionalNode)
{
this._commandStack.push(node);
this._diagramBuilder.Draw(node);
}
public void Undo()
{
var node = this._commandStack.pop();
this._diagramBuilderUndraw(node);
}
}
Some thing like that should do it and of course there will be plenty of details to sort out. By the way, the more properties your nodes have the more detailed Undraw is going to have to be.
Using an id to link the command in your stack to the element drawn might be a good idea. That might look like this:
DiagramController
{
public DiagramController(diagramBuilder:DiagramBuilder)
{
this._diagramBuilder = diagramBuilder;
this._commandStack = new Stack();
}
public void Add(node:ConditionalNode)
{
string graphicalRefId = this._diagramBuilder.Draw(node);
var nodePair = new KeyValuePair<string, ConditionalNode> (graphicalRefId, node);
this._commandStack.push(nodePair);
}
public void Undo()
{
var nodePair = this._commandStack.pop();
this._diagramBuilderUndraw(nodePair.Key);
}
}
At this point you don't absolutely have to have the object since you have the ID but it will be helpful should you decide to also implement redo functionality. A good way to generate the id for your nodes would be to implement a hashcode method for them except for the fact that you wouldn't be guaranteed not to duplicate your nodes in such a way that would cause the hash code to be identical.
The next part of the problem is within your DiagramBuilder because you're trying to figure out how the heck to deal with these commands. For that all I can say is to really just ensure you can create an inverse action for each type of component you can add. To handle the delinking you can look at the edge-connection property (links in your code I think) and notify each of the edge-connections that they are to disconnect from the specific node. I would assume that on disconnection they could redraw themselves appropriately.
To kinda summarize, I would recommend not keeping a reference to your nodes in the stack but instead just a kind of token that represents a given node's state at that point. This will allow you to represent the same node in your undo stack at multiple places without it referring to the same object.
Post if you've got Q's. This is a complex issue.
In my humble opinion, you're thinking it in a more complicated way than it really is. In order to revert to previous state, clone of whole node is not required at all. Rather each **Command class will have -
reference to the node it is acting upon,
memento object (having state variables just enough for the node to revert to)
execute() method
undo() method.
Since command classes have reference to the node, we do not need ID mechanism to refer to objects in the diagram.
In the example from your question, we want to move a node to a new position. For that, we have a NodePositionChangeCommand class.
public class NodePositionChangeCommand {
// This command will act upon this node
private Node node;
// Old state is stored here
private NodePositionMemento previousNodePosition;
NodePositionChangeCommand(Node node) {
this.node = node;
}
public void execute(NodePositionMemento newPosition) {
// Save current state in memento object previousNodePosition
// Act upon this.node
}
public void undo() {
// Update this.node object with values from this.previousNodePosition
}
}
What about links? They should be movable too but I don't want to create a command just for links (and one just for nodes).
I read in GoF book (in memento pattern discussion) that move of link with change in position of nodes are handled by some kind of constraint solver.