private static int editDistance(ArrayList<String> s1, ArrayList<String> s2) {
if (s1.size()==0) {
return s2.size();
}
else if (s2.size()==0) {
return s1.size();
}
else {
String temp1 = s1.remove(s1.size()-1);
String temp2 = s2.remove(s2.size()-1);
if (temp1.equals(temp2)) {
return editDistance((ArrayList<String>)s1.clone(),(ArrayList<String>)s2.clone());
} else {
s1.add(temp1);
int first = editDistance((ArrayList<String>)s1.clone(),(ArrayList<String>)s2.clone())+1;
s2.add(temp2);
s1.remove(s1.size()-1);
int second = editDistance((ArrayList<String>)s1.clone(),(ArrayList<String>)s2.clone())+1;
s2.remove(s2.size()-1);
int third = editDistance((ArrayList<String>)s1.clone(),(ArrayList<String>)s2.clone())+1;
if (first <= second && first <= third ) {
return first;
} else if (second <= first && second <= third) {
return second;
} else {
return third;
}
}
}
}
For example, the input can be ["div","table","tr","td","a"] and ["table","tr","td","a","strong"] and the corresponding output should be 2.
My problem is when either input list has a size too big, e.g., 40 strings in the list, the program will generate a can't reserve enough space for object heap error. The JVM parameters are -Xms512m -Xmx512m. Could my code need so much heap space? Or it is due to logical bugs in my code?
Edit: With or without cloning the list, this recursive approach does not seem to work either way. Could someone please help estimate the total heap memory it requires to work for me? I assume it would be shocking. Anyway, I guess I have to turn to the dynamic programming approach instead.
You clone() each ArrayList instance before each recursive call of your method. That essentially means that you get yet another copy of the whole list and its contents for each call - it can easily add-up to a very large amount of memory for large recursion depths.
You should consider using List#sublist() instead of clone(), or even adding parameters to your method to pass down indexes towards a single set of initial List objects.
Related
I am in a book with this code. I do not know which command the ''depth'' word is used for what purpose. I have found a few results but I do not understand what is still. I know java language but i am learning c ++ new.I wanted to know if there is something like this in Java.
if (depth() != otherStack.depth())
{
return false;
}
else
{
for (int n=0; n<depth(); n++)
{
if (!list[n].equals(otherStack.list[n]))
return false;
}
}
From the code snippet you posted, depth seems to be a method defined in the class whose instance is the otherStack variable. Here depth() probably returns the size of the stack.
The line depth() != otherStack.depth() compares the size of the Stack instance to the size of another Stack instance.
Basically, I need to compare two arrays and check if they have the same values in the same positions (recursively of course). I get an error with my current code: Array out of index exception:20
The code I have right now looks as follows:
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd){
if (first[iStart] == second[iStart]){
if (equalsHelper(first,second,(iStart+1),iEnd))
{
return true;
}
}
if (iStart == iEnd){
return first[iEnd] == second[iEnd];
}
return false;
}
You simply need to put you stop condition at the begin of you code. This will work if iStart is 0 at the beginning and iEnd is array length - 1.
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) { // you need to check this first
return first[iEnd] == second[iEnd];
}
if (first[iStart] == second[iStart]) {
if (equalsHelper(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
If you want to use the array length as input for iEnd you just need to change the code a little
private boolean equalsHelper2(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) {
return true;
}
if (first[iStart] == second[iStart]) {
if (equalsHelper2(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
Since performance was mentioned a few times I will say a few things about it.
The stack contains information about local variables and function calls. So each recursiv call will save these informations on the stack which will lead to a stackoverflow on huge inputs since the stack only has limited space. It is also slower in terms of execution due to more assembler commands in comparison to loops.
This can be avoided by using tail recursive functions.
A tail recursive call means simply that your recursive call must be the last statement that is executed in your method. The compiler will translate this into a loop. This is faster and uses less space on the stack.
A tail recursive version of your equals method would look like this:
private boolean equalsHelper2(int[] first, int[] second, int iStart, int iEnd)
{
if (iStart == iEnd)
{
return true;
}else{
if(first[iStart] != second[iStart])
{
return false;
} else
{
return equalsHelper2(first, second, iStart + 1, iEnd);
}
}
}
Leaving aside the question of whether recursion is the right solution (it really isn't, iteration here is trivial and will perform better), the problem is that the termination condition (iStart == iEnd) is not checked until after the recursive call.
Any recursive algorithm must a) check whether it is appropriate to continue recursing, and b) do the recursive call after that check. Failing to include the first step, or doing the steps out of order, will result in infinite recursion until an error is reached (StackOverflowError if nothing else happens first).
You do have a condition check before your recursive call, but it's for the method's overall purpose rather than for ending recursion. You also have a condition check for ending recursion, but it's done after the recursive call. The solution is to swap their order - take the if (iStart == iEnd) block and move it to before the if (first[iStart] == second[iStart]) block.
Recursion is a powerful programming technique, but has some draw backs in the Java language. If a method in java calls itself recursively an excessive number of times before returning it will lead to a StackOverflowError. It this instance, comparing equality of two Array's is almost guaranteed to do so.
Other languages like Scala allow you to write recursive functions which are optimised for recursion (tail recursive) and execute in constant stack space.
That been said, you should think whether recursion is really the correct solution here. It neither optimises the solution, nor adds code clarity.
Note: If you just want to compare two Array's in Java, then java.util.Arrays already has you covered.
I am working on a school assignment. The objective is to practice GUI's, clone() methods, and using/ modifying existing code. I am trying to write an equals method in the way the instructor desires-- by using a clone of the object, removing items from the bag (returns boolean based on success or failure to remove).
The bag is represented in an array, and should return true in cases such as {1,2,3} and {3,2,1}, ie order does not matter, only the number of each number present in the arrays.
Here is the issue
It works in most cases, however there is a bug in cases where the bags contain numbers as such: {1,1,2} and {1,2,2} and other similar iterations. It is returning true instead of false.
I believe it has something to do with the remove() method we are supposed to use. If i understand it correctly, it is supposed to put the value at the 'end' of the array and decrease the manyItems counter (this is a variable for number of items in the array, because array.length is by default in the constructor 10.)
The code is largely written by another person. We had to import the existing files and write new methods to complete the task we were given. I have all the GUI part done so i will not include that class, only the used methods in the IntArrayBag class.
A second pair of eyes would be helpful. Thanks.
public class IntArrayBag implements Cloneable
{
// Invariant of the IntArrayBag class:
// 1. The number of elements in the bag is in the instance variable
// manyItems, which is no more than data.length.
// 2. For an empty bag, we do not care what is stored in any of data;
// for a non-empty bag, the elements in the bag are stored in data[0]
// through data[manyItems-1], and we don�t care what�s in the
// rest of data.
private int[ ] data;
private int manyItems;
public IntArrayBag( )
{
final int INITIAL_CAPACITY = 10;
manyItems = 0;
data = new int[INITIAL_CAPACITY];
}
public IntArrayBag clone( )
{ // Clone an IntArrayBag object.
IntArrayBag answer;
try
{
answer = (IntArrayBag) super.clone( );
}
catch (CloneNotSupportedException e)
{ // This exception should not occur. But if it does, it would probably
// indicate a programming error that made super.clone unavailable.
// The most common error would be forgetting the "Implements Cloneable"
// clause at the start of this class.
throw new RuntimeException
("This class does not implement Cloneable");
}
answer.data = data.clone( );
return answer;
}
public int size( )
{
return manyItems;
}
public boolean remove(int target)
{
int index; // The location of target in the data array.
// First, set index to the location of target in the data array,
// which could be as small as 0 or as large as manyItems-1; If target
// is not in the array, then index will be set equal to manyItems;
for (index = 0; (index < manyItems) && (target != data[index]); index++)
// No work is needed in the body of this for-loop.
;
if (index == manyItems)
// The target was not found, so nothing is removed.
return false;
else
{ // The target was found at data[index].
// So reduce manyItems by 1 and copy the last element onto data[index].
manyItems--;
data[index] = data[manyItems];
return true;
}
}
//I added extra variables that are not needed to try to increase readability,
//as well as when i was trying to debug the code originally
public boolean equals(Object obj){
if (obj instanceof IntArrayBag){
IntArrayBag canidate = (IntArrayBag) obj; // i know this can be changed, this was required
IntArrayBag canidateTest = (IntArrayBag) canidate.clone(); //this was created
//as a clone because it was otherwise referring to the same memory address
//this caused items to be removed from bags when testing for equality
IntArrayBag test = (IntArrayBag) this.clone();
//fast check to see if the two objects have the same number of items,
//if they dont will return false and skip the item by item checking
if (test.size() != canidateTest.size())
return false;
//the loop will go through every element in the test bag it will
//then remove the value that is present at the first index of the test bag
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
int check = test.data[i];
//remove() returns a boolean so if the value is not present in each bag
//then the conditional will be met and the method will return false
boolean test1 = test.remove(check);
boolean test2 = canidateTest.remove(check);
if (test1 != test2)
return false;
}//end for loop
// if the loop goes through every element
//and finds every value was true it will return true
return true;
}//end if
else
return false;
}//end equals
}
I cannot see the big picture, as I havent coded GUIs in Java before, however, as far as comparing 2 int[] arrays, I would sort the arrays before the comparison. This will allow you to eliminate problem cases like the one you stated ( if sorting is possible), then apply something like:
while(array_1[index]==array_2[index] && index<array_1.length)
{index++;}
and find where did the loop break by checking the final value of index
Is it explicitly stated to use clone? You can achieve it easily by overriding the hashCode() for this Object.
You can override the hashCode() for this object as follows:
#Override
public int hashCode() {
final int prime = 5;
int result = 1;
/* Sort Array */
Arrays.sort(this.data);
/* Calculate Hash */
for(int d : this.data) {
result = prime * result + d;
}
/* Return Result */
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || this.getClass() != obj.getClass()){
return false;
}
return false;
}
If you want to continue using your implementation for equals to compare test and CandidateTest then also you can compute unique hashes and make decision based on the results.
Here is the code snippet:
/* Assuming that you have put size comparison logic on top
and the two objects are of same size */
final int prime = 31;
int testResult = 1;
int candidateTestResult = 1;
for(int i = 0; i < test.size(); i++) {
testResult = prime * testResult + test.data[i];
candidateTestResult = prime * candidateTestResult + candidateTest.data[i];
}
/* Return Result */
return testResult == candidateTestResult;
I believe the problem is in this line:
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
The problem here is that test and canidateTest are the clones that you made, and you are removing elements from those bags. And any time you remove an element from the bag, the size will decrease (because you decrease manyItems, and size() returns manyItems). This means you're only going to go through half the array. Suppose the original size is 4. Then, the first time through the loop, i==0 and test.size()==4; the second time, i==0 and test.size()==3; the third time, i==2 and test.size()==2, and you exit the loop. So you don't look at all 4 elements--you only look at 2.
You'll need to decide: do you want to go through the elements of the original array, or the elements of the clone? If you go through the elements of the clone, you actually never need to increment i. You can always look at test.data[0], since once you look at it, you remove it, so you know test.data[0] will be replaced with something else. In fact, you don't need i at all. Just loop until the bag size is 0, or until you determine that the bags aren't equal. On the other hand, if you go through the elements of this.data (i.e. look at this.data[i] or just data[i]), then make sure i goes all the way up to this.size().
(One more small point: the correct spelling is "candidate".)
Maybe you should try SET interface
view this in detail :http://www.tutorialspoint.com/java/java_set_interface.htm
A set object cannot contains duplicate elements, so it's suitable for your assignment than build your own class.
For example:[1,1,2] and [1,2,2]
you can use this to test whether they are equal
arr1 = {1,1,2}
arr2 = {1,2,2}
Set<Integer> set = new HashSet<Integer>();
for(int i : arr1){//build set of arr1
if(set.contains(i)==false){
set.add(i)
}
}
for(int i:arr2){
if(set.contains(i)==false){
System.out.println('not equal');
break;
}
}
Hope this is helpful.
I have several vectors of different elements but all extending a class which has a specific function, lets say for example
Vector<classone> one;
Vector<classtwo> two;
Vector<classthree> three;
and classone, classtwo and classthree extend Number, and number has two functions:
doThing()
getValue()
And what i want is to call doThing in the order of the getValues received from all the vectors.
One cheap solution would be to concatenate all the vectors in a single Vector, sort it by value and iterate to call the function, but that makes me have to create a huge new vector, occupying new ram, and since the doThing will happen 60 times a second, if the vectors become big, it might be an overkill, i dont really want to create a new vector just to sort it, is there any other solution using the already existing vectors?
Its Java btw.
If one, two and three are sorted, you could create an custom iterator that checks for a given set of lists what the smallest value at the current position is and proceed there.
Should look similar to this (not tested):
class MultiListIterator {
List<Number>[] lists;
int[] positions;
MultiListIterator(List<Number>... lists) {
this.lists = lists;
positions = new int[lists.length];
}
boolean hasNext() {
for (int i = 0; i < lists.length; i++) {
if (positions[i] < lists[i].length) return true;
}
return false;
}
Number next() {
int bestIndex = -1;
Number bestNumber = null;
for (int i = 0; i < lists.length; i++) {
var p = positions[i];
if (p >= positions[i].length) continue;
Number n = lists[i].get(p);
if (bestNumber == null || n.getValue() < bestNumber.getValue()) {
bestIndex = i;
bestNumer = n;
}
}
if (bestNumber == null) throw new RuntimeException("next() beyond hasNext()");
positions[bestIndex++];
return bestNumber;
}
}
Usage:
MultiListIterator mli = new MultiListIterator(one, two, three);
while (mli.hasNext()) {
mli.next().doThing();
}
You may want to let MultiListIterator implement Iterator<Number>.
Note that Java already has a built-in class Number. Using the same name for your class might lead to a lot of confusion when you forget to import it somewhere.
Premature optimizations are generally a bad idea.
Try the method that came to mind first: creating a giant Vector1 ArrayList and sorting it. If it turns out to be a performance issue, then you can start trying new things.
I'm having trouble working out how to count instances of Values in a HashMap.
I have seen that there is methods attached to the Object class that look as if they are able to help me, so I've tried to cast those in to work but I must be doing something wrong somewhere.
If there's an easier way, I haven't found it yet. NB: Library is my HashMap.
public void borrowBooks(String id, String name, String sid, String sname) {
if((getKeyFromValue(Books, name).equals(id))&&(getKeyFromValue(Students, sname).equals(sid))){
if((Object)Library.countValues(sid)!=5){
Library.put(id, sid);
}
else{
System.out.println("You have exceeded your quota. Return a book before you take one out." );
}
}
}
Which doc are you looking at ? The Javadoc for Hashmap doesn't specify a countValues() method.
I think you want a HashMap<String, List<String>> so you store a list of books per student (if I'm reading your code correctly).
You'll have to create a list per student and put that into the HashMap, but then you can simply count the entries in the List using List.size().
e.g.
if (Library.get(id) == null) {
Library.put(id, new ArrayList<String>());
}
List<String> books = Library.get(id);
int number = books.size() // gives you the size
Ignoring threading etc.
First: There is (almost) no point in ever casting anything to Object. Since everything extends Object, you can always access the methods without casting.
Second: The way you're casting actually casts the return value, not the Library. If you were doing a cast that was really necessary, you would need an extra set of parentheses:
if(((Object)Library).countValues(sid) != 5)
Third: There is no countValues method in either HashMap or Object. You'll have to make your own.
This is the general algorithm to use (I'm hesitant to post code because this looks like homework):
initialize count to 0
for each entry in Library:
if the value is what you want:
increment the count
int count = 0;
for(String str : Library.values())
{
if(str == sid)
count++;
if(count == 5)
break;
}
if(count < 5)
Library.put(id, sid);
else
System.out.println("You have exceeded your quota. Return a book before you take one out." );