Good day,
Here is my code:
public class ArrayDirectory implements Directory {
private int allocatedSize = 0;
public Entry[] entryDirectory = new Entry[allocatedSize];
#Override
public void addEntry(Entry newEntry) {
newEntry = findFreeLocation();
entryDirectory = Arrays.copyOf(entryDirectory,
entryDirectory.length + 1);
}
private Entry findFreeLocation() {
Entry returnedEntry = new Entry();
for (int i = 0; i < entryDirectory.length; i++) {
if (entryDirectory[i] == null) {
break;
}
returnedEntry = entryDirectory[i];
}
return returnedEntry;
}
I've made the size of the entryDirectory dynamic; it increments each time the addEntry method is used. However, when I am trying to call a method of an entry object from the entryDirectory array, a NullPointerException is thrown.
public static void main(String[] args) {
ArrayDirectory d = new ArrayDirectory();
d.addEntry(new Entry("Jack", "Jones", 1234));
d.addEntry(new Entry("Brad", "Jones", 1234));
d.addEntry(new Entry("Olga", "Jones", 1234));
System.out.println(d.entryDirectory[0].getInitials());
}
Here is the getInitials() method of the Entry object.
public Entry(String surname, String initials, int extension){
this.surname = surname;
this.initials = initials;
this.extension = extension;
}
public String getInitials() {
return initials;
}
You never assign anything as element of your array entryDirectory, so NullPointerException arises when you try to invoke getInitials() on null-value object entryDirectory[0].
Remember that if you use Arrays.copyOf(),
for any indices that are valid in the copy but not the original, the
copy will contain null
See Arrays javadoc
In addition to Philip Voronov's answer, your findFreeLocation method is also implemented incorrectly. Assuming null means an absence of value, the proper implementation should be like this:
private int findFreeLocation() {
for (int i = 0; i < entryDirectory.length; i++) {
if (entryDirectory[i] == null) {
return i
}
}
return -1;
}
You can then use it like this:
public void addEntry(Entry newEntry) {
int loc = findFreeLocation();
if (loc >= 0) {
entryDirectory[loc] = newEntry;
} else {
entryDirectory = Arrays.copyOf(entryDirectory, entryDirectory.length + 1);
entryDirectory[entryDirectory.length - 1] = newEntry;
}
}
That said, I highly suggest you use a built-in collection, like ArrayList, to handle automatically resizing arrays. They are much easier to use, and their performance is also better (increasing the array size by one means you have to resize every time an item is added, in comparison to ArrayList's implementation, which doubles the size every time it fills up).
Related
I've read up on the wiki page on creating a extendable hashtable Extendable Hashing. And now i'm trying to implement that into a program to better understand it but I can't figure out how to actually point the directories towards the buckets.
Directory class:
int GlobalDepth = 1;
int directories[];
public Directory() {
int temp = (int)Math.pow(2, GlobalDepth);
loadDirectories(temp);
}
public void loadDirectories(int n) {
for (int i = 0; i < n; i ++) {
String BinaryKey = Integer.toBinaryString(i);
String tempKey = BinaryKey.substring(0, this.GlobalDepth); // LSB
int depthKey = Integer.parseUnsignedInt(tempKey);
this.directories[i] = depthKey;
}
}
public void increaseGlobalDepth() {
this.GlobalDepth ++;
loadDirectories((int)(Math.pow(2, this.GlobalDepth))); // This method might throw an error because i think im changing the array size illegally and should instead create a temp array and copy/equal that array to this.directories
}
Bucket class:
private SomeObject[] item; // Class I'm using to hold all the information of something
private int Key, MaxBucketsize, LocalDepth = 1;
//Bucket next;
public Bucket() {
}
public Bucket(int BucketSize) {
this.item = new SomeObject[BucketSize]; // Initalises the number of items held in the bucket
this.MaxBucketsize = BucketSize; // Stores the max number of items that can be held in the bucket
}
public SomeObject[] getObjects() {
return this.item;
}
public boolean addObjects(int key, SomeObject item) {
boolean inserted = false;
for (int i = 0; i < this.MaxBucketsize; i ++) {
if (this.item[i] == null) { // only inserts if there is an empty spot in the bucket
this.item[i] = item;
this.item[i].setKey(key);
inserted = true;
break;
}
}
return inserted;
}
After doing all this, I'm not sure how to now link the 2 together like in the wiki page.
I've got array. I've got an isFull method, which checks if the array is full, but I don't know how to use this to check if it's full, then if it's not full add to the array, otherwise disregard the add call.
The array should take 10 elements and then not accept any more. After 10 elements, it should 'be full' and disregard any addSpy calls.
How would you implement this?
public class ConcreteSubject extends AbstractSubject {
public int arySize;
private int i = 0;
private static AbstractSpy[] spies;
public ConcreteSubject(int a) {
arySize = a;
spies = new AbstractSpy[a];
}
#Override
public void addSpy(AbstractSpy spy) {
if (spies.length < 10) {
spies[i] = spy;
System.out.println("spy added at index " + i);
i++;
}
}
public void isFull() {
//1
boolean b = false;
for (int i = 0; i < spies.length; i++) {
if (spies[i] == null) {
b = true;
}
}
if (!b) {
System.out.println("Array is full");
} else {
System.out.println("Array not full");
}
}
public class TestSpies {
public static void main(String[] args) {
ConcreteSubject cs = new ConcreteSubject(10);
AbstractSpy spy = new ConcreteSpy();
AbstractSpy[] spies = new AbstractSpy[10];
cs.addSpy(spy);
cs.addSpy(spy);
cs.addSpy(spy);
cs.isFull();
}
}
spies.length < 10 isn't correct. It should be spies.length > 0 && i < spies.length to make sure that the following assignment spies[i] = spy; is always valid.
void isFull() should be boolean isFull(). Your implementation looks OK, just return b. full is a tricky word because technically an array is always "full". A better adjective would be populated, filled.
Since addSpy isn't filling null gaps but simply adds a spy to the end, isFull could be rewritten to return spies.length == i;.
The simplest way of doing it would be like that:
#Override
public void addSpy(AbstractSpy spy) {
if (!isFull())
{
spies[i] = spy;
System.out.println("spy added at index " + i);
i++;
}
}
To use that, you should change your isFull method to:
public boolean isFull() {
for (int i = 0; i < spies.length; i++) {
if (spies[i] == null) {
return false;
}
}
return true;
}
Keep a track of the number of filled cells of the array using a variable. And before inserting anything into it, check if the filled cells count strictly less than the size of the array (obviously you want to keep track of the array total size as well).
In my java class, we are using junit test to test our methods. This section introduced using an interface.
this specific method I am having problems on is supposed to search an array at each index, looking for a matching string as the input.
In the junit test I have
void test()
{
MyClassList labTest = new MyClassList("CIS 120", "Fall", "Professor Awesome");
MyStudent george = new MyStudent("George","Lucas", "555-555-5555","george.lucas#starwars.com");
MyStudent gene = new MyStudent("Gene", "Roddenberry","666-666-6666", "gene.roddenberry#startrek.com");
MyStudent jordan = new MyStudent("Jordan" ,"Robberts", "755-555-5555", "jordan.robberts#wheeloftime.com");
labTest.insert(george);
labTest.insert(gene);
labTest.insert(jordan);
System.out.println(labTest.toString());
System.out.println(labTest.contains(george));
System.out.println(labTest.search("George"));
This is the code U have for the method search:
Note
protected MyStudent [] log;
protected int lastIndex = -1;
are global variables
package Lab2;
import java.util.Arrays;
import java.util.Scanner;
import Lab2.ClassListInterFace;
public class MyClassList implements ClassListInterFace {
protected String course;
protected String semester;
protected String teacherLastName;
protected MyStudent[] log;
protected int lastIndex = -1;
public MyClassList(String currCourse, String currSemester, String lastName, int maxSize) {
log = new MyStudent[maxSize];
this.course = currCourse;
this.semester = currSemester;
this.teacherLastName = lastName;
}
public MyClassList( String currCourse, String currSemester, String lastName)
{
log = new MyStudent[100];
this.course = currCourse;
this.semester = currSemester;
this.teacherLastName = lastName;
}
public void insert(MyStudent element) {
lastIndex++;
log[lastIndex] = element;
}
public boolean isFull() {
if (lastIndex == (log.length - 1))
return true;
else
return false;
}
public int size() {
return (lastIndex + 1);
}
public void clear()
{
for (int i = 0; i <= lastIndex; i++)
log[i] = null;
lastIndex = -1;
}
public String getName() {
return teacherLastName;
}
public boolean contains(MyStudent element) {
boolean found = false;
for( int location = 0;location <= lastIndex; location++)
{
if (element.equals(log[location])) // if they match
found = true;
}
return found;
}
public String toString()
{
String message = "Course " + course + "\n Semester " + semester + "\n Proffessor " + teacherLastName + "\n";
for (int i = 0; i <= lastIndex; i++) {
message += log[i].toString();
}
return message;
}
public int search(String x)
{
int answer = 0;
for(int i = 0; i < log.length; i++)
{
if(x.equalsIgnoreCase(log[i]))
answer++;
}
return answer;
}
I got this based off some code that the teacher gave us for reference, and I tweaked it a little.
This looks like something that can be done much more elegantly with a for loop. In my experience, using a more concise control structure designed for things like this can lead to far fewer chances of errors. While I'm not sure what exact issue you are looking for help with, I do notice that if you do find a match, you skip the next element without checking to see if it is also a match.
int location = 0;
while (location <= lastIndex)
{
if (x.equalsIgnoreCase(log[location]))
{ // if they match
answer ++;
location ++; //<-- Here's where you increment twice upon finding a match!
}
location++; //To fix with the smallest number of changes, just put this in an else clause
}
This entire block can be reduced to approximately half the lines and half the variables by changing it up to be a for loop. See below:
for(int i = 0; i < log.length; i++) {
if(x.equalsIgnoreCase(log[i].firstName))
answer++;
}
This is much easier to read, and far less prone to errors. Trying to keep track of an excessive number of variables or dividing out common operations (such as incrementing where you are) is just asking for issues. This four-liner is functionally equivalent to your above code block (aside from the fact it doesn't skip the following entry when it finds a match), yet has far fewer opportunities for a programmer to make a mistake. Always, when you can get away with it, use the control flow structure designed for the task.
I have made an inheritance hierarchy with one super-class called Employe and two subclasses called Lecturer and Assistant. In addition to this I made a class called Subject which has an array of employees.
What I want to do here is create a method for adding Employe objects into the array.
I made the same one that works for ArrayList, but it didn't seem to work for Arrays.
If it is possible, how can I create a method for doing the same thing with arrays?
public class Subject {
private String subjectcode;
private Employe[] employees;
public Subject(String subjectcode) {
this.subjectcode = subjectcode;
Employe[] employees = new Employe[5];
}
public void setSubjectcode(String code) {
this.subjectcode = code;
}
public String getSubjectcode() {
return this.subjectcode;
}
public boolean addStaff(Employe employe) {
if (employe instanceof Lecturer || employe instanceof Assistant) {
this.employees.add(employe);
return true;
} else {
return false;
}
}
}
You need to use an ArrayList :
public class Subject
{
private String subjectcode;
private final List<Employee> employees = new ArrayList<Employee>();
public Subject(String subjectcode){
this.subjectcode = subjectcode;
}
public boolean addStaff(Employe employe){
return this.employees.add(employe);
}
Or if you still want to use an array :
public boolean addStaff(Employe employe){
List<Employee> tempList = Arrays.asList(this.employees);
boolean added = tempList.add(employe);
this.employees = tempList.toArray(this.employees);
return added;
}
Arrays cannot grow or shrink dynamically by themselves as ArrayLists do, that's why the don't have add() method — it'd stop working after array instance is full.
What you have with arrays are, essentially, a get(index) and set(index, value), so when you know that you will have at maximum N employees, Subject may look like this:
public class Subject {
private static final int N = 5;
private String subjectcode;
private Employe[] employees = new Employe[N];
private int size = 0;
public Subject(String subjectcode){
this.subjectcode = subjectcode;
}
public void setSubjectcode(String code){
this.subjectcode = code;
}
public String getSubjectcode(){
return this.subjectcode;
}
public boolean addStaff(Employe employe){
if (size == employees.length) {
// cannot add when is full
return false;
}
if(employe instanceof Lecturer || employe instanceof Assistant){
this.employees[size++] = employe;
return true;
}
return false;
}
}
On the other hand, if you don't know how many employees Subject may have even at a time when Subject is created (if you'd know it, you may pass N as a constructor argument), you'd have to implement method for growing internal array and call it whenever new employe is added, which may look like this:
private void ensureCapacity(int n) {
int oldCapacity = employees.length;
if (oldCapacity >= n) {
// there's nothing to do
return;
}
// grow at least in half, to minimize copying data on each add
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - n < 0)
newCapacity = n;
employees = Arrays.copyOf(employees, newCapacity);
}
public boolean addStaff(Employe employe) {
ensureCapacity(size + 1);
if (employe instanceof Lecturer || employe instanceof Assistant) {
this.employees[size++] = employe;
return true;
}
return false;
}
For better example of growing arrays see default implementation of ArrayList's ensureCapacity(int minCapacity) in JDK.
But again, this growing-shrinking stuff is just reimplementing what is done already in ArrayList for you.
In case of Java arrays, unlike ArrayList you do not have add method. So, you cannot add like it. Array operates as below:
String[] employees = new String[5];
employees[0] = "ad";
So, array needs index based approach, where you specify that at index 0 put this element, at index 1 put this element, and so on .... employees[0] = "as";
In your case, why you need to use array? I think ArrayList fits best, as per information you have provided.
I have a filter class wherein the user must declare the type (e.g. Filter<Double>, Filter<Float> etc). The class then implements a moving average filter so objects within the class must be added. My question is how to do this? I'm sorry if the answer is simple but I've muddled myself up by thinking about it too much I think :p.
public abstract class FilterData<T>
{
private final List<T> mFilter;
private T mFilteredValue; // current filtered value
protected Integer mSize = 10;
private T mUnfilteredValue; // current unfiltered value
public FilterData()
{
mFilter = new ArrayList<T>();
}
public FilterData(int size)
{
mSize = size;
mFilter = new ArrayList<T>(mSize);
}
public abstract T add(final T pFirstValue, final T pSecondValue);
#SuppressWarnings("unchecked")
public T filter(T currentVal)
{
T filteredVal;
mUnfilteredValue = currentVal;
push(currentVal);
T totalVal = (T) (new Integer(0));
int numNonZeros = 1;
for (int i = 0; i < mFilter.size(); ++i)
{
if (mFilter.get(i) != (T) (new Integer(0)))
{
++numNonZeros;
T totalValDouble = add(mFilter.get(i), totalVal);
totalVal = totalValDouble;
}
}
Double filteredValDouble = (Double) totalVal / new Double(numNonZeros);
filteredVal = (T) filteredValDouble;
mFilteredValue = filteredVal;
return filteredVal;
}
public T getFilteredValue()
{
return mFilteredValue;
}
public List<T> getFilterStream()
{
return mFilter;
}
public T getUnfilteredValue()
{
return mUnfilteredValue;
}
public void push(T currentVal)
{
mFilter.add(0, currentVal);
if (mFilter.size() > mSize)
mFilter.remove(mFilter.size() - 1);
}
public void resizeFilter(int newSize)
{
if (mSize > newSize)
{
int numItemsToRemove = mSize - newSize;
for (int i = 0; i < numItemsToRemove; ++i)
{
mFilter.remove(mFilter.size() - 1);
}
}
}
}
Am I right to include the abstract Add method and if so, how should I extend the class correctly to cover primitive types (e.g. Float, Double, Integer etc.)
Thanks
Chris
EDIT:
Apologies for being unclear. This is not homework I'm afraid, those days are long behind me. I'm quite new to Java having come from a C++ background (hence the expectation of easy operator overloading). As for the "push" method. I apologise for the add method in there, that is simply add a value to a list, not the variable addition I was referring to (made a note to change the name of my method then!). The class is used to provide an interface to construct a List of a specified length, populate it with variables and obtain an average over the last 'x' frames to iron out any spikes in the data. When a new item is added to the FilterData object, it is added to the beginning of the List and the last object is removed (provided the List has reached the maximum allowed size). So, to provide a continual moving average, I must summate and divide the values in the List.
However, to perform this addition, I will have to find a way to add the objects together. (It is merely a helper class so I want to make it as generic as possible). Does that make it any clearer? (I'm aware the code is very Mickey Mouse but I wanted to make it as clear and simple as possible).
What you're trying to do is create a Queue of Number objects with a fixed size, over which you want to calculate an average. With the trivial situation that you have size = 2 and store two integers 1 & 2 you have an average of 1.5 so its reasonable to set the return type of your filter method to double.
You can then write this code similar to this
public abstract class FilterData<T extends Number> {
private final Queue<T> mFilter = new LinkedList<T>();
protected Integer mSize;
public FilterData() {
this(10);
}
public FilterData(int size) {
mSize = size;
}
public double filter(T currentVal) {
push(currentVal);
double totalVal = 0d;
int numNonZeros = 0;
for (T value : mFilter) {
if (value.doubleValue() != 0) {
++numNonZeros;
totalVal += value.doubleValue();
}
}
return totalVal / numNonZeros;
}
public void push(T currentVal) {
mFilter.add(currentVal);
if (mFilter.size() > mSize)
mFilter.remove();
}
public void resizeFilter(int newSize) {
if (mSize > newSize) {
int numItemsToRemove = mSize - newSize;
for (int i = 0; i < numItemsToRemove; ++i) {
mFilter.remove();
}
}
mSize = newSize;
}
}
You should note that this isn't thread safe.