Word Transformation by changing 1 letter at a time bug - java

I have written a program which will show whether a word can be transformed into another by changing a single character at a time, while the intermediate words are also valid words.
For e.g CAT->COT -> DOT-> DOC
The program works when I use LinkedHashSet to represent the vertices
but it goes into an infinite loop or wrong answer when I use HashSet.
I would like to know what is the problem and if there is a better way to solve the problem then please tell me.
Here is the code: Split into 3 files:
Graph.java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
public class Graph {
private Set<GraphNode> vertices;
public Graph() {
//the code runs when I use LinkedHashSet
vertices = new LinkedHashSet<>();
//the code goes into infinite loop or wrong answer when I use HashSet to represent the vertices
//************
//vertices = new HashSet<>();
//*************
//^^^^^ strange behaviour
}
/**
* adds all the words from the given dictonary to the graph
* #param dictonary
* #return
*/
public boolean addAll(Set<String> dictonary){
boolean result= false;
for (String word : dictonary){
addNode(word);
}
return result;
}
/**
* add a single node into the graph
* #param data
* #return
*/
public GraphNode addNode(String data){
GraphNode node = new GraphNode();
node.setValue(data);
vertices.add(node);
return node;
}
/**
* add a neighbour to the "source" node
* #param source
* #param neighbour
* #return
*/
public boolean addNeighbour(GraphNode source, GraphNode neighbour) {
boolean result = false;
source.getNeighbours().add(neighbour);
return result;
}
/**
* This method assigns the neighbours of nodes depending on whether they are one edit
* away or not
*/
public void assignNeighbours(){
ArrayList<GraphNode> listOfNodes = getAllVertices();
Set<String> usedWords = new HashSet<>();
for ( int i=0 ;i <listOfNodes.size() ;i++){
String currentWord = listOfNodes.get(i).value;
for (int j=0 ; j < listOfNodes.size() ;j++ ){
if (currentWord.equals(listOfNodes.get(j).value)==false){
if (oneEditAway(currentWord, listOfNodes.get(j).value) && usedWords.contains(listOfNodes.get(j).value)==false){
listOfNodes.get(i).neighbours.add(listOfNodes.get(j));
//reflective
listOfNodes.get(j).neighbours.add(listOfNodes.get(i));
usedWords.add(listOfNodes.get(j).value);
}
}
}
}
}
public ArrayList<GraphNode> getAllVertices(){
return new ArrayList<>(vertices);
}
/**
* This method determines whether 2 strings are one edit away or not
* #param first
* #param second
* #return
*/
public boolean oneEditAway(String first, String second) {
// TODO Auto-generated method stub
if (first == null || second == null)
return false;
if (Math.abs(first.length() - second.length())>1){
return false;
}else{
int firstLength = first.length();
int secondLength = second.length();
int mismatchCount = 0;
for (int i=0 ;i < firstLength && i < secondLength ; ++i){
if (first.charAt(i) != second.charAt(i)){
mismatchCount++;
}
}
if (mismatchCount > 1 || Math.abs(firstLength - secondLength) == 1){
return false;
}
return true;
}
}
/**
* This method prints the graph and the connections
*/
public void printGraph() {
// TODO Auto-generated method stub
for (GraphNode node :vertices){
System.out.println("Node is :"+node.value);
System.out.println("Neighbours are :");
for (GraphNode graphNode : node.getNeighbours()){
System.out.print(graphNode.value+ " ");
}
System.out.println();
}
}
/**
* This function determines whether a word can be transformed into an another or not
* #param source
* #param dest
* #return
*/
public boolean canTransform(String source, String dest) {
boolean result = false;
Set<GraphNode> visited = new HashSet<>();
//BFS is the way to go
Queue<GraphNode> allNodes = new LinkedList<>();
GraphNode root=null;
//find the source node in the graph
for (GraphNode node : vertices){
if (node.value.equals(source)){
root = node;
}
}
allNodes.add(root);
System.out.println("***************");
while(!allNodes.isEmpty()){
GraphNode currentNode = allNodes.poll();
System.out.println(currentNode.value);
visited.add(currentNode);
if (currentNode.value.equals(dest)){
result = true;
break;
}
for (GraphNode node: currentNode.getNeighbours()){
if (visited.contains(node) == false){
allNodes.add(node);
}
}
}
return result;
}
#Override
public String toString() {
return "Graph is as follows :\nvertices=" + vertices + "";
}
public Set<GraphNode> getVertices() {
return vertices;
}
public void setVertices(Set<GraphNode> vertices) {
this.vertices = vertices;
}
}
Here is the GraphNode.java
import java.util.HashSet;
import java.util.Set;
public class GraphNode {
String value;
Set<GraphNode> neighbours = new HashSet<GraphNode>();
public GraphNode() {
// TODO Auto-generated constructor stub
}
public GraphNode(String value) {
super();
this.value = value;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GraphNode other = (GraphNode) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
#Override
public String toString() {
return "GraphNode [value=" + value + ", neighbours=" + neighbours + "]";
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Set<GraphNode> getNeighbours() {
return neighbours;
}
public void setNeighbours(Set<GraphNode> neighbours) {
this.neighbours = neighbours;
}
}
Here is the driver class:
import java.util.HashSet;
import java.util.Set;
public class GraphMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
Graph graph = new Graph();
Set<String> dict = new HashSet<>();
dict.add("CAT");
dict.add("COT");
dict.add("DOT");
dict.add("DOG");
dict.add("DOC");
graph.addAll(dict);
graph.assignNeighbours();
graph.printGraph();
String source="CAT",dest = "DOC";
System.out.println("can transform from "+source+" to "+dest+" ??"+graph.canTransform(source,dest));
}
}

The method determining the neighbours of a word is incorrect as the use of the Set usedWords is incorrect. The relation neighbour(w1,w2) must be independent of the order the neighbours are determined, so using some state to decide whether one word is the neighbour of another one cannot be correct.
public void assignNeighbours(){
for ( GraphNode w1: vertices ){
for ( GraphNode w2: vertices ){
if (! w1.equals(w2) ){
if (oneEditAway(w1.getValue(), w2.getValue())){
w1.neighbours.add(w2);
//reflective
w2.neighbours.add(w1);
}
}
}
}
}

Related

Implement the tree in java? not hard coded

There is a Tree implementation, which requires the correction and idea of how to implement the logic.
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* #param <T>
*/
class TreeNode<T> implements Iterable<TreeNode<T>> {
private final List<TreeNode<T>> elementsIndex;
public T data;
public TreeNode<T> parent;
public List<TreeNode<T>> children;
/**
* #param data
*/
public TreeNode(T data) {
this.data = data;
this.children = new LinkedList<TreeNode<T>>();
this.elementsIndex = new LinkedList<TreeNode<T>>();
this.elementsIndex.add(this);
}
/**
* #param depth
* #return Indentation
*/
private static String createIndent(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append('-');
}
return sb.toString();
}
/**
* #return parent
*/
public boolean isRoot() {
return parent == null;
}
/**
* #return check the size of child
*/
public boolean isLeaf() {
return children.size() == 0;
}
/**
* #param child
* #return child node
*/
public TreeNode<T> addChild(T child) {
TreeNode<T> childNode = new TreeNode<T>(child);
childNode.parent = this;
this.children.add(childNode);
this.registerChildForSearch(childNode);
return childNode;
}
/**
* #return the depth of the level
*/
public int getLevel() {
if (this.isRoot())
return 0;
else
return parent.getLevel() + 1;
}
/**
* #param node
*/
private void registerChildForSearch(TreeNode<T> node) {
elementsIndex.add(node);
if (parent != null)
parent.registerChildForSearch(node);
}
/**
* #param cmp
* #return finds the element
*/
public TreeNode<T> findTreeNode(Comparable<T> cmp) {
for (TreeNode<T> element : this.elementsIndex) {
T elData = element.data;
if (cmp.compareTo(elData) == 0)
return element;
}
return null;
}
/**
* #return the root
*/
#Override
public String toString() {
return data != null ? data.toString() : "[data null]";
}
/**
* #return iterator
*/
#Override
public Iterator<TreeNode<T>> iterator() {
TreeNodeIter<T> iter = new TreeNodeIter<T>(this);
return iter;
}
/**
* #param treeRoot
* #param data
* #return the data else null if not found
*/
public TreeNode<T> search(TreeNode<T> treeRoot, T data) {
Comparable<T> searchCriteria = new Comparable<T>() {
#Override
public int compareTo(Object treeData) {
if (treeData == null)
return 1;
boolean nodeOk = treeData.equals(data);
return nodeOk ? 0 : 1;
}
};
TreeNode<T> found = treeRoot.findTreeNode(searchCriteria);
return found;
}
/**
* #param treeRoot
* #return the whole tree
*/
public StringBuilder display(TreeNode<T> treeRoot) {
StringBuilder print = new StringBuilder();
print.append('\n');
for (TreeNode<T> node : treeRoot) {
String indent = createIndent(node.getLevel());
print.append(indent + node.data);
print.append("\n|");
}
if (print.length() > 0)
print.deleteCharAt(print.length() - 1);
return print;
}
}
/**
* #param <T>
*/
class TreeNodeIter<T> implements Iterator<TreeNode<T>> {
private final TreeNode<T> treeNode;
private final Iterator<TreeNode<T>> childrenCurNodeIter;
private ProcessStages doNext;
private TreeNode<T> next;
private Iterator<TreeNode<T>> childrenSubNodeIter;
/**
* #param treeNode
*/
public TreeNodeIter(TreeNode<T> treeNode) {
this.treeNode = treeNode;
this.doNext = ProcessStages.ProcessParent;
this.childrenCurNodeIter = treeNode.children.iterator();
}
/**
* #return true if there is nay element
*/
#Override
public boolean hasNext() {
if (this.doNext == ProcessStages.ProcessParent) {
this.next = this.treeNode;
this.doNext = ProcessStages.ProcessChildCurNode;
return true;
}
if (this.doNext == ProcessStages.ProcessChildCurNode) {
if (childrenCurNodeIter.hasNext()) {
TreeNode<T> childDirect = childrenCurNodeIter.next();
childrenSubNodeIter = childDirect.iterator();
this.doNext = ProcessStages.ProcessChildSubNode;
return hasNext();
} else {
this.doNext = null;
return false;
}
}
if (this.doNext == ProcessStages.ProcessChildSubNode) {
if (childrenSubNodeIter.hasNext()) {
this.next = childrenSubNodeIter.next();
return true;
} else {
this.next = null;
this.doNext = ProcessStages.ProcessChildCurNode;
return hasNext();
}
}
return false;
}
/**
* #return the next element
*/
#Override
public TreeNode<T> next() {
return this.next;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
enum ProcessStages {
ProcessParent,
ProcessChildCurNode,
ProcessChildSubNode
}
}
So, the issue is that I have the data something like this
Gen
|-Test1
|--Mat
|-Test2
|--123
|---Child's Child
|----Child's Child's Child
|----2406
|-Test3
|--24
But to implement that I have to hard code something like this
public static TreeNode<String> getSet() {
TreeNode<String> root = new TreeNode<String>("Gen");
{
TreeNode<String> node0 = root.addChild("Test1");
{
TreeNode<String> node00 = node0.addChild("Mat");
}
TreeNode<String> node1 = root.addChild("Test2");
{
TreeNode<String> node10 = node1.addChild("123");
{
TreeNode<String> node100 = node10.addChild("Child's Child");
{
TreeNode<String> node1000 = node100.addChild("Child's Child's Child");
TreeNode<String> node1001 = node100.addChild("2406");
}
}
}
TreeNode<String> node2 = root.addChild("Test3");
{
TreeNode<String> node20 = node2.addChild("24");
}
}
return root;
}
}
On the top that I have the helper method called getPartentChildPart() method which is used to get the
Map<Parent, List> that is Map<String,List<String>>
Gen
|-Test1
|--Mat
|-Test2
|--123
|---Child's Child
|----Child's Child's Child
|----2406
|-Test3
|--24
For example, if I gave Gen as the parameter to getPartentChildPart() then it will return
Map<Gen,<Test1,Test2,Test3>>
So far what I can achieve is this
public void Build(Map<String, List<String>> ROOT) {
TreeNode<String> root = null;
TreeNode<String> node = null;
for (Map.Entry<String, List<String>> i : ROOT.entrySet()) {
root = new TreeNode<>(i.getKey());
for (String j : i.getValue())
{
node = root.addChild(j);
parent = getPartentChildPart(j);
Build(parent);
}
System.out.println("Root"+root.display(root));
}
}
public void Show() {
Map<String, List<String>> rt = null;
rt = getPartentChildPart("Gen");
Build(rt);
}
The result what I get this is
Gen
|-Test1
|-Test2
|-Test3
I don't understand why recursion is not working and how can I implement this... Although if I hardcode this it can work what if my tree grows in future then hard code will not work.
The first thing to do would be to add a method that returns your list of children. From there recursion becomes quite simple.
void itChildren(TreeNode<T> node)
{
// do stuff
if (!node.getChildren().isEmpty())
{
for (int i = 0; i < node.getChildren().size(); i++)
{
itChildren(node.getChildren().get(i));
}
}
// do stuff
}
This would then iterate over the entirety of the tree. Depending on whether you want to do things before (which I believe is your case) or after the children you can place your code either at the top or bottom of the function.
Let me know if this works for you.
final TreeNode<String> struct = "Gen";
public void build(Map<String, List<String>> parentRoot, TreeNode<String> node) {
Map<String, List<String>> parent;
for (Map.Entry<String, List<String>> i : parentRoot.entrySet()) {
for (Stringj : i.getValue()) {
TreeNode<String> childNode = node.addChild(new TreeNode<>(j));
parent = getPartentChildPart(j);
build(parent, childNode);
}
}
}
public void show() {
Map<String, List<String>> ROOT = null;
ROOT = getPartentChildPart("Gen");
build(ROOT, struct);
System.out.println(struct.display(struct));
}
The mistake was that I need to create a new node every time and need to get the root outside the recurrsion.

how to fix junit test to return value?

My data structures project on dequeues is passing all junit tests except for one. the "removeFrontRemoveRear" test. It keeps returning null instead of the
student name.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Dequeue <E> {
private int front;
private int rear;
private E[] elements;
private static final int DEFAULT_CAPACITY = 5;
/**
* Constructor sets up an empty double-ended
* queue
*/
#SuppressWarnings("unchecked")
public Dequeue() {
elements = (E[]) new Object[DEFAULT_CAPACITY];
front = 0;
rear = elements.length - 1;
}
/**
* Inserts item at the front of the dequeue. Throws
* an exception if the item could not be inserted
* #param anEntry the item to be added (Student)
* #return true
*/
public boolean addFront(E anEntry) {
if (empty()) {
front = rear = 0;
elements[front] = anEntry;
}
else if (isFull()) {
reallocate();
front = (front + (elements.length - 1)) % elements.length;
}
else {
front = (front + (elements.length - 1)) % elements.length;
}
elements[front] = anEntry;
return true;
}
/**
* private method to check if the dequeue is full
* #return true only if dequeue is full (has
* 1 empty spot)
*/
private boolean isFull() {
if (size() == elements.length -1) {
return true;
}
return false;
}
/**
*Doubles and adds 1 to the size of the dequeue
*then reallocates the data.
*/
#SuppressWarnings("unchecked")
private void reallocate() {
E[] newData = (E[]) new Object[size() * 2 + 1];
int indexOfFront = front;
for(int i = 0; i < size(); i++) {
newData[i] = elements[indexOfFront];
indexOfFront = (indexOfFront + 1) % elements.length;
}
rear = size() - 1;
front = 0;
elements = newData;
}
/**
* Inserts item at the rear of the dequeue.
* Throws an exception if the item could not be inserted
* #param anEntry the entry being inserted into the end of the queue
* #return true
*/
public boolean addRear(E anEntry) {
if (empty()) {
front = rear = 0;
elements[rear] = anEntry;
}
else if (isFull()) {
reallocate();
rear = (rear + 1) % elements.length;
}
else {
rear = (rear + 1) % elements.length;
}
elements[rear] = anEntry;
return true;
}
/**
* This method checks if the dequeue is empty
* #return true if the dequeue is empty. otherwise
* returns false
*/
public boolean empty() {
if (front == 0 && rear == elements.length-1) {
return true;
}
return false;
}
/**
* #return the dequeue's iterator
*/
public Iterator<E> iterator() {
return new dequeueIterator();
}
/**
* implementation of Iterator interface
* with inner class
*/
private class dequeueIterator implements Iterator<E> {
private int index;
private int count = 0;
/**
* references the front dequeue element
* and initializes the dequeueIterator object
*/
public dequeueIterator(){
index = front;
}
/**
*#return true it there are additional
* elements in the dequeue
*/
#Override
public boolean hasNext() {
return count < size();
}
/**
* #return the next element in the queue
*/
#Override
public E next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
E returnValue = elements[index];
index = (index + 1) % elements.length;
count++;
return returnValue;
}
/**
* removes the elements accessed by the
* iterator object
*/
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* //Returns the entry at the front of the
* dequeue without removing it; returns
* NoSuchElementException if the dequeue
* is empty
* #return the object at the front of dequeue
*/
public E peekFront() {
if (empty())
throw new NoSuchElementException();
else
return elements[front];
}
/**
* returns the item at the rear of the dequeue, throws
* NoSuchElementException if empty.
* #return the element in the rear
*/
public E peekRear() {
if (empty())
throw new NoSuchElementException();
else
return elements[rear];
}
/**
*Removes the entry at the front of the dequeue and
*returns it if the dequeue is not empty. If the
*dequeue is empty, throws a NoSuchElementException
* #return front element before removing it
*/
public E removeFront() {
if (empty())
throw new NoSuchElementException();
E temp = elements[front];
elements[front] = null;
front = (front++) % elements.length;
return temp;
}
/**
* Removes the entry at the rear of the dequeue and
*returns it if the dequeue is not empty. If the
*dequeue is empty, throws a NoSuchElementException
* #return rear element before removing it
*/
public E removeRear() {
if (empty())
throw new NoSuchElementException();
E temp = elements[rear];
elements[rear] = null;
rear = (rear + elements.length - 1) % elements.length;
return temp;
}
/**
* Gets the amount of elements in the dequeue
* #return the number of elements in the dequeue
*/
public int size() {
int count = 0;
int indexOfFront = front;
int nextRearPosition = (rear + 1) % elements.length;
while(indexOfFront != nextRearPosition) {
count++;
indexOfFront = (indexOfFront + 1) % elements.length;
}
return count;
}
}
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.NoSuchElementException;
public class DequeueTest {
Dequeue<Student> q;
Student s1, s2, s3, s4, s5, s6, s7, s8;
#BeforeEach
public void setUp() throws Exception {
q = new Dequeue<Student> ();
s1 = new Student("John", "Doe");
s2 = new Student ("Jane", "Smith");
s3 = new Student ("Bob", "Taylor");
s4 = new Student ("Anne", "Frank");
s5 = new Student("Frank", "Gauvin");
s6 = new Student("Kevin", "Austin");
s7 = new Student ("Cindy", "Bryant");
s8 = new Student ("Peter", "Lander");
}
#Test
public void testaddFrontAddRear() {
q.addFront(s1);
q.addFront(s2);
q.addFront(s3);
assertThat(q.peekFront(), is(s3)); // assertEquals(s3, q.peekFront());
q.addRear(s4);
q.addRear(s5);
q.addFront(s6);
q.addRear(s7);
assertThat(q.peekRear(), is(s7)); // assertEquals(s7, q.peekRear());
assertThat(q.size(), is(7)); // assertEquals(7, q.size());
}
#Test
public void testRemoveFrontRemoveRear() {
q.addFront(s1);
q.addFront(s2);
q.addFront(s3);
q.addRear(s4);
q.addRear(s5);
q.addFront(s6);
q.addRear(s7);
assertThat(q.removeFront(), is(s6)); // assertEquals(s6, q.removeFront());
assertThat(q.removeRear(), is(s7)); // assertEquals(s7, q.removeRear());
assertThat(q.removeFront(), is(s3)); // assertEquals(s3, q.removeFront() );
assertThat(q.size(), is(4)); // assertEquals(4, q.size());
assertThat(q.removeRear(), is(s5)); // assertEquals(s5, q.removeRear());
assertThat(q.removeFront(), is(s2)); // assertEquals(s2, q.removeFront());
assertThat(q.size(), is(2)); // assertEquals(2, q.size());
assertThat(q.removeFront(), is(s1)); // assertEquals(s1, q.removeFront());
assertThat(q.removeRear(), is(s4)); // assertEquals(s4, q.removeRear());
assertTrue(q.empty());
assertTrue(q.size() == 0);
}
#Test
public void testIterator() {
q.addFront(s1);
q.addFront(s2);
q.addFront(s3);
q.addRear(s4);
assertEquals(4, q.size() );
q.addRear(s5);
q.addFront(s6);
q.addRear(s7);
assertEquals(7, q.size() );
Iterator <Student> iter = q.iterator();
ArrayList<Student> list = new ArrayList<Student>();
while (iter.hasNext()) {
list.add(iter.next() );
}
assertThat(list.get(0), is(s6)); // assertEquals(s6, list.get(0));
assertThat(list.get(1), is(s3)); // assertEquals(s3, list.get(1));
assertThat(list.get(2), is(s2)); // assertEquals(s2, list.get(2));
assertThat(list.get(3), is(s1)); // assertEquals(s1, list.get(3));
assertThat(list.get(4), is(s4)); // assertEquals(s4, list.get(4));
assertThat(list.get(5), is(s5)); // assertEquals(s5, list.get(5));
assertThat(list.get(6), is(s7)); // assertEquals(s7, list.get(6));
}
#Test
public void testPeekFrontOnEmptyQueue() throws NoSuchElementException {
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.peekFront();});
}
#Test
public void testRearFrontOnEmptyQueue() throws NoSuchElementException{
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.peekRear();});
}
#Test
public void testRemoveFrontOnEmptyQueue() throws NoSuchElementException {
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.removeFront();});
}
#Test
public void testRemoveRearOnEmptyQueue() throws NoSuchElementException
{
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.removeRear();});
}
}
/** Abstraction of a Student entity */
public class Student implements Comparable <Student> {
private String firstName;
private String lastName;
/** Initialize a Student
#param first firstName
#param last lastName
*/
public Student(String first, String last) {
firstName = first;
lastName = last;
}
/** Mutator Method
#param aName firstName
*/
public void setFirstName(String aName) {
firstName = aName;
}
/** Accessor Method
#return firstName of this Student
*/
public String getFirstName() {
return firstName;
}
/** Mutator Method
#param aName lastName
*/
public void setLastName(String aName) {
lastName = aName;
}
/** Accessor Method
#return lastName of this Student
*/
public String getLastName() {
return lastName;
}
#Override
public String toString() {
String str = "";
str += (lastName + "," + firstName);
return str;
}
/* this version overloads the equals method (note the
signature of this method).
*/
public boolean equals(Student s) {
return ( (this.lastName.equalsIgnoreCase(s.lastName)) &&
(this.firstName.equalsIgnoreCase(s.firstName)));
}
/* We need to override this method so indexOf and
contains methods work. Both of them use this version
equals method
*/
#Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof Student)) return false;
else {
Student s = (Student) obj;
return ( this.equals(s)); // calls the
equals(Student) method
}
}
/**
#return
a negative integer if "s1 < s2"; 0 if "s1 == s2"
a positive integer if "s1 > s2"
*/
#Override
public int compareTo(Student s) {
int result = lastName.compareToIgnoreCase(s.lastName);
if (result != 0) return result;
else
return (firstName.compareToIgnoreCase(s.firstName));
}
}
The expected result is but the actual result was null.
I am not sure what to try. I am drawing a blank. The error is brought forth in line 55 of dequeueTest.

Iterator implement on AVL tree java

I'm trying to implement iterator on AVL tree, I'm stuck at this specific function:
/**
* #return an iterator for the Avl Tree. The returned iterator iterates over the tree nodes.
* in an ascending order, and does NOT implement the remove() method.
*/
public Iterator<Integer> iterator(){
List myList=new ArrayList<>();
Node counter=root;
Node counter1=root.getChildernLeft();
if(counter1==null){
myList.add(counter1);
}
Node counter1=root.getChildernLeft();
}
I added my two classes:
full code, Node class:
public class Node {
private Node parent;
private Node childernRight;
private Node childernLeft;
private int data;
private int height;
/**
* constractor
*/
public Node(int data, Node childernLeft, Node childernRight) {
this.data = data;
this.childernLeft = childernLeft;
this.childernRight = childernRight;
this.childernRight.setParent(this);
this.childernLeft.setParent(this);
}
public Node(int data) {
this.data = data;
}
public Node getParent() {
return parent;
}
public Node getChildernRight() {
return childernRight;
}
public Node getChildernLeft() {
return childernLeft;
}
public void setParent(Node parent) {
this.parent = parent;
}
public void setChildernRight(Node childernRight) {
this.childernRight = childernRight;
this.childernRight.setParent(this);
}
public void setChildernLeft(Node childernLeft) {
this.childernLeft = childernLeft;
this.childernLeft.setParent(this);
}
public int getData() {
return data;
}
public String toString() {
if (this.childernLeft != null && this.getChildernRight() != null) {
return childernLeft.toString() + "," + this.data + "," + childernRight.toString();
} else if (this.childernLeft != null && this.getChildernRight() == null) {
return childernLeft.toString() + "," + this.data;
} else if (this.childernLeft == null && this.getChildernRight() != null) {
return this.data + "," + childernRight.toString();
} else {
return this.data + "";
}
}
public int balanceFactor() {
int balanceFactor = childernRight.height - childernLeft.height;
return balanceFactor;
}
public boolean hasChildrenRight() {
if (this.childernRight != null) {
return true;
}
else{
return false;
}
}
public boolean hasChildrenLeft() {
if (this.childernLeft != null) {
return true;
}
else{
return false;
}
}
/**
* if we have many children in the tree
*/
public void addNode(Node val){
if(hasChildrenRight()&&this.data>val.data){
this.setChildernRight(val);
}
if(!hasChildrenLeft()&&this.data<val.data){
this.setChildernLeft(val);
}
if(!hasChildrenLeft()&&!hasChildrenRight()){
if(this.data>val.data){
setChildernLeft(val);
}
else{
setChildernRight(val);
}
}
if(val.data>this.data){
childernRight.addNode(val);
}
else{
childernLeft.addNode(val);
}
}
}
full code for AvlTree:`
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class AvlTree {
private Node root;
private int size;
/**
* default constructor.
*/
public AvlTree() {
this.root = null;
this.size = 0;
}
/**
* A constructor that builds a new AVL tree containing all unique values in the input
* array
*
* #param data the values to add to tree
*/
public AvlTree(int[] data) {
for (int i = 0; i < data.length; i++) {
add(data[i]);
}
}
/**
* A copy constructor that creates a deep copy of the given oop.ex4.data_structures.AvlTree. The new tree
* contains all the values of the given tree, but not necessarily in the same structure.
*
* #param avlTree an AVL tree.
*/
public AvlTree(AvlTree avlTree) {
}
/**
* Add a new node with the given key to the tree.
*
* #param newValue the value of the new node to add.
* #return true if the value to add is not already in the tree and it was successfully added,
* false otherwise.
*/
public boolean add(int newValue) {
if (root == null) {
root = new Node(newValue);
size++;
return true;
}
Node current = root;
Node parent = null;
while (current != null) {
if (current.getData() == newValue) {
return false;
}
parent = current;
if (newValue < current.getData()) {
current = current.getChildernLeft();
} else {
current = current.getChildernRight();
}
}
size++;
// when we here the new NODE Need to be chiled of Node hashmor in parent.
// addHelper is adding the new Node.2
// addHelper(newNodeToAdd, current);
return true;
}
private void addHelper(Node newNodeToAdd, Node current) {
// if (newNodeToAdd.getData() > current.getData()) {
// if (current.getChildernRight() == null) {
// current.setChildernRight(newNodeToAdd);
// } else {
// addHelper(newNodeToAdd, current.getChildernRight());
// }
// } else {
// if (current.getChildernLeft() == null) {
// current.setChildernLeft(newNodeToAdd);
// } else {
// addHelper(newNodeToAdd, current.getChildernLeft());
// }
// }
}
/**
* Check whether the tree contains the given input value.
*
* #param searchVal the value to search for.
* #return the depth of the node (0 for the root) with the given value if it was found in the tree, −1 otherwise.
*/
public int contains(int searchVal) {
Node current = root;
int depth = 0;
while (current != null) {
if (current.getData() == searchVal) {
return depth;
}
depth++;
if (searchVal < current.getData()) {
current = current.getChildernLeft();
} else {
current = current.getChildernRight();
}
}
return -1;
}
/**
* Removes the node with the given value from the tree, if it exists.
*
* #param toDelete the value to remove from the tree.
* #return true if the given value was found and deleted, false otherwise.
*/
public boolean delete(int toDelete) {
size -= 1;
return true;
}
/**
* #return the number of nodes in the tree.
*/
public int size() {
return size;
}
/**
* #return an iterator for the Avl Tree. The returned iterator iterates over the tree nodes.
* in an ascending order, and does NOT implement the remove() method.
*/
public Iterator<Integer> iterator(){
List myList=new ArrayList<>();
Node counter=root;
Node counter1=root.getChildernLeft();
if(counter1==null){
myList.add(counter1);
}
Node counter1=root.getChildernLeft();
}
/**
* Calculates the minimum number of nodes in an AVL tree of height h
*
* #param h the height of the tree (a non−negative number) in question.
* #return the minimum number of nodes in an AVL tree of the given height.
*/
public static int findMinNodes(int h) {
// I SOVLE THIS WITH ROCKISA
int counterMin = 0;
if (h == 0) {
return counterMin = 1;
}
if (h == 1) {
return counterMin = 2;
}
return (findMinNodes(h - 1) + findMinNodes(h - 2) + 1);
}
/**
* Calculates the maximum number of nodes in an AVL tree of height h.
*
* #param h the height of the tree (a non−negative number) in question.
* #return the maximum number of nodes in an AVL tree of the given height.
*/
public static int findMaxNodes(int h) {
int counterMax = 0;
for (int i = 0; i < h; i++) {
counterMax += Math.pow(h, i);
}
return counterMax;
}
/**
* #return
*/
public String toString() {
if (root == null) {
return "";
}
return root.toString();
}
//THIS IS OK
public void RotationRr(Node valRotation) {
if (valRotation == root) {
Node keepRootChild = root.getChildernRight();
root.setChildernRight(null);
}
Node parent1 = valRotation.getParent();
Node keepRightChild = valRotation.getChildernRight();///4
valRotation.setChildernRight(null);
keepRightChild.setParent(parent1);
if (!keepRightChild.hasChildrenLeft()) {
keepRightChild.setChildernLeft(valRotation);
valRotation.setParent(keepRightChild);
} else {
keepRightChild.getChildernLeft().addNode(valRotation);
}
}
public void RotationLr(Node valRotation) {
RotationLl(valRotation);
}
/**
* ........CHECK.....!!!!TODO
*
* #param valRotation
*/
public void RotationLl(Node valRotation) {
Node parent2 = valRotation.getParent();
Node keepLeftChild = valRotation.getChildernLeft();
valRotation.setChildernLeft(null);
keepLeftChild.setParent(parent2);
if (!keepLeftChild.hasChildrenRight()) {
keepLeftChild.setParent(keepLeftChild);
} else {
keepLeftChild.getChildernRight().addNode(valRotation);
}
}
public void RotationRl(Node valRotation) {
RotationRr(valRotation);
}
public static void main(String[] args) {
AvlTree avlTree = new AvlTree();
avlTree.add(7);
avlTree.add(2);
System.out.println(avlTree.contains(2));
// System.out.println(avlTree.contains(5));
avlTree = new AvlTree();
avlTree.add(2);
avlTree.add(7);
System.out.println(avlTree.contains(2));
// System.out.println(avlTree);
}
}
`
You can implement a iterator using stack
public Iterator<V> iterator() {
return new Itr();
}
private class Itr<V> implements Iterator<V> {
TreeNode<V> localNode = (TreeNode<V>) root;
Stack<TreeNode<V>> stack;
public Itr() {
stack = new ArrayStack<TreeNode<V>>();
while (localNode != null) {
stack.push(localNode);
localNode = localNode.getLeftChield();
}
}
public boolean hasNext() {
return !stack.empty();
}
public V next() {
TreeNode<V> node = stack.pop();
V v = node.getValue();
if (node.getRightChield() != null) {
node = node.getRightChield();
while (node != null) {
stack.push(node);
node = node.getLeftChield();
}
}
return v;
}
public void remove() {
throw new UnsupportedOperationException();
}
}

ArrayList is losing my reference

I have a static ArrayList (masterLog) that is in my main driver class. The ArrayList contains Event objects, the Event object has an ArrayList (heats) as a global variable. the heat object as an ArrayList (racers) as a global variable. Now when I have the following line of code:
System.out.println(ChronoTimer1009System.getMasterLog().get(0).getHeats().get(getCurHeat()).getRacers().toString());
this returns [] even though the getRacers() IS NOT empty!
When I call this:
System.out.println(getHeats().get(getCurHeat()).getRacers());
this returns the proper filled array.
I think I need to sync the masterLog ArrayList but I am unsure how. I have tried syncing it the way other threads on Stack Exchange have recommended but no luck.
it seems like the static ArrayList masterLog is updated two levels deep but not three levels deep if that makes sense.
What am I doing wrong?
UPDATE:
Maybe this will help explain:
In my main (driver) class, I have a static ArrayList called masterLog. The purpose of this ArrayLIst is to store instances of Event objects for later data retrieval. Now, without making it too complicated, the Event class contains an ArrayList called heats, and the Heat class contains an ArrayList called racers. When I access the masterLog ArrayList at some point in the program (when the other ArrayLists are populated with data), say for example by the call "masterLog.getHeats().get(0).getRacers()", the masterLog does not find any data in the racers ArrayList. It does, however, find data in the heats ArrayList. In other words, the object instance that is stored in the masterLog only updates information to a depth of 2 (not 3 if that makes sense).
UPDATE:
Here is some code:
ChronoTimer1009System class (driver)
package main;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
public class ChronoTimer1009System {
private Event curEvent;
private static Channel[] channels = new Channel[8];
private boolean state;
private static Stack<Log> log;
private static ArrayList<Event> masterLog;
private static Printer p;
public static Time globalTime;
private int oldLogSize; //used only in this.export()
public ChronoTimer1009System() throws UserErrorException{
for(int i=0; i<channels.length; ++i){channels[i] = new Channel(SensorType.NONE);} // initialize channels
masterLog = new ArrayList<Event>(); //this holds references to each event
this.newEvent(EventType.IND);
this.state = false; //system is initally off
log = new Stack<Log>();
p = new Printer();
globalTime = null;
oldLogSize = 0;
}
public void newEvent(EventType e) throws UserErrorException {
switch(e){
case IND: this.curEvent = new IND();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case PARIND: this.curEvent = new PARIND();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case GRP: this.curEvent = new GRP();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case PARGRP: this.curEvent = new PARGRP();ChronoTimer1009System.masterLog.add(this.curEvent);break;
}
for(Channel x : channels){if(x.getState()) x.toggleState();}
}
public void on() throws UserErrorException{
if(state) throw new IllegalStateException();
this.curEvent = new IND();
ChronoTimer1009System.globalTime = new Time(0);
state = true;
}
public void reset() throws UserErrorException{
if(state) state = false;
on();
}
public void exit(){
this.curEvent = null;
ChronoTimer1009System.globalTime = null;
if(!state) throw new IllegalStateException();
state = false;
}
public static Time searchElapsedByID(int idNum){
Time toReturn = null;
for(Log item : log){
if(item.getCompetitorNumber() == idNum){
toReturn = item.getElapsedTime(); break;
}
}
return toReturn;
}
/**
* #return the curEvent
*/
public Event getCurEvent() {
return curEvent;
}
/**
* #return the state
*/
public boolean isState() {
return state;
}
public static Channel getChan(int chan){
if(chan < 1 || chan > 8) throw new IllegalArgumentException("Argument is not in range");
return channels[chan-1];
}
public static void export(){
//*****FORMAT JSON*****
//before formating, a sort of the runners within each heat is needed to determine place.
String toJson = "{\"events\":[";
System.out.println(ChronoTimer1009System.getMasterLog().get(0).getHeats().get(0).getRacers().size());
//iterate through each event
for(int i = 0; i < ChronoTimer1009System.getMasterLog().size(); ++i){
//iterate through each heat of each event
toJson += "{\"name\":\"" + ChronoTimer1009System.getMasterLog().get(i).getType().toString() + "\",\"heats\":[";
for(int j = 0; j < ChronoTimer1009System.getMasterLog().get(i).getHeats().size(); ++j){
//iterate through each competitor in each heat
toJson += "{\"runners\":[";
System.out.println(ChronoTimer1009System.getMasterLog().get(i).getHeats().size());
ArrayList<Competitor> x = sortByPlace(ChronoTimer1009System.getMasterLog().get(i).getHeats().get(j).getRacers()); <----- on this line, the getRacers() part has a size of zero when it isn't empty.
for(int k = 0; k < x.size(); ++k){
//notice we are working with a sorted copy
//TODO make Competitor endTime the elapsed time
toJson += "{\"place\":\"" + String.valueOf(k+1) + "\",\"compNum\":\"" + x.get(k).getIdNum() + "\", \"elapsed\":\"" + x.get(k).getEndTime().toString() + "\"},";
}
toJson += "]},";
}
toJson += "]},";
}
toJson += "}";
System.out.println(toJson);
/*try{
URL site = new URL("http://7-dot-eastern-cosmos-92417.appspot.com/chronoserver");
HttpURLConnection conn = (HttpURLConnection) site.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
String data = "data=" + toJson;
out.writeBytes(data);
out.flush();
out.close();
System.out.println("Done sent to server");
new InputStreamReader(conn.getInputStream());
}
catch (Exception e)
{
e.printStackTrace();
}*/
}
private static ArrayList<Competitor> sortByPlace(ArrayList<Competitor> unsorted)
{
ArrayList<Competitor> whole = (ArrayList<Competitor>) unsorted.clone();
ArrayList<Competitor> left = new ArrayList<Competitor>();
ArrayList<Competitor> right = new ArrayList<Competitor>();
int center;
if(whole.size()==1)
return whole;
else
{
center = whole.size()/2;
// copy the left half of whole into the left.
for(int i=0; i<center; i++)
{
left.add(whole.get(i));
}
//copy the right half of whole into the new arraylist.
for(int i=center; i<whole.size(); i++)
{
right.add(whole.get(i));
}
// Sort the left and right halves of the arraylist.
left = sortByPlace(left);
right = sortByPlace(right);
// Merge the results back together.
merge(left,right,whole);
}
return whole;
}
private static void merge(ArrayList<Competitor> left, ArrayList<Competitor> right, ArrayList<Competitor> whole) {
int leftIndex = 0;
int rightIndex = 0;
int wholeIndex = 0;
// As long as neither the left nor the right arraylist has
// been used up, keep taking the smaller of left.get(leftIndex)
// or right.get(rightIndex) and adding it at both.get(bothIndex).
while (leftIndex < left.size() && rightIndex < right.size())
{
if ((left.get(leftIndex).getEndTime().compareTo(right.get(rightIndex)))<0)
{
whole.set(wholeIndex,left.get(leftIndex));
leftIndex++;
}
else
{
whole.set(wholeIndex, right.get(rightIndex));
rightIndex++;
}
wholeIndex++;
}
ArrayList<Competitor>rest;
int restIndex;
if (leftIndex >= left.size()) {
// The left arraylist has been use up...
rest = right;
restIndex = rightIndex;
}
else {
// The right arraylist has been used up...
rest = left;
restIndex = leftIndex;
}
// Copy the rest of whichever arraylist (left or right) was
// not used up.
for (int i=restIndex; i<rest.size(); i++) {
whole.set(wholeIndex, rest.get(i));
wholeIndex++;
}
}
/**
* #return the log
*/
public static Stack<Log> getLog() {
return log;
}
/**
* #return the masterLog
*/
public static ArrayList<Event> getMasterLog() {
return masterLog;
}
/**
* #return the p
*/
public static Printer getPrinter() {
return p;
}
}
Event Class:
package main;
import java.util.ArrayList;
public abstract class Event extends Display{
private ArrayList<Heat> heats;
private int curHeat; //private means only this class can modify, not the subclasses
private Competitor curComp;
private String name;
public Event(String name) throws UserErrorException{
this.name = name;
heats = new ArrayList<Heat>();
curHeat = -1;
curComp = null;
createRun();
}
/**
* This method will be used by all EventTypes and will not change
* regardless of the EventType.
* #throws UserErrorException
*/
public void createRun() throws UserErrorException{
heats.add(new Heat()); ++curHeat;
}
/**
* #return the heats
*/
public ArrayList<Heat> getHeats() {
return heats;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #return the currentHeat
*/
public int getCurHeat() {
return curHeat;
}
/**
* #return the curComp
*/
public Competitor getCurComp() {
return curComp;
}
/**
* #param curComp the curComp to set
*/
public void setCurComp(Competitor curComp) {
this.curComp = curComp;
}
/* (non-Javadoc)
* #see Display#displayHeatNumber()
*/
#Override
public String displayHeatNumber() {
// TODO Auto-generated method stub
return "Heat: " + (curHeat+1);
}
/* (non-Javadoc)
* #see Display#displayFinished()
*/
#Override
public String displayFinished() {
String toReturn = "";
boolean noRunners = true;
for(Competitor x : getHeats().get(getCurHeat()).getRacers()){
if(x.getEndTime() != null){
toReturn += "\n" + x.getIdNum() + " " + (ChronoTimer1009System.searchElapsedByID(x.getIdNum()).equals(new Time(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE)) ? "DNF" : ChronoTimer1009System.searchElapsedByID(x.getIdNum()).toString() + " F");
noRunners = false;
}
}
if(noRunners){toReturn = "no runners have finished";}
return toReturn;
}
public abstract void endRun() throws UserErrorException;
public abstract void trigChan(int chan, boolean dnf) throws UserErrorException;
public abstract void cancel(int ln) throws UserErrorException;
public abstract EventType getType();
}
Heat class:
package main;
import java.util.ArrayList;
public class Heat {
private ArrayList<Competitor> racers;
//private ArrayList<Competitor> racers;
private int currentCompetitor;
/**
* Constructor
*/
public Heat(){
racers = new ArrayList<Competitor>();
//racers = new ArrayList<Competitor>();
currentCompetitor = 0;
}
/**
* Set selected racer as next on to start
* #param racer the racer to start next
*/
public void setNextCompetitor(Competitor x){
int pos = racers.indexOf(x);
if(pos == -1 || pos<currentCompetitor) throw new IllegalArgumentException("Competitor not in the race! Please add first");
for(int i = pos; i>currentCompetitor; --i){
racers.set(i, racers.get(i-1));
}
racers.set(currentCompetitor, x);
}
/**
* Take the selected runner (the next runner) out from the race
* #param racer the runner to be cleared
*/
public void clearNextCompetitor() throws UserErrorException {
if(racers.size()-(currentCompetitor)<1) throw new UserErrorException("No runners to clear!");
for(int i = currentCompetitor+1; i<racers.size(); ++i){
racers.set(i-1, racers.get(i));
}
racers.remove(racers.size()-1);
}
/**
* basically a remove method
* #param x
*/
public void remove(Competitor x){
int pos = racers.indexOf(x);
if(pos < 0) throw new IllegalArgumentException("runner does not exists");
racers.remove(pos);
}
/**
* Swaps two runners positions in line
*/
public void swap() throws UserErrorException{
int count = 0;
for(Competitor x : racers){
if(x.getStartTime() == null) ++count;
}
if(count > 1 && currentCompetitor + 1 <= racers.size()){
Competitor first = racers.get(currentCompetitor);
Competitor second = racers.get(currentCompetitor+1);
racers.set(currentCompetitor, second);
racers.set(currentCompetitor+1, first);
}
else{
throw new UserErrorException("Not enough competitors to swap");
}
}
/**
* Add a competitor to the end of the current line of competitors if any
* #param x the competitor to add
*/
public boolean addCompetitor(Competitor x) throws UserErrorException{
if(x.getIdNum() < 0 || x.getIdNum() > 99999) throw new UserErrorException("ID number out of range");
if(x.getRunNum() < 0) throw new IllegalArgumentException("Run Num Out of range");
boolean add = true;
for(Competitor i : racers){
if(i.getIdNum() == x.getIdNum()){
add = false;
break;
}
}
if(add){
racers.add(x);
}
return add;
}
/**
* Retrieve the next competitor if there is one
* #return the next competitor
*/
public Competitor getNextCompetitor() throws UserErrorException{
if(!hasNextCompetitor()) throw new UserErrorException("There are no more competitors!");
while(racers.get(currentCompetitor).isCompeting()){++currentCompetitor;}
return racers.get(currentCompetitor++);
}
/**
* used to fix the order of the queue after cancel is called
*/
public void fix(EventType x){
switch(x){
case IND:
--currentCompetitor;
break;
case GRP: case PARGRP: case PARIND:
for(int i = 0; i<racers.size(); ++i){
if(racers.get(i).getStartTime() == null){
currentCompetitor = i;
break;
}
}
break;
}
}
/**
* Is there another competitor to go?
* #return whether or not there is another competitor to go.
*/
public boolean hasNextCompetitor(){
return currentCompetitor < racers.size();
}
/**
* Return a 1D array view of the competitors
* #return
*/
public ArrayList<Competitor> getRacers(){
return racers;
}
}
in the export method of the ChronoTimer1009System class, I point out where the error is and what is happening

equals method for DoublyLinkedList

I got this assignment to create an equals method for doubly linked list. So far I got the code I posted below. It passes some of the tests, but not all. The failures do have the same expected value as the actual value, but I still get some AssertionErrors.
Ive been messing and trying to change things for quite some time now, but I cant seem to figure it out on my own. Nor can I find any good examples on the internet. I've tried using Eclipse to generate the equals method, but that too does not pass all the tests.
I know you do not give away free answers here, but could someone maybe point to the mistake in the code?
/**
* This method should return true iff the values of this list
* and that are identical and in the same order.
* #param that list to compare this to.
* #return true iff the values are identical and in the same order
*/
public boolean equals(Object that) {
if (that == null)
return false;
if (!(that instanceof DoublyLinkedList) )
return false;
DoublyLinkedList<E> other = (DoublyLinkedList<E>) that;
if (header == null&&other.header != null)
return false;
if (trailer == null&&other.trailer != null)
return false;
while (header.getNext() != trailer){
if (!(header.equals(other.header))){
return false;
}
header = header.getNext();
other.header = other.header.getNext();
}
return true;
}
Edit, per request the failed tests en DLL class:
public static class DoublyLinkedList<E> {
private Node<E> header;
private Node<E> trailer;
/**
* Constructor that creates an empty DLL
*/
public DoublyLinkedList() {
this.header = new Node<>(null, null, null);
this.trailer = new Node<>(null, header, null);
this.header.setNext(trailer);
}
/**
* #return if the list is empty.
*/
public boolean isEmpty() {
return this.header.getNext() == this.trailer;
}
/**
* #return the first element of the list.
*/
public E getFirst() {
if (isEmpty()) return null;
return this.header.getNext().getElement();
}
/**
* #return the last element of the list.
*/
public E getLast() {
if (isEmpty()) return null;
return this.trailer.getPrevious().getElement();
}
/**
* Adds a new Node to the beginning of the list,
* containing the specified value.
* #param value for the new first node to hold.
*/
public void addFirst(E element) {
Node<E> newNode = new Node<>(element, header, header.getNext());
header.getNext().setPrevious(newNode);
header.setNext(newNode);
}
/**
* This method should return true iff the values of this list
* and that are identical and in the same order.
* #param that list to compare this to.
* #return true iff the values are identical and in the same order
*/
public boolean equals(Object that) {
if (that == null)
return false;
if (!(that instanceof DoublyLinkedList) )
return false;
DoublyLinkedList<E> other = (DoublyLinkedList<E>) that;
if (header == null&&other.header != null)
return false;
if (trailer == null&&other.trailer != null)
return false;
while (header.getNext() != trailer){
if (!(header.equals(other.header))){
return false;
}
header = header.getNext();
other.header = other.header.getNext();
}
return true;
}
/**
* Simple toString for testing purposes. Please note that solutions that use the
* .toString() to implement the .equals() method will be rejected.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("DoublyLinkedList<");
Node<E> finger = header.getNext();
while (finger != trailer) {
sb.append(finger.toString());
if (finger.getNext() != trailer) {
sb.append("-");
}
finger = finger.getNext();
}
sb.append(">");
return sb.toString();
}
}
And the tests:
#Test
public void testEqualsCopy() {
Solution.DoublyLinkedList<Integer> dll1 = createDLL(2);
Solution.DoublyLinkedList<Integer> dll2 = createDLL(2);
assertEquals(dll1, dll2);
}
#Test
// Both lists contain only the entry 42.
public void testTwoEqualLists() {
Solution.DoublyLinkedList<Integer> dll1 = new Solution.DoublyLinkedList<>();
Solution.DoublyLinkedList<Integer> dll2 = new Solution.DoublyLinkedList<>();
dll1.addFirst(42);
dll2.addFirst(42);
assertEquals(dll1, dll2);
}
and the errors:
testEqualsCopy(UTest) failed: 'java.lang.AssertionError: expected: Solution$DoublyLinkedList<DoublyLinkedList<1-0>> but was: Solution$DoublyLinkedList<DoublyLinkedList<1-0>>'
testTwoEqualLists(UTest) failed: 'java.lang.AssertionError: expected: Solution$DoublyLinkedList<DoublyLinkedList<42>> but was: Solution$DoublyLinkedList<DoublyLinkedList<42>>'
Since, there's quite a gap between what I think a doubly linked list should look like and what you have, I would like to add my sample implementation instead. It does away with the dummy header and trailer nodes which IMHO aren't required at all.
public class DoublyLinkedList<E> {
private Node<E> header;
private Node<E> trailer;
/**
* #return if the list is empty.
*/
public boolean isEmpty() {
return header == null;
}
/**
* #return the first element of the list.
*/
public E getFirst() {
return header != null ? header.getElement() : null;
}
/**
* #return the last element of the list.
*/
public E getLast() {
return trailer != null ? trailer.getElement() : null;
}
/**
* Adds a new Node to the beginning of the list,
* containing the specified value.
* #param value for the new first node to hold.
*/
public void addFirst(E element) {
Node<E> newNode = new Node<E>(element, null, header);
header = newNode;
if (trailer == null) {
trailer = newNode;
}
}
/**
* This method should return true if the values of this list and that are
* identical and in the same order.
*
* #param that
* list to compare this to.
* #return true if the values are identical and in the same order
*/
#SuppressWarnings("unchecked")
public boolean equals(Object that) {
if (!(that instanceof DoublyLinkedList))
return false;
DoublyLinkedList<E> other = (DoublyLinkedList<E>) that;
// if lists are empty
if (header == null) {
return other.header == null ? true : false;
}
if (!header.equals(other.header))
return false;
// Just one element
if (header == trailer) {
return true;
}
if (!trailer.equals(other.trailer))
return false;
Node<E> thisNode = header;
Node<E> otherNode = other.header;
while (thisNode.getNext() != trailer) {
thisNode = thisNode.getNext();
otherNode = otherNode.getNext();
if (!(thisNode.equals(otherNode))) {
return false;
}
}
return true;
}
/**
* Simple toString for testing purposes. Please note that solutions that use the
* .toString() to implement the .equals() method will be rejected.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("DoublyLinkedList<");
Node<E> finger = header;
while (finger != null) {
sb.append(finger.toString());
if (finger.getNext() != null) {
sb.append("-");
}
finger = finger.getNext();
}
sb.append(">");
return sb.toString();
}
}
Here's what my Node class looks like. Not many changes here.
public class Node<E> {
private E element;
private Node<E> previous;
private Node<E> next;
public Node<E> getPrevious() {
return previous;
}
public Node<E> getNext() {
return next;
}
public E getElement() {
return element;
}
public Node(E element, Node<E> previous, Node<E> next) {
this.element = element;
this.previous = previous;
this.next = next;
}
#Override
#SuppressWarnings("unchecked")
public boolean equals(Object that) {
if (!(that instanceof Node)) {
return false;
}
Node<E> other = (Node<E>) that;
if (element == null) {
return other.element == null ? true : false;
}
return element.equals(other.element);
}
#Override
public String toString() {
return element.toString();
}
}
Here's the code I used to test my implementation.
DoublyLinkedList<Integer> dll1 = new DoublyLinkedList<Integer>();
dll1.addFirst(100);
dll1.addFirst(200);
DoublyLinkedList<Integer> dll2 = new DoublyLinkedList<Integer>();
dll2.addFirst(100);
dll2.addFirst(200);
DoublyLinkedList<Integer> dll3 = new DoublyLinkedList<Integer>();
dll3.addFirst(42);
DoublyLinkedList<String> blankList1 = new DoublyLinkedList<String>();
DoublyLinkedList<String> blankList2 = new DoublyLinkedList<String>();
if (blankList1.equals(blankList2)) {
System.out.println(blankList1 + " = " + blankList2);
}
if (!dll1.equals(dll3)) {
System.out.println(dll1 + " != " + dll3);
}
if (dll1.equals(dll2)) {
System.out.println(dll1 + " = " + dll2);
}
Output :
DoublyLinkedList<> = DoublyLinkedList<>
DoublyLinkedList<200-100> != DoublyLinkedList<42>
DoublyLinkedList<200-100> = DoublyLinkedList<200-100>

Categories

Resources