Running methods of objects within an ArrayList - java

I am creating an A Star search algorithm to solve a 8 puzzle board and I've got all the Board object classes listed within an ArrayList. My problem is I need to run methods within each of the Board objects to allow me to check if they have reached there goal, get board information and other functions similar to that.
Problem is I can't find a way after a few hours of internet searching that will solve this problem, I tried using an iterator to do the job which seems like the right direction but I couldn't get it to work but I don't have any experience with them.
Any help would be of great help.
public class Solve8Puzzle {
ArrayList startNode;
ArrayList nodes;
public Solve8Puzzle() {
startNode = new ArrayList();
nodes = new ArrayList();
}
public boolean checkGoalNodes() {
while( currently selected node has next ) {
run current node goal check
}
}
}

List<StartNode> startNode = new ArrayList<StartNode>();
.......................
for (StarNode node : starNodes) {
// do what you want with the node
}
Other possibility
for (Iterator<StarNode> it = starNodes.iterator(); it.hasNext(); ) {
StarNode node = it.next();
// do what you want with the node
}

Related

How to find the largest Count of Objects assosiated with the same Object

I have a Mentor class in which I have an ID for each mentor and an ArrayList of mentee IDs, like this:
public class Mentor {
int mentorId;
ArrayList<Integer> mentees = new ArrayList<>();
public Mentor(int mentorId, ArrayList<Integer> mentees) {
this.mentorId = mentorId;
this.mentees = mentees ;
}
}
The problem is that some mentees can be mentors too.
I would like to somehow get a count of all of the mentees associated to the top mentor as well as how many mentors are under the top mentor.
So, basically, if a mentor has a mentee, who is also a mentor, then this mentor's mentees are also associated to the top mentor.
So, my thinking was to loop through the mentee-list and see if any of the id's match an ID of Mentor. If true, Add this mentor's list of mentees to a list and loop again, but this will not work dynamically.
My main class looks something like this:
ArrayList<Mentor> mentors = new ArrayList<>();
ArrayList<Integer> mentees = new ArrayList<>();
ArrayList<Integer> mentees2 = new ArrayList<>();
mentees.add(2);
mentees.add(3);
mentees2.add(4);
mentees2.add(5);
//[1,{2,3}]
mentors.add(new Mentor(1, mentees));
//[2,{4,5}]
mentors.add(new Mentor(2, mentees2));
int mentorCount = 0;
int menteeCount = 0;
for (Mentor mentor : mentors) {
for (Integer mentee : mentees) {
mentorCount++;
if (mentee == mentor.mentorId){
mentorCount++;
//add each mentee to arraylist and start the process again, but is there an easier way to do this.
}
}
}
I was wondering if there is a way of solving this, maybe using streams?
I would recommend using good object oriented design, you shouldn't just use integer id's like that, because in this situation you could simply make an ArrayList of Person objects Where Mentees, and Mentors Inherit from Person. Then you can check if a Person is an instance of Mentee versus Mentor:
for (Person p : people) {
if (p instanceof Mentor)
{
// Mentor logic
}
if (p instanceof Mentee)
{
// Mentee Logic
}
}
Firstly, let's briefly recap the task.
You have a set of mentors, each mentor has a collection of mentees. Some of them might happen also to be mentors and so on.
Class design
From the perspective of class design, the solution is pretty simple: you need only one class to describe this relationship - Mentor. And each Mentor should hold a reference to a collection of Mentors (not integer ids).
In your domain model, as you described it, there's no substantial difference between a mentor and a mentee. Mentor points to other mentors - is a simplest way to model that. Mentee is just an edge case, a mentor which has an empty collection of mentors.
You don't need to include classes and features in your application that doesn't bring benefit.
Data structure
From the perspective of data structures, this problem can be described very well with an acyclic disjointed Graph.
Acyclic because if we consider the relationship between mentors when a mentor could indirectly point at themself (i.e. a mentor N has a mentee, with in tern points to another mentee that happens to be also a mentor of mentor N) the task becomes ambiguous. Therefore, I'm making an assumption that no one can be a mentor to himself.
I also depicted this data structure as disjointed because mentors in this model (as well as in real life) can form isolated groups, which in graph theory called connected components. That means that there could be several mentors with the same count of mentee, which happens to be the largest.
Depth first search
In order to find all the vertices (mentors) connected with a particular mentor, we have a classic traversal algorithm, which is called Depth first search (DFS). The core idea of DFS is to peek a single neighbor of the given vertex, then in turn peek one of its neighbors and so on until the hit the vertex that doesn't point to the other vertex (i.e. maximum depth is reached). And then it should be done with every other neighbors of the previously visited vertices.
There are two ways to implement DFS.
Iterative approach
For that, we need a stack. It will store all unvisited neighbors of the previously encountered vertexes. The last vertex from each list of neighbors in every branch will be explored first because it will be placed on the top of the stack. Then it will get removed from the stack and it's neighbors will be placed on the stack. This process repeats in a loop until the stack contains at least one element.
The most performant choice of collection for the stack is ArrayDeque.
Because this approach require continuous modification of the stack by adding and removing vertices, it isn't suitable to be implemented with Stream IPA.
Recursive approach
The overall principle is the same as described above, but we don't need to provide a stack explosively. The call stack of the JVM will be utilized for that purpose.
With this approach, there's also some room to apply streams. For that reason, I've chosen the recursive implementation. Also, its code is probably a bit easier to understand. But keep in mind that recursion has certain limitations, especially in Java, and not suitable for processing a large set of data.
Recursion
A quick recap on recursion.
Every recursive implementation consists of two parts:
Base case - that represents a simple edge-case for which the outcome is known in advance. For this task, the base case is the given vertex has no neighbors. That means menteesCount of this vertex needs to be set to 0 because it has no mentee. And the return value for the base case is 1 because this vertex, in turn, is a valid mentee of another vertex that holds a reference to it.
Recursive case - a part of a solution where recursive calls a made and where the main logic resides.
The recursive case could be implemented using streams and entails recursive invocation of the for every neighbor of the given vertex. Each of these values will contribute to the menteesCount of the given vertex.
The value returned by the method will be menteesCount + 1 because for the vertex which triggered this method call, the given vertex will be a mentee as well as its mentees.
Implementation
Class mentor basically serves as a vertex of the graph. Each vertex has a unique id and collection of adjacent vertexes.
Also, in order to reuse values obtained by performing DFS I've added a field menteesCount which is initially initialized to -1 in order to distinguish between vertices that has no adjacent vertices (i.e. menteesCount has to be 0) and vertices which value wasn't calculated. Every value will be established only ones and then reused (another approach will be to utilize a map for that purpose).
Method getTopMentors() iterates over the collection of vertices and invokes DFS for every vertex which value wasn't calculated yet. This method returns a list of mentors with the highest number of associated mentees
Method addMentor() that takes a vertex id, and id of its neighbors (if any) was added in order to interact with the graph in a convenient way.
Map mentorById contains every vertex that was added in the graph and, as its name suggests, allows retrieving it based on the vertex id.
public class MentorGraph {
private Map<Integer, Mentor> mentorById = new HashMap<>();
public void addMentor(int mentorId, int... menteeIds) {
Mentor mentor = mentorById.computeIfAbsent(mentorId, Mentor::new);
for (int menteeId: menteeIds) {
mentor.addMentee(mentorById.computeIfAbsent(menteeId, Mentor::new));
}
}
public List<Mentor> getTopMentors() {
List<Mentor> topMentors = new ArrayList<>();
for (Mentor mentor: mentorById.values()) {
if (mentor.getCount() != -1) continue;
performDFS(mentor);
if (topMentors.isEmpty() || mentor.getCount() == topMentors.get(0).getCount()) {
topMentors.add(mentor);
} else if (mentor.getCount() > topMentors.get(0).getCount()) {
topMentors.clear();
topMentors.add(mentor);
}
}
return topMentors;
}
private int performDFS(Mentor mentor) {
if (mentor.getCount() == -1 && mentor.getMentees().isEmpty()) { // base case
mentor.setCount(0);
return 1;
}
int menteeCount = // recursive case
mentor.getMentees().stream()
.mapToInt(m -> m.getCount() == -1 ? performDFS(m) : m.getCount() + 1)
.sum();
mentor.setCount(menteeCount);
return menteeCount + 1;
}
public static class Mentor {
private int id;
private Set<Mentor> mentees = new HashSet<>();
private int menteesCount = -1;
public Mentor(int id) {
this.id = id;
}
public boolean addMentee(Mentor mentee) {
return mentees.add(mentee);
}
// getters, setter for menteesCount, equeals/hashCode
}
}
An example of the graph used as a demo.
main() - the code models the graph shown above
public static void main(String[] args) {
MentorGraph graph = new MentorGraph();
graph.addMentor(1, 3, 4);
graph.addMentor(2, 5, 6, 7);
graph.addMentor(3, 8, 9);
graph.addMentor(4, 10);
graph.addMentor(5, 11, 12);
graph.addMentor(6);
graph.addMentor(7, 13, 14);
graph.addMentor(8);
graph.addMentor(9, 16, 17, 18);
graph.addMentor(10);
graph.addMentor(11, 18);
graph.addMentor(12);
graph.addMentor(13);
graph.addMentor(14, 19, 20);
graph.addMentor(15);
graph.addMentor(16, 21, 22);
graph.addMentor(17);
graph.addMentor(18);
graph.addMentor(19);
graph.addMentor(20);
graph.addMentor(21);
graph.addMentor(22);
graph.getTopMentors()
.forEach(m -> System.out.printf("mentorId: %d\tmentees: %d\n", m.getId(), m.getCount()));
}
Output
mentorId: 1 mentees: 10
mentorId: 2 mentees: 10
Use Person and Mentor and Mentee subclasses as suggested by acornTime, define mentees as a list of Person and the information you want becomes simple to get:
import java.util.*;
import java.util.stream.Stream;
public class Main{
public static void main(String[] args) {
ArrayList<Person> mentees = new ArrayList<>();
mentees.add(new Mentee(11));
mentees.add(new Mentee(12));
mentees.add(new Mentor(2, new ArrayList<>()));
mentees.add(new Mentee(13));
mentees.add(new Mentee(14));
mentees.add(new Mentor(3, new ArrayList<>()));
mentees.add(new Mentor(4, new ArrayList<>()));
mentees.add(new Mentor(5, new ArrayList<>()));
Mentor mentor = new Mentor(1, mentees);
System.out.println(mentor.menteesCount());
System.out.println(mentor.mentorsInMentees().count());
}
}
interface Person {
int getId();
}
class Mentor implements Person{
private final int mentorId;
private List<Person> mentees = new ArrayList<>();
public Mentor(int id, ArrayList<Person> mentees) {
mentorId = id;
this.mentees = mentees ;
}
#Override
public int getId() {
return mentorId;
}
public List<Person> getMentees() {
return mentees;
}
public int menteesCount() {
return mentees.size();
}
public Stream<Person> mentorsInMentees(){
return mentees.stream().filter(m -> (m instanceof Mentor));
}
}
class Mentee implements Person{
private final int menteeId;
public Mentee(int id) {
menteeId = id;
}
#Override
public int getId() {
return menteeId;
}
}
Test it online here
You should do something like a depth-first or breadth-first search (*):
Maintain a Set<Integer> containing all the people you have already seen.
Maintain a queue of some kind (e.g. an ArrayDeque), of people you are going to check.
Put the first person (or any number of people, actually) into this queue.
Then, while the queue is not empty:
Take the next person in the queue
If you've already seen them, go to the next item in the queue
If you've not already seen them, put the person into the seen set; add all of their mentees into the queue
That's it. The number of people at the end is the size of the seen set.
(*) Whether you do depth-first or breadth-first search depends on which end of the queue you add mentees to: adding them to the same end that you remove them from results in depth-first search; adding them to the other end results in breadth-first search. If you don't care which, choose either.

Why does node selection not work properly after TreeModel reload?

I have a Swing application that uses a JTree. I want some of the nodes of the tree to be hidden, so I have implemented two DefaultTreeModels, one with every node and a filtered one with only the ones that should be displayed. The latter is set as the actual model.
At some points I must change the filtered nodes, and when I do, the items in the tree update properly, but their behavior is wrong. Nodes do not get highlighted when they are selected (even though they are indeed selected) and the user can no longer double-click to expand a node, they must click the little '+' button.
Below is a generalization of my code, two methods from my custom class that extends JTree.
updateFilter gets called when the filter needs to be updated.
populateFilteredNode recursively populates the root node of my filtered model. For simplicity, filteredRoot is a class member variable (of type DefaultMutableTreeNode) and is the root of the filtered model. fullModel and filteredModel are of type DefaultTreeModel
public void updateFilter() {
// Get current expansion state
ArrayList<Integer> expansionState = getExpansionState();
DefaultMutableTreeNode fullModelRoot = fullModel.getRoot();
// Remove existing nodes in the filtered model
while(filteredRoot.getChildCount() > 0) {
filteredModel.removeNodeFromParent(filteredRoot.getFirstChild());
}
populateFilteredNode(fullModelRoot, filteredRoot);
// Repaint tree and restore expansion state
repaint();
setExpansionState(expansionState);
}
private void populateFilteredNode(DefaultMutableTreeNode fullNode, DefaultMutableTreeNode filteredNode) {
int index = 0;
for(int n = 0; n < fullNode.getChildCount(); n++) {
DefaultMutableTreeNode fullChildNode = fullNode.getChildAt(n);
// Show the item and its children if one of many cases is true
if(shouldShowItem(fullChildNode.getItem())) {
DefaultMutableTreeNode filteredChildNode = fullChildNode.clone();
filteredModel.insertNodeInto(filteredChildNode, filteredNode, index++);
populateFilteredNode(fullChildNode, filteredChildNode);
}
}
}
If anyone has a similar experience or knows why the selected node will not appear highlighted, please let me know. Or if there is a better way to accomplish filtering. Or if more code would help provide an answer.
I found something that works for my case, although it's quick and dirty and I don't necessarily understand why it works. This 12-year-old post on Code Ranch somehow got me headed in the right direction. I'm just posting it here in case anyone has a similar problem and it might be of help.
I save the selection path before making any changes to the table model, and then call this new function findNewSelectionPath after the changes were made. Below is a generalized version of the function (I use several custom classes so I did my best to make it look generically usable).
private TreePath findNewSelectionPath(TreePath oldSelectionPath) {
TreePath newSelectionPath = null;
if(oldSelectionPath != null) {
Object[] oldPathComponents = oldSelectionPath.getPath();
Object[] newPathComponents = new Object[oldPathComponents.length];
DefaultMutableTreeNode node = (DefaultMutableTreeNode) filteredModel.getRoot();
// Set the root
if(oldPathComponents[0].equals(node)) {
newPathComponents[0] = node;
}
// Set the rest of the path components
for(int n = 1; n < oldPathComponents.length; n++) {
for(int k = 0; k < node.getChildCount(); k++) {
if(oldPathComponents[n].equals(node.getChildAt(k))) {
newPathComponents[n] = node.getChildAt(k);
node = node.getChildAt(k);
break;
}
}
}
// Make sure that the last path component exists
if(newPathComponents[newPathComponents.length - 1] != null) {
newSelectionPath = new TreePath(newPathComponents);
}
}
return newSelectionPath;
}

Dynamically add nodes in a JTree

I have data like this (has other data like percentage, but is not important now) in a List that can vary:
1
1.1
1.1.1
1.1.2
1.2
2
2.1
2.2
How i easily work with the levels to build a proper JTree for any given levels?
Can be done with recursion?
What the best way?
Thank you so much.
Yes, it can easily be done using recursion. The idea is to check if there is already a node in the tree under which the new node can be fallen. For example, if the new node is "1.1.2", then we have to check if the node "1.1" exists in the tree. I wrote a very simple code and it is working, I am going yo cope here. If you don't understand something then just let me know, I will explain you. The function to check if the tree has the node of a particular string is given below.
public DefaultMutableTreeNode findparentnode(String s,DefaultMutableTreeNode root){
DefaultMutableTreeNode parent=null;
for (int i=0;i<root.getChildCount();i++) {
if(s.equalsIgnoreCase(((DefaultMutableTreeNode)root.getChildAt(i)).toString())){
parent = (DefaultMutableTreeNode)root.getChildAt(i);
break;
}
else
parent=findparentnode(s, (DefaultMutableTreeNode)root.getChildAt(i));
}
return parent;
}
Now, we will check every string in the list. We will skip the last part of the string, and will pass the remaining value to the function. To check the string, the code is given below
for(String s:list){
String[] substr=s.split("\\.");
String parent=substr[0];
for(int i=1;i<substr.length-1;i++){
parent=parent+ "." + substr[i];
}
DefaultMutableTreeNode node=null;
node=findparentnode(parent,root);
if(node==null)
root.add(new DefaultMutableTreeNode(s));
else
node.add(new DefaultMutableTreeNode(s));
}

BFS shortest path only using adjacency matrix?

I'm trying to implement Ford-Fulkerson/Edmonds-Karp only using adjacency matrix'. The only thing I'm not able to program is the function to calculate the shortest path, using BFS. The function to see if a shortest path actually exists is fine, but is it possible to also get the shortest path? Or is the only way to get the shortest path with BFS to use some kind of parent pointers, and traverse backwards to get the path?
Here is my code for see if path exists:
public static boolean existsPathFromSourceToSinkInGf(int Gf[][])
{
LinkedList<Integer> queue = new LinkedList<Integer>();
queue.add(0);
while (!queue.isEmpty())
{
int v = queue.remove();
if (v == sink) return true;
for (int i = 0; i < 5; i++)
{
if (Gf[v][i] != 0)
{
if (!queue.contains((Integer)i))
{
queue.add((Integer)i);
}
}
}
}
return false;
}
The common way to do it would indeed be to maintain parent pointers each time you settle a node and to go backwards once you found your path.
You could also keep track of paths explicitly in your queue. Instead of using just an integer for your linkedlist, you could create your own class consisting of the integer and a string with something like "node 1-> node 3->...". It's less commonly used because of the overhead of the class and the paths, but it avoids having to keep the parent pointers on their own and having to traverse them in the end.
On a side note 2 remarks on your code:
Why does it run for i=0..5?
You check if (!queue.contains((Integer)i)) so you don't put a vertex on your queue that's already on it. You should also avoid putting vertices on that have already been removed from the list (try maintaining a set of visited nodes).

ArrayList<String> NullPointerException

Am trying to solve a labyrinth by DFS, using adj List to represent the vertices and edges of the graph. In total there are 12 nodes (3 rows[A,B,C] * 4 cols[0,..,3]). My program starts by saving all the vertex labels (A0,..C3), so far so good, then checks the adjacent nodes, also no problems, if movement is possible, it proceeds to create the edge, here its where al goes wrong.
adjList[i].add(vList[j].label);
I used the debugger and found that vList[j].label is not null it contains a correct string (ie. "B1"). The only variables which show null are in adjList[i], which leads me to believe i have implemented it wrongly. this is how i did it.
public class GraphList {
private ArrayList<String>[] adjList;
...
public GraphList(int vertexcount) {
adjList = (ArrayList<String>[]) new ArrayList[vertexCount];
...
}
...
public void addEdge(int i, int j) {
adjList[i].add(vList[j].label); //NULLPOINTEREXCEPTION HERE
}
...
}
I will really appreaciate if anyone can point me on the right track regrading to what its going wrong... Thanks!
You've created the array, but you still need to go through and create the ArrayList objects. As it's written, adjList[i] returns null because nothing has been assigned to it yet.
I see that you created the container but are you sure you populated the list with elements?
Why don't you add assert((adjList[i] != null) && (adjList[j] != null)) to addEdge just to be sure either of them are not null. Run with java -ea ...

Categories

Resources