Avoiding duplicate entries in an array - java

I am writing a method that adds Vertex objects to an array. I need to check if the vertex I am adding already exists in the array. I am not sure where I am going wrong. Here is my method:
public void addVertex(Vertex v) {
if (activeVertices >= maxVertices) {
System.out.println("Graph full");
return;
}
for(int i=1; i<vertices.length; i++) {
if(vertices[i] != vertices[i-1]){
vertices[activeVertices] = v; // add vertex to list of vertices
v.graphIndex = activeVertices; // record index of vertex in graph
activeVertices++; // increment vertex count
}
}
}
Vertex class:
public class Vertex {
public String name;
public int graphIndex; // index of adjacency matrix position of node in graph
public Vertex (String s) {
name = s;
graphIndex = -1; // invalid position by default
}
public String toString() {
return name;
}
}
The class that contains the addVertex() method:
public class Graph {
private int maxVertices;
private Vertex[] vertices; // array of nodes
private int[][] edges; // adjacency matrix
int activeVertices;
public Graph(int maxSize) {
maxVertices = maxSize;
vertices = new Vertex[maxVertices];
activeVertices = 0;
}
public void addVertex(Vertex v) {
if (activeVertices >= maxVertices) {
System.out.println("Graph full");
return;
}
for(int i=1; i<vertices.length; i++) {
if(vertices[i] != vertices[i-1]){
vertices[activeVertices] = v; // add vertex to list of vertices
v.graphIndex = activeVertices; // record index of vertex in graph
activeVertices++; // increment vertex count
}
}
}
public void addEdge(Vertex v1, Vertex v2, int w) {
edges[v1.graphIndex][v2.graphIndex] = w;
edges[v2.graphIndex][v1.graphIndex] = w;
}
public Graph minimumSpanningTree() {
Graph mst = new Graph(maxVertices); // create new graph
int[] set = new int[activeVertices];
for (int i=0; i<activeVertices; i++) { // copy nodes to graph
mst.addVertex(vertices[i]);
set[i]=i; // assign each node to its own set
}
PriorityQueue q = new PriorityQueue(maxVertices*maxVertices); // create priority queue
for (int i=0; i<activeVertices; i++) { // copy edges to queue
for (int j=0; j<activeVertices; j++) {
if (edges[i][j]!=0) {
q.enqueue(new Edge(vertices[i],vertices[j],edges[i][j]));
}
}
}
while (!q.isEmpty()) { // iterate over all edges in priority order
Edge e = q.dequeue(); // consider next edge
if (set[e.source.graphIndex]!=set[e.destination.graphIndex]) { // skip edges not connecting different sets
mst.addEdge(e.source, e.destination, e.weight); // add edge to MST
System.out.println("adding "+e);
int setToMerge=set[e.destination.graphIndex]; // rename nodes from "other" set
for (int i=0; i<activeVertices; i++) {
if (set[i]==setToMerge) { // find nodes from "other" set
set[i]=set[e.source.graphIndex]; // reassign nodes
}
}
}
}
return mst;
}
public void print() {
System.out.format(" ");
for (int i=0; i<activeVertices; i++) {
System.out.format("%3s ", vertices[i].name);
}
System.out.format("\n");
for (int j=0; j<activeVertices; j++) {
System.out.format("%3s ", vertices[j].name);
for (int i=0; i<activeVertices; i++) {
System.out.format("%3d ", edges[i][j]);
}
System.out.format("\n");
}
}
}

First, you should be using equals instead of ==. You should write a proper equals method in your Vertex class (use Google to find plenty of tutorials on how to do this).
For example, if you wanted two Vertex objects to be considered equal only when their names were the same, then your equals method would look something like this:
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj instanceof Vertex) {
Vertex otherVertex = (Vertex) obj;
if(this.name.equals(otherVertex.name)) {
return true;
}
}
return false;
}
If you wanted to compare graphIndex as well, then you would need to check that in the equals method as well.
Assuming you have a proper equals method in your Vertex class, the simplest solution would be to use the ArrayUtils.contains method, from the Apache Commons library (Apache Commons has TONS of useful methods, which can save you a lot of time. You should check it out). This method takes in an array and an Object, and checks if the array contains the object or not.

You're always checking vertices[1] against vertices[0] and adding based on the result. You're not checking for v, and not actually looking in the whole array.
If an == check (identity, not equivalence) is really what you want, then:
public void addVertex(Vertex v) {
if (activeVertices >= maxVertices) {
System.out.println("Graph full");
return;
}
for(int i=0; i<vertices.length; i++) {
if(vertices[i] == v){
// Already have it
return;
}
}
vertices[activeVertices] = v; // add vertex to list of vertices
v.graphIndex = activeVertices; // record index of vertex in graph
activeVertices++; // increment vertex count
}
If you want equivalence instead, replace
if(vertices[i] == v){
with
if(v.equals(vertices[i])){
Side note: Based on your having an activeVertices variable, I suspect you may be better off with ArrayList<Vertex> rather than Vertex[]. That would also give you the contains method (which uses equals), which may be able to replace your loop (if you want an equals, not ==, check).

Whenever you write a value class, i.e. a class that represents a value or quantity of something, you should always override the following methods for your class:
equals(Object o);
hashCode();
Not all classes are value classes. Some represent system resources and others represent actions or processes, but whenever a class is written as an abstraction for a collection of data you should always consider writing the above methods.
The reason is straightforward. Whereas Java primitives have only value, Java reference types (which include all the instances of classes you write yourself) have both value and location. This confers the properties of both equality and identity to reference types and they are very different.
By default, the equals() method in the Object class performs an identity comparison and NOT an equality comparison ... and it's a good thing too. Because any subclass of Object can have vastly different notions of "how instances can be considered equal" there is no straightforward way that Object could have a superclass method that would test equality for any arbitrary Java object. In contrast, it is always straightforward to test for identity. If any two references indicate the same location, then their objects are identical. This exemplifies the different notions of equality and identity.
You need to be able to test whether your Vertex instances are equal and not whether they are identical. For this reason, you really do need to override the equals(Object o) method. If you also override hashCode() (which you should), then you may be able to store your vertices in a HashSet, which would guarantee that no two vertices would be equal.

Related

Bfs game Map implementation in java

I'm trying to implement a bfs algorithm in Java,but it doesn't work as it should be.
I've made a game map comprised of HexTile objects(custom objects,similar to matrix elements). Each HexTile includes one adjacency list containing references to the elements that it's connected to, one function that returns those elements and one function that computes the distance between two HexTiles. The bfs algorithm is excecuted in another class called unit(units are placed in HexTiles) and finds every unit available in a given range from the room(currentTile). It then creates an ArrayList with the given units.
class HexTile {
static final int MAX_NEIGHBOURS = 6;
private HexTile[] neighbours;
public HexTile[] getNeighbours() {
return this.neighbours;
}
public double distanceFromTarget(HexTile target) {
double distance = Math.sqrt(Math.pow((this.getRow() - target.getRow()), 2) + Math.pow((this.getCol() - target.getCol()), 2));
return distance;
}
}
class Unit {
private ArrayList<Unit> unitsWithinRange = new ArrayList<Unit>();
private void findUnitsWithinRange(HexTile currentTile, int attackRange) {
Queue<HexTile> queue = new LinkedList<>();
ArrayList<HexTile> visited = new ArrayList<HexTile>();
queue.add(currentTile);
visited.add(currentTile);
while (!queue.isEmpty()) {
HexTile aux = queue.poll();
for (HexTile auxNeigh : aux.getNeighbours()) {
if (auxNeigh != null && (!visited.contains(auxNeigh))) {
visited.add(auxNeigh);
queue.add(auxNeigh);
}
}
if (aux != null && (currentTile.distanceFromTarget(aux) <= attackRange)) {
Unit auxUnit = aux.getUnitOnTile();
this.unitsWithinRange.add(auxUnit);
}
}
queue.clear();
visited.clear();
}
}
What happens whenever findUnitsWithinRange is excecuted is that it return a list of units,but the units that are in range 1 are not included(direct neighbours to root).Sometimes the program crashes,because units need to be able to know if there are any nearby units,to excecute some other functions.Any advice would be appreciated!

I have a problem with ArrayList as a value of Hashtable

I have created these two data structures
private Vector<Hapsira> places;
private Hashtable<Klienti,ArrayList<Hapsira>> booking;
public void addPlace(Place h) throws RezervimiException{
if(h == null){
throw new RezervimiException("null");
}
for(int i=0;i<places.size();i++){
if(places.get(i).equals(h)){
throw new RezervimiException("exits");
}
}
places.add(h);
}
public boolean hasBooking(){
return places.size() > 0;
}
public Hapsira bookPlace(Client k) throws RezervimiException{
Place h = null;
if(hasBooking()){
h = places.remove(0);
}
return h;
}
In this method i want to test if my hashtable contains the same clients if that is true then you add the place to arraylist value,if that is not true you add the list to hashmap.
But iam doing wrong when i add places , the size of booking hashtable is always 1
public void registerPlace(Client k,Place h) throws RezervimiException{
ArrayList<Place> list = new ArrayList<>();
if(booking.containsKey(k)){
list.add(h);
} else {
booking.put(k, list);
}
}
" the size of booking hashtable is always 1 "
This means the put method puts the value using the same key over and over in your registerPlace method.
2 things to check.
Whether you are passing the same Client k instance in your registerPlace method over different invocations. Print the value of k or debug & inspect the variable to check this.
Also when you use data structures which relies on keys, you should make sure it follows this very important contract. (if you have not already done so).
You can also read more about using keys in a Map here

Fundamental misunderstanding of objects and attributes in Java

I'm sitting on an assignment for university and I'm at a point, where I fear I haven't really understood something fundamental in the concecpt of Java or OOP altogether. I'll try to make it as short as possible (maybe it's sufficient to just look at the 3rd code segment, but I just wanted to make sure, I included enough detail). I am to write a little employee management. One class within this project is the employeeManagement itself and this class should possess a method for sorting employees by first letter via bubblesort.
I have written 3 classes for this: The first one is "Employee", which contains a name and an ID (a running number) , getter and setter methods and one method for checking whether the first letter of one employee is smaller (lower in the alphabet) than the other. It looks like this:
static boolean isSmaller(Employee source, Employee target) {
char[] sourceArray = new char[source.name.length()];
char[] targetArray = new char[target.name.length()];
sourceArray = source.name.toCharArray();
targetArray = target.name.toCharArray();
if(sourceArray[0] < targetArray[0])
return true;
else
return false;
}
I tested it and it seems to work for my case. Now there's another class called EmployeeList and it manages the employees via an array of employees ("Employee" objects). The size of this array is determined via constructor. My code looks like this:
public class EmployeeList {
/*attributes*/
private int size;
private Employee[] employeeArray;
/* constructor */
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
}
/* methods */
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/* adds employee to end of the list. Returns false, if list is too small */
boolean add(Employee m) {
int id = m.getID();
if (id > employeeArray.length) {
return false;
} else {
employeeArray[id] = m;
return true;
}
}
/* returns employee at certain position */
Employee get(int index) {
return employeeArray[index];
}
/* Sets employee at certain position. Returns null, if position doesn't exist. Else returns old value. */
Employee set(int index, Employee m) {
if (employeeArray[index] == null) {
return null;
} else {
Employee before = employeeArray[index];
employeeArray[index] = m;
return before;
}
}
Now comes my real problem: In a third class called "employeeManagement" I am supposed to implement the sorting algorithm. The class looks like this:
public class EmployeeManagement {
private EmployeeList ml = new EmployeeList(3);
public boolean addEmployee(Employee e) {
return ml.add(e);
}
public void sortEmployee() {
System.out.println(ml.getSize()); // I wrote this for debugging, exactly here lies my problem
for (int n = ml.getSize(); n > 1; n--) {
for (int i = 0; i < n - 1; i++) {
if (Employee.isSmaller(ml.get(i), ml.get(i + 1)) == false) {
Employee old = ml.set(i, ml.get(i + 1));
ml.set(i+1, old);
}
}
}
}
The "println" before my comment returns "0" in console... I am expecting "3" as this is the size I gave the "EmployeeList" as parameter of the constructor within my "EmployeeManagement" class. Where is my mistake ? And how can I access the size of the object I created in the "EmployeeManagement" class (the "3") ? I'm really looking forward to your answers!
Thanks,
Phreneticus
You are not storing size in your constructor. Something like,
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
this.size = size; // <-- add this.
}
Also, setSize isn't going to automatically copy (and grow) the array. You will need to copy the array, because Java arrays have a fixed length. Finally, you don't really need size here since employeeArray has a length.
The size variable you are calling is the class field. If you take a quick look at your code, the getter is getting the field (which is initialized as zero when created). The size you are using it. The good way of doing it would be to get the size of the array in the getter like this:
public int getSize() {
return employeeArray.length;
}
This would return the size of the array in the object.

Adding elements to array in alphebetical order

I'm writing a program which adds telephone entries into a staff phone directory, I want to add the elements to the array in alphabetical order (using surnames) rather than adding the elements then calling Arrays.sort every time a new entry is added, as that would be less efficient. Here is some code I have so far, I'm not sure how to compare each element in the array with the following one and so forth.
public class ArrayDirectory implements Directory {
Entry [] directory = new Entry [50];
#Override
public void addEntry(String initials, String surname, int extension) {
//Entries are added here in alphabetical order
}
Here is my Entry class -
public class Entry {
private String initals,surname;
private int extention;
public Entry(String initals, String surname, int extention){
this.initals = initals;
this.surname = surname;
this.extention = extention;
}
public String getInitals(){
return initals;
}
public String getSurname(){
return surname;
}
public int getExtention(){
return extention;
}
}
Any suggestions, do I override compareTo? Thanks
edit - should have noted I have been asked to use an array. Sorry for the confusion.
Edit 2: updated my addEntry method and overriden compareTo in Entry -
public void addEntry(String initials, String surname, int extension) {
for (int i = 0; i < directory.length; i++) {
if (directory[i] != null) {
int y = directory[i].getSurname().compareTo(surname);
if (y == 1) {
int position = i;
break;
}
} else if (directory[i] == null) {
int position = i;
break;
}
}
}
And my compareTo method -
public int compareTo(Entry other) {
return this.surname.compareTo(other.getSurname());
}
I'm not sure how to shift the elements in the array to the right after I have found the correct position? Thank you for all of you help.
If you dont have to use an array then your using the wrong data structure.
No matter what path you need to implement Comparable:
public class Entry implements Comparable<Entry>{
..
#Override
public int compareTo(Entry other) {
// TODO Auto-generated method stub
return this.surname.compareTo(other.getSurname());
}
..
Consider using a SortedSet:
Set<Entry> map = new TreeSet<Entry>();
map.add(new Entry("JEH", "Hamlet", 123));
map.add(new Entry("AAC", "Adams", 123));
map.add(new Entry("FAM", "Monti", 321));
That will print in the desired order. If you must use an Array then you need to sort it upon insert.
You could make Entry comparable and implement the compareTo in it. But you don't really have to in this case because String is already comparable.
Since this is a homework, I think it will be best to just give you some suggestions on how to proceed, instead of handing you the code -
In your method you do not need to sort the array, you just need to insert it at the correct location in the array.
loop through the array starting at the first index
as you pass through each element in the array, you will have to check following two conditions
is the element null
is the surname of current element greater than surname-argument to the method
as soon as you find the element that satisfies any of the above conditions, record the index and break the loop
then, starting at that index shift the rest of elements to the right
and finally create a new instance of Entry for the provided arguments and set it at that index
Note: This doesn't take care of the situation where you are out of the space in the array.
Update:
I think you mixed up my answer and #David Wallace's answer. It wasn't my suggestion to implement compareTo. Also, it's great that you at least gave it a try and came back.
int position = -1; //declare the position outside (if declared inside, it's not visible outside the loop)
for (int i = 0; i < directory.length; i++) {
// position = i; just assign value of i inside the loop
}
//use the position after the loop
int j = position; // start at position
Entry temp = null; // temp will temporarily hold the entry at the next index
while(true) {
temp = directory[j + 1]; // since we need move entry at j to j+1, first we need save the entry at j+1
directory[j + 1] = directory[j]; // entry at j to j+1
if(temp == null) { // if the next entry is null, don't really need to move no more, so break
break;
}
}
// finally place new entry at index position
directory[position] = //the new Entry
Make Entry implement Comparable<Entry> and write the appropriate compareTo method in your Entry class. Then, in your insert method, you want to
Use Arrays.binarySearch to find the right place in the array to insert your the entry.
Use System.arraycopy to shift everything in the array that's after the appropriate location one place to the right.
Set the appropriate entry.
You'll want to check out the Javadoc for Arrays.binarySearch and System.arraycopy.
Firstly, never use arrays unless you absolutely have to. Use Collecctions instead - they are far easier to deal with and have support for lots of operations you commonly want to perform on groups of things.
In your case, a TreeSet would be a good choice. If you want to sort the entries by surname only in this usage (and not generally), you can pass a customer Comparator to the constructor:
Set<Entry> directory = new TreeSet<>(new Comparator<Entry>() {
#Override
public int compare(Entry o1, Entry o2) {
return o1.getSurname().compareTo(o2.getSurname());
}
});
If your always want to sort Entry objects using surname, have your Entry class implement Comparable<Entry> and move the code into the compareTo() method of the Entry class.

detecting circular reference

So in an interview, I was actually asked a simple question that goes like this, say that I have a nested JSON response, [a, b, c ,d [a, [b, [d, e], g], h]. I am asked to implement a class that basically can handle to store this data and a print method to do so, so here's what I have:
public class JSONode
{
private String str;
private JSONode nodes;
public JSONode (String a, ArrayList<String> n)
{
str = a;
nodes = n;
}
}
public class JSONResp
{
private ArrayList<JSONode> arr;
public JSONResp ()
{
arr = new ArrayList<JSONode>();
}
public boolean checkCircular(JSONode temp)
{
for (int i = 0; i < arr.size(); i++)
{
if (arr.get(i).nodes == temp)
return true;
}
return false;
}
public void add (JSONode nd)
{
if (!checkCircular(nd))
arr.add(nd);
}
public void recurseJSONode(JSONode)
{
if (!JSONode.node)
System.out.print(JSONode.str);
else {
System.out.print(JSONode.str);
recurseJSONode(JSONode.node);
}
}
public void print()
{
for (int i = 0; i < arr.size(); i++)
recurseJSONode(arr.get(i));
}
public static void main (String[] args) {
JSONResp x = new JSONResp();
x.add(new JSONode("a", null);
x.add(new JSONode("b", null);
}
}
Now he said that there will circular references issues when I print, in other words I have list A = [a, b, c, D] and D = [q, t, y, A]. So he said I'd have to prevent from adding D by using the checkCircular above. I made an attempt. Also just a node I know my recurseJSONode isn't correct and so does the print, so looking for a suggestion to fix that as well.. I am just curious to this problem.
The reason your circular check isn't right is that you only look for an existing duplicate of JSONode under the one node you're trying to add it to. But A might be under B and B is under A, so each is unique within its parent's list.
Re: using a stack for tracking activity in a recursive function:
Set<SomeNodeType> stack = new HashSet<SomeNodeType>();
someRecursiveThing(rootNode, stack);
And then inside someRecursiveThing:
void someRecursiveThing(SomeNodeType under, Set<SomeNodeType> stack) {
if (!stack.add(under)) {
return;
// continue happily, e.g. call self with child node,
// passing down the stack
SomeNodeType child = ...
someRecursiveThing(child, stack)
// finish by removing 'under' from the stack:
stack.remove(under);
}
The advantage of HashSet is that add and remove typically run in constant time - the size of the tree is irrelevant.
For comparison:
Markus Lausberg's answer suggests doing a complete recursive search of the whole tree, which would be O(N) where N is the number of nodes in the tree, and as you are doing that check for every node it ends up being O(N^2). A tree of 10 nodes will do 100 node comparisons; a tree of 1000 nodes will do 1000,0000 node comparisons.
In kan's answer the check involves searching the parent chain, which will depend on the depth of the tree. For a perfectly lopsided tree (worst case) the depth will be the same as the number of nodes, giving O(N^2) again. For a balanced tree the depth will be ~log N, not much better (remember, the check has to be done for every node).
The effect of these differences depends on the comparison operation used to determine if two nodes are the same. If it is just a pointer comparison (i.e. you only care if they're the same object) and the tree is never very large, the overhead of HashSet may have a negative impact. Whereas if you need to compare two nodes in a more complex way, so each comparison is expensive, and the tree is large, then the optimised lookup of HashSet will become beneficial.
First of all it should be like
public class JSONode
{
private String str;
private ArrayList<JSONode> nodes;
public JSONode (String a, ArrayList<JSONode> n)
{
str = a;
nodes = n;
}
}
You have to check recursivly, if the given node is part of the parent node and the parent of the parent and so on...
So more like
public static boolean checkCircular(JSONode temp)
{
if(temp == null){
return false;
}
ArrayList<JSONode> pNodes = temp.getChildrens();
for (int i = 0; i < nodes.size(); i++)
{
if (pNodes.get(i).getString().equals(temp.getString()))
return true;
if(checkCircular(temp))
return true;
}
return false;
}

Categories

Resources