I am making a program that creates a generic hashtable that has both generic keys and generic data. When I cast the data array as the type Person, a class I created, and I try to access the data stored inside an individual Person from my Driver class using a getter method, I get an Object-type returned. My question is how do I access a non-generic class's information through a generic class, since it is stored in a generic array.
This is how I constructed the hashtable:
//region Instance Variables
private int count;
private K[] keys;
private E[] data;
private boolean[] hasBeenUsed;
//endregion
//region Constructor
public Table(int capacity)
{
if (capacity <= 0)
throw new IllegalArgumentException("Capacity is negative.");
keys = (K[]) new Object[capacity];
data = (E[]) new Object[capacity];
hasBeenUsed = new boolean[capacity];
}
My data getters(part of the Table class):
public E[] getData()
{
return data;
}
public E getDataAt(int index)
{
return data[index];
}
This is where I am trying to access the information from my Driver class:
public void print(Table hash)
{
Person[] people = toArray(hash);
for (int i = 0; i < hash.getData().length; i++)
{
if (null == hash.getKeyAt(i))
System.out.println("NULL AT " + i);
else
System.out.println("Key: " + hash.getKeyAt(i) + " Data: " + hash.getDataAt(i));
}
}
private Person[] toArray(Table hash)
{
Person[] people = new Person[hash.getData().length];
for (int i = 0; i < hash.getData().length; i++)
{
people[i] = hash.getDataAt(i);
}
}
This is my entire Hashtable Class if it's needed:
public class Table<K,E>
{
//region Instance Variables
private int count;
private K[] keys;
private E[] data;
private boolean[] hasBeenUsed;
//endregion
//region Constructors
/**
* Constructor
* Instantiates the keys, data, and hasBeenUsed variables with a passed value of capacity
* #param capacity the size to give the three instance arrays
*/
#SuppressWarnings("unchecked")
public Table(int capacity)
{
if (capacity <= 0)
throw new IllegalArgumentException("Capacity is negative.");
keys = (K[]) new Object[capacity];
data = (E[]) new Object[capacity];
hasBeenUsed = new boolean[capacity];
}
/**
* Constructor
* Default-Sets arrays to size 10
*/
#SuppressWarnings("unchecked")
public Table()
{
keys = (K[]) new Object[10];
data = (E[]) new Object[10];
hasBeenUsed = new boolean[10];
}
//endregion
//region Public Methods
/**
* Put
* Adds a new set to the table
* #param key The new Key value
* #param data the new Data value
* #return null if this is a new set, the old data value if the key already exists
*/
public E put(K key, E data)
{
int index = findIndex(key);
E answer;
if (index != -1)
{
answer = (E) this.data[index];
this.data[index] = data;
return answer;
} else if (count < this.data.length)
{
index = hash(key);
while (keys[index] != null)
{
System.out.println("Collision!");
index = nextIndex(index, key);
}
keys[index] = key;
this.data[index] = data;
hasBeenUsed[index] = true;
count++;
return null;
} else
System.out.println("ERROR IN PUT");
return null;
}
/**
* Remove
* Removes a key-data set from the table
* #return the value removed
*/
#SuppressWarnings("unchecked")
public E remove(K key)
{
int index = findIndex(key);
E answer = null;
if (index != -1)
{
answer = (E) data[index];
keys[index] = null;
data[index] = null;
count--;
}
return answer;
}
/**
* Contains Key
* Checks if the passed key exists
* #param key generic type key to check for
* #return true if the key exists
*/
public boolean containsKey(K key)
{
for (int i = 0; i < data.length; i++)
{
if (hasBeenUsed[i])
{
if (keys[i].equals(key))
{
return true;
}
}
}
return false;
}
/**
* Get
* Retrieves the data held stored with key
* #param key the key to access
* #return the data at key, null if key does not exist
*/
#SuppressWarnings("unchecked")
public E get(K key)
{
int index = findIndex(key);
if (index == -1)
return null;
else
return (E) data[index];
}
//endregion
//region Private Methods
//Locates the index value of key
private int findIndex(K key)
{
int count = 0;
int i = hash(key);
while ((count < data.length) && (hasBeenUsed[i]))
{
if (key.equals(keys[i]))
return i;
count++;
i = nextIndex(i, key);
}
return -1;
}
//Hashes the key
private int hash(K key)
{
return Math.abs(key.hashCode()) % data.length;
}
private int hash2(K key)
{
return 1 + (Math.abs(key.hashCode()) % (data.length-2));
}
//Determines if the next index is valid
private int nextIndex(int i, K key)
{
return (i + hash2(key)) % data.length;
}
//endregion
//region Getters and Setters
public int getCount()
{
return count;
}
public void setCount(int count)
{
this.count = count;
}
public K[] getKeys()
{
return keys;
}
public K getKeyAt(int index)
{
return keys[index];
}
public void setKeys(K[] keys)
{
this.keys = keys;
}
public E[] getData()
{
return data;
}
public E getDataAt(int index)
{
return data[index];
}
public void setData(E[] data)
{
this.data = data;
}
//endregion
}
EDIT
I edited the print method, and now I am getting a ClassCastException
Here is my new print method:
public void print(Table<Integer, Person> hash)
{
for (int i = 0; i < hash.getKeys().length; i++)
{
if (null == hash.getKeyAt(i))
System.out.println("NULL AT " + hash.getKeyAt(i));
else
{
System.out.println("Data at key " + hash.getKeyAt(i) + ": \n");
hash.getDataAt(i).printInfo();
}
}
}
You Table is actually generic. So when you want a new Table instance, you can say new Table<KEY_TYPE, VALUE_TYPE>() which will not need you to cast anywhere.
If you're not sure how to create an instance of generic class, please check https://docs.oracle.com/javase/tutorial/java/generics/types.html.
Related
I have Implemented B-Tree, I have given toString to Implement method in Node class as it but its giving errot in this line children.forEach(c ->builder.append(c.toString(depth + 1))); I have tried various methods but not worked
here is other B-Tree files and pdf where is given toString Methods and other Instruction check out these files
toString code
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class Node<E extends Comparable<E>> {
public int nodeLocation;
public int index;
private E[] keys = null;
int keysSize = 0;
public Node<E>[] children = null;
public Node<E>[] elements;
int childrenSize = 0;
private Comparator<Node<E>> comparator = new Comparator<Node<E>>() {
#Override
public int compare(Node<E> arg0, Node<E> arg1) {
return arg0.getKey(0).compareTo(arg1.getKey(0));
}
};
protected Node<E> parent = null;
Node(Node<E> parent, int maxKeySize, int maxChildrenSize) {
this.parent = parent;
this.keys = (E[]) new Comparable[maxKeySize + 1];
this.keysSize = 0;
this.children = new Node[maxChildrenSize + 1];
this.childrenSize = 0;
}
E getKey(int index) {
return keys[index];
}
int indexOf(E value) {
for (int i = 0; i < keysSize; i++) {
if (keys[i].equals(value))
return i;
}
return -1;
}
void addKey(E value) {
keys[keysSize++] = value;
Arrays.sort(keys, 0, keysSize);
}
E removeKey(E value) {
E removed = null;
boolean found = false;
if (keysSize == 0)
return null;
for (int i = 0; i < keysSize; i++) {
if (keys[i].equals(value)) {
found = true;
removed = keys[i];
} else if (found) {
// shift the rest of the keys down
keys[i - 1] = keys[i];
}
}
if (found) {
keysSize--;
keys[keysSize] = null;
}
return removed;
}
E removeKey(int index) {
if (index >= keysSize)
return null;
E value = keys[index];
for (int i = index + 1; i < keysSize; i++) {
// shift the rest of the keys down
keys[i - 1] = keys[i];
}
keysSize--;
keys[keysSize] = null;
return value;
}
int numberOfKeys() {
return keysSize;
}
Node<E> getChild(int index) {
if (index >= childrenSize)
return null;
return children[index];
}
int indexOf(Node<E> child) {
for (int i = 0; i < childrenSize; i++) {
if (children[i].equals(child))
return i;
}
return -1;
}
boolean addChild(Node<E> child) {
child.parent = this;
children[childrenSize++] = child;
Arrays.sort(children, 0, childrenSize, comparator);
return true;
}
boolean removeChild(Node<E> child) {
boolean found = false;
if (childrenSize == 0)
return found;
for (int i = 0; i < childrenSize; i++) {
if (children[i].equals(child)) {
found = true;
} else if (found) {
// shift the rest of the keys down
children[i - 1] = children[i];
}
}
if (found) {
childrenSize--;
children[childrenSize] = null;
}
return found;
}
Node<E> removeChild(int index) {
if (index >= childrenSize)
return null;
Node<E> value = children[index];
children[index] = null;
for (int i = index + 1; i < childrenSize; i++) {
// shift the rest of the keys down
children[i - 1] = children[i];
}
childrenSize--;
children[childrenSize] = null;
return value;
}
int numberOfChildren() {
return childrenSize;
}
/**
* {#inheritDoc}
*/
public String toStringg() {
return toString(0);
}
// // based on what toString() does, think about what ‘elements’ and ‘children’
// can be
private String toString(int depth) {
StringBuilder builder = new StringBuilder();
String blankPrefix = new String(new char[depth]).replace("\0", "\t");
List<String> printedElements = new LinkedList<>();
for (Node<E> e : elements)
printedElements.add(e.toString());
String eString = String.join(" :: ", printedElements);
builder.append(blankPrefix).append(eString).append("\n");
children.forEach(c -> builder.append(c.toString(depth + 1))); // this line is giving error
return builder.toString();
}
}
I Have Gievn pdf File where is gievn insructions and code implement I have tried to change childern but not worked I am bound to not make changes in gievn toString method
Arrays in Java doesn't declare their own behavior (don't try to reproduce your experience from languages like JavaScript and TypeScript, where Arrays have methods).
Therefore, you can't invoke method forEach() on the children array (this method is accessible with implementations of Iterable interface, like Collections).
You can use an enhanced for-loop instead:
for (Node<E> node : children) {
builder.append(node.toString(depth + 1));
}
Alternatively, if you declare the property children as a List you'll be able use forEach() with it:
public List<Node<E>> children;
Judging by your assignment requirements, that what you're expected to do.
That would require changing all the methods that make use of children because you can't dial with a List in the same way as with an array. I.e. you would need to use the behavior of the List interface.
children[i] would turn to children.get(i). And children[i] = ... would become children.set(i, ...), or children.add(...).
In advance, I apologize for my lack of experience, these are advanced concepts that are difficult to wrap my head around. From what I understand, linear probing is circular, it won't stop until it finds an empty cell.
However I am not sure how to implement it. Some example on how to would be greatly appreciated. Sorry again for the inexperience, I'm not some vetted programmer, I'm picking this up very slowly.
public boolean ContainsElement(V element)
{
for(int i = 0; i < capacity; i++)
{
if(table[i] != null)
{
LinkedList<Entry<K, V>> bucketMethod = table[i];
for(Entry<K, V> entry : bucketMethod)
{
if(entry.getElement().equals(element))
{
return true;
}
}
}
}
return false;
}
Here's a working hash table based on the pseudocode examples found in the Wikipedia article for open addressing.
I think the main differences between the Wikipedia example and mine are:
Treating the hashCode() a little bit due to the way Java does modulo (%) with negative numbers.
Implemented simple resizing logic.
Changed the logic in the remove method a little bit because Java doesn't have goto.
Otherwise, it's more or less just a direct translation.
package mcve;
import java.util.*;
import java.util.stream.*;
public class OAHashTable {
private Entry[] table = new Entry[16]; // Must be >= 4. See findSlot.
private int size = 0;
public int size() {
return size;
}
private int hash(Object key) {
int hashCode = Objects.hashCode(key)
& 0x7F_FF_FF_FF; // <- This is like abs, but it works
// for Integer.MIN_VALUE. We do this
// so that hash(key) % table.length
// is never negative.
return hashCode;
}
private int findSlot(Object key) {
int i = hash(key) % table.length;
// Search until we either find the key, or find an empty slot.
//
// Note: this becomes an infinite loop if the key is not already
// in the table AND every element in the array is occupied.
// With the resizing logic (below), this will only happen
// if the table is smaller than length=4.
while ((table[i] != null) && !Objects.equals(table[i].key, key)) {
i = (i + 1) % table.length;
}
return i;
}
public Object get(Object key) {
int i = findSlot(key);
if (table[i] != null) { // Key is in table.
return table[i].value;
} else { // Key is not in table
return null;
}
}
private boolean tableIsThreeQuartersFull() {
return ((double) size / (double) table.length) >= 0.75;
}
private void resizeTableToTwiceAsLarge() {
Entry[] old = table;
table = new Entry[2 * old.length];
size = 0;
for (Entry e : old) {
if (e != null) {
put(e.key, e.value);
}
}
}
public void put(Object key, Object value) {
int i = findSlot(key);
if (table[i] != null) { // We found our key.
table[i].value = value;
return;
}
if (tableIsThreeQuartersFull()) {
resizeTableToTwiceAsLarge();
i = findSlot(key);
}
table[i] = new Entry(key, value);
++size;
}
public void remove(Object key) {
int i = findSlot(key);
if (table[i] == null) {
return; // Key is not in the table.
}
int j = i;
table[i] = null;
--size;
while (true) {
j = (j + 1) % table.length;
if (table[j] == null) {
break;
}
int k = hash(table[j].key) % table.length;
// Determine if k lies cyclically in (i,j]
// | i.k.j |
// |....j i.k.| or |.k..j i...|
if ( (i<=j) ? ((i<k)&&(k<=j)) : ((i<k)||(k<=j)) ) {
continue;
}
table[i] = table[j];
i = j;
table[i] = null;
}
}
public Stream<Entry> entries() {
return Arrays.stream(table).filter(Objects::nonNull);
}
#Override
public String toString() {
return entries().map(e -> e.key + "=" + e.value)
.collect(Collectors.joining(", ", "{", "}"));
}
public static class Entry {
private Object key;
private Object value;
private Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
public Object getKey() { return key; }
public Object getValue() { return value; }
}
public static void main(String[] args) {
OAHashTable t = new OAHashTable();
t.put("A", 1);
t.put("B", 2);
t.put("C", 3);
System.out.println("size = " + t.size());
System.out.println(t);
t.put("X", 4);
t.put("Y", 5);
t.put("Z", 6);
t.remove("C");
t.remove("B");
t.remove("A");
t.entries().map(e -> e.key)
.map(key -> key + ": " + t.get(key))
.forEach(System.out::println);
}
}
java.util.HashMap implementation of java.util.Map internally provides linear probing that is HashMap can resolve collisions in hash tables.
So i am trying to make an array based generic heap that i can use with my tester class. Much of what i have is based of my understandings of trees and some research online as well as from my textbook; both which have very limited info on what i am looking for. However, i did manage to get all the methods in need and when i run it, i get this error:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at q1.Heaps.<init>(Heaps.java:23)
at q1.createGui.<init>(Gui.java:46)
at q1.Gui.main(Gui.java:18)
Im guessing it has to do with how i declare and initialize my Comparable array, which i am having trouble figuring out how to.
package q1;
import java.util.Arrays;
public class Heaps<E extends Comparable<E>> {
Comparable[] data;
int size;
/**
* Constructor with s as size
*/
#SuppressWarnings("unchecked")
public Heaps(int s) {
size = 0;
data = (E[]) new Object[s];
}
/**
* Adds a value to the heap
*/
public void add(E value) {
if (full()) // expand array
ensureCapacity(2*size);
size++;
data[size] = value;
if (size > 1)
heapifyUp();
}
/**
* Checks if the array is full
*/
private boolean full()
{
return (size == data.length-1);
}
private void heapifyUp()
{
Comparable<E> temp;
int next = size;
while (next != 1 && data[next].compareTo(data[next/2]) > 0)
{
temp = data[next];
data[next] = data[next/2];
data[next/2] = temp;
next = next/2;
}
}
private void heapifyDown()
{
Comparable<E> temp;
int next = 0;
while (next*2 <= size) // node has a child
{
int child = 2*next; // left child
if (child < size &&
data[child].compareTo(data[child+1]) > 0)//left smaller than right
child++; // right child instead
if (data[next].compareTo(data[child]) > 0)
{
temp = data[next];
data[next] = data[child];
data[child] = temp;
next = child;
}
else;
next = size; // stop loop
}//end while
}
/**
* Removes all occurrence of element
*/
public boolean removeAll(E element) {
if (contains(element) && !(isEmpty())){
for (int i = 0; i < size; i++){
if(element.equals(data[i])){
data[i] = data[size-1];
}
heapifyDown();
}
return true;
}
return false;
}
/**
* Removes 1st occurrence of element
*/
public boolean remove(E element) {
if (contains(element) && !(isEmpty())){
for (int i = 0; i < size; i++){
if(element.equals(data[i])){
data[i] = data[size-1];
heapifyDown();
return true;
}
}
}
return false;
}
public boolean isEmpty() {
return size == 0;
}
public Comparable<E>[] ensureCapacity(int s) {
return Arrays.copyOf(data, 2*s);
}
/**
* Converts the heap into its String representation.
* #return the String representation
*/
public Comparable<E>[] iteratorPreOrder()
{
Comparable<E>[] temp = (E[]) new Object[size];
temp[0] = data[0];
int i = 1;
int count = 1;
while(data[2*i] != null){
temp[count] = data[2*i];
++i;
++count;
}
i = 1;
while(data[(2*i) +1] != null){
temp[count] = data[(2*i) +1];
++i;
++count;
}
return temp;
}
public int countOccurance(E element){
int count = 0;
for (int i =0; i < size; i++){
if(element.equals(data[i])){
count++;
}
}
return count;
}
public boolean contains (E element)
{
for (int i=0; i<size; i++){
if (element.equals(data[i])){
return true;
}
}
return false;
}
}
If you could please show me how i would solve this problem, i would greatly appreciate it. Thanks
EDIT: SO i edited the my class and now it works when i do data = (E[]) new Comparable[s]. So why does java not allow generic Array types, what makes it different from Arraylist, Stacks, Queues, and/or LinkedList which can be generic?
You are creating an Object[] and then trying to cast it to a Comprable[]. The compiler was telling you what you did wrong with the unchecked cast error.
You want data to be E[] data and the line to be:
data = new E[s];
Note: this could run into issues with how Java handles generics.
So I have a HashTable implementation here that I wrote using only Arrays and had a little bit of help with the code. Unfortunately, I don't quite understand one of the lines someone added while running the "get" or "put" method. What exactly is happening in the while loop below? It is a method for linear probing correct? Also why is the loop checking the conditions it's checking?
Specifically,
int hash = hashThis(key);
while(data[hash] != AVAILABLE && data[hash].key() != key) {
hash = (hash + 1) % capacity;
}
Here's the whole Java class below for full reference.
public class Hashtable2 {
private Node[] data;
private int capacity;
private static final Node AVAILABLE = new Node("Available", null);
public Hashtable2(int capacity) {
this.capacity = capacity;
data = new Node[capacity];
for(int i = 0; i < data.length; i++) {
data[i] = AVAILABLE;
}
}
public int hashThis(String key) {
return key.hashCode() % capacity;
}
public Object get(String key) {
int hash = hashThis(key);
while(data[hash] != AVAILABLE && data[hash].key() != key) {
hash = (hash + 1) % capacity;
}
return data[hash].element();
}
public void put(String key, Object element) {
if(key != null) {
int hash = hashThis(key);
while(data[hash] != AVAILABLE && data[hash].key() != key) {
hash = (hash + 1) % capacity;
}
data[hash] = new Node(key, element);
}
}
public String toString(){
String s="<";
for (int i=0;i<this.capacity;i++)
{
s+=data[i]+", ";
}
s+=">";
return s;
}
Thank you.
I just rewrote some part of the code and added the findHash-method - try to avoid code-duplication!
private int findHash(String key) {
int hash = hashThis(key);
// search for the next available element or for the next matching key
while(data[hash] != AVAILABLE && data[hash].key() != key) {
hash = (hash + 1) % capacity;
}
return hash;
}
public Object get(String key) {
return data[findHash(key)].element();
}
public void put(String key, Object element) {
data[findHash(key)] = new Node(key, element);
}
What you asked for is - what exactly does this findHash-loop? The data was initialized with AVAILABLE - meaning: the data does not (yet) contain any actual data. Now - when we add an element with put - first a hashValue is calculated, that is just an index in the data array where to put the data. Now - if we encounter that the position has already been taken by another element with the same hash value but a different key, we try to find the next AVAILABLE position. And the get method essentially works the same - if a data element with a different key is detected, the next element is probed and so on.
The data itself is a so called ring-buffer. That is, it is searched until the end of the array and is next search again at the beginning, starting with index 0. This is done with the modulo % operator.
Alright?
Sample Hashtable implementation using Generics and Linear Probing for collision resolution. There are some assumptions made during implementation and they are documented in javadoc above class and methods.
This implementation doesn't have all the methods of Hashtable like keySet, putAll etc but covers most frequently used methods like get, put, remove, size etc.
There is repetition of code in get, put and remove to find the index and it can be improved to have a new method to find index.
class HashEntry<K, V> {
private K key;
private V value;
public HashEntry(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public K getKey() { return this.key; }
public void setValue(V value) { this.value = value; }
public V getValue() { return this.value; }
}
/**
* Hashtable implementation ...
* - with linear probing
* - without loadfactor & without rehash implementation.
* - throws exception when table is full
* - returns null when trying to remove non existent key
*
* #param <K>
* #param <V>
*/
public class Hashtable<K, V> {
private final static int DEFAULT_CAPACITY = 16;
private int count;
private int capacity;
private HashEntry<K, V>[] table;
public Hashtable() {
this(DEFAULT_CAPACITY);
}
public Hashtable(int capacity) {
super();
this.capacity = capacity;
table = new HashEntry[capacity];
}
public boolean isEmpty() { return (count == 0); }
public int size() { return count; }
public void clear() { table = new HashEntry[this.capacity]; count = 0; }
/**
* Returns null if either probe count is higher than capacity else couldn't find the element.
*
* #param key
* #return
*/
public V get(K key) {
V value = null;
int probeCount = 0;
int hash = this.hashCode(key);
while (table[hash] != null && !table[hash].getKey().equals(key) && probeCount <= this.capacity) {
hash = (hash + 1) % this.capacity;
probeCount++;
}
if (table[hash] != null && probeCount <= this.capacity) {
value = table[hash].getValue();
}
return value;
}
/**
* Check on the no of probes done and terminate if probe count reaches to its capacity.
*
* Throw Exception if table is full.
*
* #param key
* #param value
* #return
* #throws Exception
*/
public V put(K key, V value) throws Exception {
int probeCount = 0;
int hash = this.hashCode(key);
while (table[hash] != null && !table[hash].getKey().equals(key) && probeCount <= this.capacity) {
hash = (hash + 1) % this.capacity;
probeCount++;
}
if (probeCount <= this.capacity) {
if (table[hash] != null) {
table[hash].setValue(value);
} else {
table[hash] = new HashEntry(key, value);
count++;
}
return table[hash].getValue();
} else {
throw new Exception("Table Full!!");
}
}
/**
* If key present then mark table[hash] = null & return value, else return null.
*
* #param key
* #return
*/
public V remove(K key) {
V value = null;
int probeCount = 0;
int hash = this.hashCode(key);
while (table[hash] != null && !table[hash].getKey().equals(key) && probeCount <= this.capacity) {
hash = (hash + 1) % this.capacity;
probeCount++;
}
if (table[hash] != null && probeCount <= this.capacity) {
value = table[hash].getValue();
table[hash] = null;
count--;
}
return value;
}
public boolean contains(Object value) {
return this.containsValue(value);
}
public boolean containsKey(Object key) {
for (HashEntry<K, V> entry : table) {
if (entry != null && entry.getKey().equals(key)) {
return true;
}
}
return false;
}
public boolean containsValue(Object value) {
for (HashEntry<K, V> entry : table) {
if (entry != null && entry.getValue().equals(value)) {
return true;
}
}
return false;
}
#Override
public String toString() {
StringBuilder data = new StringBuilder();
data.append("{");
for (HashEntry<K, V> entry : table) {
if (entry != null) {
data.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
}
}
if (data.toString().endsWith(", ")) {
data.delete(data.length() - 2, data.length());
}
data.append("}");
return data.toString();
}
private int hashCode(K key) { return (key.hashCode() % this.capacity); }
public static void main(String[] args) throws Exception {
Hashtable<Integer, String> table = new Hashtable<Integer, String>(2);
table.put(1, "1");
table.put(2, "2");
System.out.println(table);
table.put(1, "3");
table.put(2, "4");
System.out.println(table);
table.remove(1);
System.out.println(table);
table.put(1, "1");
System.out.println(table);
System.out.println(table.get(1));
System.out.println(table.get(3));
// table is full so below line
// will throw an exception
table.put(3, "2");
}
}
Sample run of the above code.
{2=2, 1=1}
{2=4, 1=3}
{2=4}
{2=4, 1=1}
1
null
Exception in thread "main" java.lang.Exception: Table Full!!
at Hashtable.put(Hashtable.java:95)
at Hashtable.main(Hashtable.java:177)
I have been trying to write a Java function IntList get(int i) that is supposed to return a reference to the i-th element in a singly linked integer list.
My problem is that the function returns null, even if I try to reference an existing element!
public class IntList {
private int info; //the int data of this list element
private IntList next; //the rest of the list
/**
* Sets up a new instance of IntList corresponding to the given info and next.
* #param info the int data of this list element
* #param next the rest of the list
*/
public IntList(int info, IntList next) {
this.info = info;
this.next = next;
}
/**
* A new list where the given info has been prepended.
* #param info the int data of the new list element
* #return a new instance of IntList
*/
/*
public IntList prepend(int info) {
return new IntList(info, this);
}
*/
/**
* A new list where the given info has been appended.
* #param info the int data of the new list element
* #return a new instance of IntList
*/
public IntList append(int info) {
if(next == null) {
return new IntList(this.info, new IntList(info, null));
} else {
return new IntList(this.info, next.append(info));
}
}
/**
* Commputes the sum of all elements of this list.
* #return the sum of all elements
*/
public int sum() {
if(next == null) {
return info;
} else {
return info + next.sum();
}
}
/**
* Auxiliary function for the reversal of this list.
* #param acc the list elements accumulated so far
* #return a new instance of IntList
*/
private IntList reverseAux(IntList acc) {
if(next == null) {
return new IntList(info, acc);
} else {
return next.reverseAux(new IntList(info, acc));
}
}
/**
* A new list with the elements of this list in reverse order.
* #return a new instance of the IntList
*/
public IntList reverse() {
return reverseAux(null);
}
/**
* String representation of this list.
*/
#Override
public String toString() {
if(next == null) {
return "" + info;
} else {
return info + " , " + next;
}
}
/**
* An integer array is converted to a list
* #param values is an array containing integer elements
* #return a new instance of IntList
*/
public static IntList fromArray(int[] values) {
int n = values.length;
IntList res = new IntList(values[0] , null);
for(int i = 1; i < n ; i ++) {
res = res.append(values[i]);
}
return res;
}
/**
* The length of a given IntList object is determined
* #return the length of the list
*/
public int length() {
int counter = 1;
while(next != null) {
counter = counter + 1;
next = next.next;
}
return counter;
}
public IntList get(int i) {
for(int k = 0 ; k < i - 1 ; k ++) {
if(next != null) {
next = next.next;
}
}
return next;
}
public static void main(String[] args) {
IntList lst = new IntList(1, null);
for(int i = 2 ; i < 10 ; i ++) {
lst = lst.append(i);
}
System.out.println(lst);
System.out.println(lst.reverse());
System.out.println(lst.sum());
int[] values = new int[4];
values[0] = 3;
values[1] = 4;
values[2] = 5;
values[3] = 8;
System.out.println(fromArray(values));
System.out.println(lst.length());
System.out.println(fromArray(values).length());
System.out.println(lst.get(2));
}
}
Since my implementation of the list does not require two separate classes for nodes and the list itself, I cannot find any valuable information on the web (most people use two classes).
This one works without checking for IndexOutOfBoundsException:
public IntList get(int i) {
IntList current = this;
for(int k = 0 ; k < i - 1 ; k ++) {
if(current.next != null) {
current = current.next;
}
}
return current;
}
Your length method modifies next. Make it recursive (or make a new variable to step through your list):
public int length() {
if(next != null) {
return 1 + next.length();
}
else {
return 1;
}
}
Your get method also modifies the original list. Recursive solution is:
public IntList get(int i) {
if (i < 0) {
throw new IndexOutOfBoundsException("Index is negative!");
}
if (i == 0) {
return this;
} else if (next != null) {
return next.get(i - 1);
}
throw new IndexOutOfBoundsException("Index exceeds bounds");
}
I think you want something like this...
public IntList append(int info) {
if(next == null) {
return new IntList(info, this);
} else {
return new IntList(info, next);
}
}