How to implement Union-Find using linked lists? - java

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
}

Related

Balance a binary search tree

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/

Determine average of all Node values within a Tree Structure

Given this interface...
public static interface Node
{
int getValue();
List<Node> getChildren();
}
Implement the following method to return the average of all node values in the tree.
public static double getAverage(Node root)
{
}
I'm having an extremely hard time with this practice problem and have a few questions.
I assume this is best completed using recursion, is that correct?
Is this possible without a helper method or global variables?
Is this possible without having to traverse the tree twice? (Once for node sum, once for node count)
Additionally, if someone could provide some psuedo-code, I'd greatly appreciate it.
You can use recursion, but it is possible to solve this problem without it, too. What you need is just a depth-first search. You can implement it iteratively using a stack.
Yes, it is possible. A version with a stack does not require any additional methods.
Yes, it is possible. You can just compute both of these values during one traversal.
Here is a pseudo code of a non-recursive implementation:
valuesSum = 0
nodesCount = 0
stack = new Stack
stack.add(root)
while (!stack.isEmpty())
Node v = stack.poll()
nodesCount++
valuesSum += v.getValue()
for (child : v.getChildren())
stack.add(child)
return valuesSum / nodesCount

Efficient search in datastructure ArrayList

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.

Best way to code large if-else-statements of Objects in Java?

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!

How to calculate leaf nodes in a nested data structure in Java?

I have a structure like this of what we'll call Box objects.
Box--+---Box----Box
|
+---Box-+--Box
|
+--Box
|
+--Box
I'm trying to ask the top box object for a list of the leaf node Boxes, which is the 3 box objects in this case.
The box object has a list of its children in an instance variable of type Vector called children.
The number of children can be unlimited.
I've been trying to write a single recursive method to do this, but without success.
One way to do this would be a recursive traversal of the structure. The idea is as follows:
There are no leaf nodes in the empty tree.
In a tree with root r with no children, then r is the only leaf.
In a tree with root r, if r has children, then the leaves of the tree are the leaves of those children.
You could write a recursive traversal with this sort of pseudocode:
void findChildren (Box current, List<Box> found) {
/* Case 1. */
if (current == null) return;
/* Case 2. */
if (current.children.isEmpty()) {
found.add(current);
return;
}
/* Case 3. */
for (Box child: current.children)
findChildren(child, found);
}
Hope this helps!
it has been awhile since I've done Java, so I'm sure this code has plenty of syntax errors, and I hope no one marks me down for it; just trying to give you some algorithm ideas. Hopefully it helps:
vector<Box> getLeaves(Box root)
{
vector<Box> tempList; //vector to hold nodes to check
vector<Box> tempList2; //vector to hold nodes' children
vector<Box> leafList;
bool goflag = true;
tempList.add(root);
while(goflag){
for(int i = 0; i < tempList.size; i++){
if(tempList[i].children.isEmpty()){
leafList.add(tempList[i]);
}
else{
//add all children to tempList2
for(int c = 0; c < tempList[i].children.size; c++){
tempList2.add(tempList[i].children[c])
}
}
if(tempList2.isEmpty()) //no more childs
goflag = false;
else
tempList = tempList2;
tempList2.clear();
}
return leafList;
}
It goes through all the nodes, adding children to the next list to check, and adding leaves to a list to be returned.
There are several ways to write such a function. Here's one approach to work through.
Define a helper function that takes a node and a mutable queue holding nodes.
In that helper function, check if the supplied node's children are empty. If so, add that node to the queue, and return.
If instead the supplied node has any children, call the helper function once for each of the children, passing the child and the same queue reference through.
At the top level, create an empty queue, and call the helper function, passing in the root node and the queue.
When the helper function returns, the queue contains all the leaves in the order they were discovered.
A different approach uses the same depth-first traversal, but the function would return the list of leaves it discovered. These lists would need to be combined for each set of siblings explored, working back up the tree as each function call returns.

Categories