I have a class that implements an interface and I think when I try to insert an element into the array more than once the first insertions are forgotten. I really can't figure this one out. This is what I have:
public void insertElementAt(int index, E el)
throws IllegalArgumentException {
Object temp[] = new Object[data.length + 1];
for (int i = 0; i < data.length; i++) {
if (i == index){
temp[index] = el;
temp[i + 1] = data[i];
i++;
}
temp[i] = data[i];
}
data = temp;
if (index > data.length || index < 0) {
throw new IllegalArgumentException();
}
}
Then my test reports null instead of first at he last assertion.
#Test
public void testInsertToLeft() {
PriorityList<String> list = new ArrayPriorityList<String>();
list.insertElementAt(0, "First");
// Must shift array elements in this case
list.insertElementAt(0, "New First");
assertEquals("New First", list.getElementAt(0));
assertEquals("First", list.getElementAt(1));
}
You must do like this:
public void insertElementAt(int index, E el) throws IllegalArgumentException {
Object temp[] = new Object[data.length + 1];
for (int i = 0; i < data.length; i++) {
if (i >= index){
temp[i + 1] = data[i];
} else {
temp[i] = data[i];
}
}
temp[index] = el;
data = temp;
if (index > data.length || index < 0) {
throw new IllegalArgumentException();
}
}
To remove it:
public void removeElementAt(int index) throws IllegalArgumentException {
Object temp[] = new Object[data.length - 1];
for (int i = 0; i < temp.length; i++) {
if (i > index){
temp[i - 1] = data[i];
} else {
temp[i] = data[i];
}
}
data = temp;
if (index > data.length || index < 0) {
throw new IllegalArgumentException();
}
}
Try changing your for loop to either:
for (int i = 0; i < data.length; i++) {
if (i == index){
temp[index] = el;
temp[i + 1] = data[i];
i++;
}else{
temp[i] = data[i];
}
}
or
for (int i = 0; i < data.length; i++) {
if (i == index){
temp[index] = el;
temp[i + 1] = data[i];
i++;
continue;
}
temp[i] = data[i];
}
What is data.length when the list is empty? If it is empty at first insertion you will not enter the for loop but copy the temp array, it will go into the loop at next insertion with length 1. The first insertion will be skipped.
I would do this:
public static void insertElementAt(int index, E el)
throws IllegalArgumentException {
if (index > data.length || index < 0) {
throw new IllegalArgumentException();
}
Object temp[] = new Object[data.length + 1];
for (int i = index; i < data.length; i++) {
temp[i+1] = data[i];
}
temp[index] = el;
data = temp;
}
You should have the test for valid parameters first ("fail early"), and you can make good use of the JDK's utility methods do the lifting for you:
public static void insertElementAt(int index, E el) {
if (index > data.length || index < 0) {
throw new IllegalArgumentException();
}
data = Arrays.copyOf(data, data.length + 1);
System.arrayCopy(data, index, data, index + 1, data.length - index);
data[index] = el;
}
Also note you don't need to declare a throws, becauseIllegalArgumentException is an unchecked exception, so I removed it. Normally, one follows this pattern.
Related
I am working on sorting algorithms and I am trying to improve mergeSort by locating already sorted subArrays.
public static void mergeSort(int[] array)
{
if(array == null)
{
return;
}
if(array.length > 1)
{
int mid = array.length / 2;
// left
int[] left = new int[mid];
for(int i = 0; i < mid; i++)
{
left[i] = array[i];
}
//right
int[] right = new int[array.length - mid];
for(int i = mid; i < array.length; i++)
{
right[i - mid] = array[i];
}
//recursively calls
mergeSort(left);
mergeSort(right);
int i = 0;
int j = 0;
int k = 0;
// left and right merged
while(i < left.length && j < right.length)
{
if(left[i] < right[j])
{
array[k] = left[i];
i++;
}
else
{
array[k] = right[j];
j++;
}
k++;
}
// left overs
while(i < left.length)
{
array[k] = left[i];
i++;
k++;
}
while(j < right.length)
{
array[k] = right[j];
j++;
k++;
}
}
}
What you are looking for is called natural merge sort. Before you start with sorting the dataset you will do one run to identify all the presorted data. The mergesort itself stays the same.
I found some example code for you at: happycoders
package eu.happycoders.sort.method.mergesort;
import eu.happycoders.sort.method.Counters;
import eu.happycoders.sort.method.SortAlgorithm;
/**
* Natural merge sort implementation for performance tests.
*
* #author Sven Woltmann
*/
public class NaturalMergeSort implements SortAlgorithm {
#Override
public void sort(int[] elements) {
int numElements = elements.length;
int[] tmp = new int[numElements];
int[] starts = new int[numElements + 1];
// Step 1: identify runs
int runCount = 0;
starts[0] = 0;
for (int i = 1; i <= numElements; i++) {
if (i == numElements || elements[i] < elements[i - 1]) {
starts[++runCount] = i;
}
}
// Step 2: merge runs, until only 1 run is left
int[] from = elements;
int[] to = tmp;
while (runCount > 1) {
int newRunCount = 0;
// Merge two runs each
for (int i = 0; i < runCount - 1; i += 2) {
merge(from, to, starts[i], starts[i + 1], starts[i + 2]);
starts[newRunCount++] = starts[i];
}
// Odd number of runs? Copy the last one
if (runCount % 2 == 1) {
int lastStart = starts[runCount - 1];
System.arraycopy(from, lastStart, to, lastStart,
numElements - lastStart);
starts[newRunCount++] = lastStart;
}
// Prepare for next round...
starts[newRunCount] = numElements;
runCount = newRunCount;
// Swap "from" and "to" arrays
int[] help = from;
from = to;
to = help;
}
// If final run is not in "elements", copy it there
if (from != elements) {
System.arraycopy(from, 0, elements, 0, numElements);
}
}
private void merge(int[] source, int[] target, int startLeft,
int startRight, int endRight) {
int leftPos = startLeft;
int rightPos = startRight;
int targetPos = startLeft;
// As long as both arrays contain elements...
while (leftPos < startRight && rightPos < endRight) {
// Which one is smaller?
int leftValue = source[leftPos];
int rightValue = source[rightPos];
if (leftValue <= rightValue) {
target[targetPos++] = leftValue;
leftPos++;
} else {
target[targetPos++] = rightValue;
rightPos++;
}
}
// Copy the rest
while (leftPos < startRight) {
target[targetPos++] = source[leftPos++];
}
while (rightPos < endRight) {
target[targetPos++] = source[rightPos++];
}
}
#Override
public void sort(int[] elements, Counters counters) {
// Not implemented
}
}
Lets say I have a class called "Sequence". This class has an instance variable private int[] tab.
There are also some methods to create this tab like those:
public Sequence() {
this.tab = fillAnArray(drawsNumber(5, 20));
}
private int drawsNumber(int min, int max) {
if (min > max) {
throw new IllegalArgumentException("Wrong range");
}
return new Random().nextInt(max - min + 1) + min;
}
public int[] fillAnArray(int size) {
int[] arr = new int[size];
arr[0] = 1;
for (int i = 1; i < arr.length; i++) {
arr[i] = drawsNumber(arr[i - 1], arr[i - 1] + 10);
}
return arr;
}
Now, I would like to create the method that accepts two Sequence objects as arguments and returns number of the same tab elements. So, I created method like this:
public int howManyCommonElements(Sequence c1, Sequence c2) {
int i = 0, j = 0;
int counter = 0;
while (i < c1.tab.length && j < c2.tab.length) {
if (c1.tab[i] == c2.tab[j]) {
++counter;
} else if (c1.tab[i] < c2.tab[j]) {
++i;
} else {
++j;
}
}
return counter;
}
How do I compare single elements like c1.tab[i], c2.tab[j]?
You have to compare every element of the 1st array with every element of the 2nd one. To do that you have to use 2 nested for cycles:
for (int i = 0; i < c1.tab.length; i++)
for (int j = 0; j < c2.tab.length; j++)
if (c1.tab[i] == c2.tab[j])
++counter;
If you have ordered elements (ASC), you can do like;
int i = 0, j = 0;
int counter = 0;
while (i < arr1.length && j < arr2.length) {
if (arr1[i] == arr2[j]) {
++i;
++j;
++counter;
} else if (arr1[i] < arr2[j]) {
++i;
} else {
++j;
}
}
I'm trying to make a method that creates a new array containing the index of every occurrence of a target value. I have to use 2 loops for this. The first counts how many times the target occurs. Then create the new array, to hold this many indexes. Then the second loop puts the indexes into the new array.
I've written the code below, but it throws java lang Array Out Of Bound Exception:5, on the line result [ i ] = f [ i ] ;
public class FindAll {
public FindAll() {
int a[] = {7, 8, 9, 9, 8, 7};
print(findAll(a, 7));
print(findAll(a, 2));
}
public void print(int p[]) {
System.out.print("{");
int i;
for (i = 0; i < p.length - 1; ++i) {
System.out.print(p[i] + ", ");
}
System.out.print(p[i]);
System.out.print("}");
}
public int[] findAll(int f[], int target) {
int count = 0;
for (int i = 0; i < f.length; ++i) {
if (f[i] == target) {
count++;
}
}
int result[] = new int[count];
for (int i = 0; i < f.length; ++i) {
if (f[i] == target) {
result[i] = f[i];
}
}
return result;
}
}
Try this
int result[] = new int[count];
int index = 0;
for (int i = 0; i < f.length; i++)
{
if (f[i] == target){
result[index] = f[i];
index++;
}
}
Replace the findAll function with this
public int[] findAll(int f[], int target) {
int count = 0;
for (int i = 0; i < f.length; ++i) {
if (f[i] == target)
count++;
}
if(count == 0) return null;
int result[] = new int[count];
for (int i = 0, curr = 0; i < f.length; ++i) {
if (f[i] == target)
result[curr++] = i;
// Here you have to store the index not the value
}
return result;
}
Add these lines to print method to avoid an exception when the array is null
if(p == null || p.length == 0){
System.out.println("P is null or empty");
return;
}
It will work fine!
The result array you are creating is the size of the number of occurrences of the target, not the size of the original array.
public int[] findAll(int f[], int target)
{
int count = 0;
for (int i = 0; i < f.length; ++i)
{
if (f[i] == target)
count++;
}
int result[] = new int[count]; // This is the size of number of occurrences of target
for (int i = 0; i < f.length; ++i) // 'i' will go up to size of original array
{
if (f[i] == target)
result[i] = f[i]; // You are trying to put the element of the original array in to the same index of your result!?
}
return result;
}
Instead, you need to be adding, for each target element, it's index:
int resultIndex = 0;
for (int i = 0; i < f.length; i++) {
if ( f[i] == target ) {
result[n] = i;
n++;
}
}
This feature is supposed to add an element at the selected index and push all other in the array elements down. So, for instance, say I have the following array:
[0] = zero
[1] = one
[2] = two
if I add another element at index 0 called NEWZERO, the array has to look like this:
[0] = NEWZERO
[1] = zero
[2] = one
[3] = two
but currently I'm getting IndexOutOfBounds exception and it doesn't work.
P.S. I don't want to use the built-in ArrayList library, which automatically does it for you.
public void insert(int i, String s) {
if (array[i] == null) {
array[i] = s; //Need to add feature that instantly puts the element at the first available spot on the list.
} else {
for (int j = i; j < array.length; j++) { //Can't use >= i
array[j + 1] = array[j];
if (j == array.length - 1) {
break;
}
}
array[i] = s;
Try this
public void insert(int i, String s) {
String[] newArr = new String[array.length + 1];
for (int j = 0; j < array.length; j++) {
if(j < i){
newArr[j] = array[j];
} else if(j == i){ // '==' insted of '='
newArr[j] = s;
} else {
newArr[j+1] = array[i];
}
}
array = newArr;
}
Well, arrays are not dynamic, so if you have an array that has size 3 you cannot add anything to it unless you create a new array that has size of oldArray.length+1 and then populate it with new data.
public static int[] addAtIndex(int[] a, int index, int value) {
int[] newArr = new int[a.length + 1];
int temp;
for (int j = 0; j < a.length + 1; j++) {
if (j < index) {
newArr[j] = a[j];
} else if (j == index) {
//copy value at index to temp so that value added at specific index can be shifted right
temp = a[j];
newArr[j] = value;
newArr[j + 1] = temp;
} else {
newArr[j] = a[index];
index++;
}
}
return newArr;
}
I'm writing a merge sort class in java and i get a stack overflow error when I get to the sort(left) line. Any thoughts? I don't understand why this would be a problem.
package ds;
import java.util.Comparator;
public class MergeSorter<T> extends Sorter<T> {
public MergeSorter(Comparator<T> comparator){
super(comparator);
}
#SuppressWarnings("unchecked")
#Override
public void sort(T[] array){
if (array.length <= 1);
else {
T[] left = (T[]) new Object[array.length/2 + 1];
T[] right = (T[]) new Object[array.length/2 + 1];
int middleIndex = array.length / 2;
for (int i = 0; i < middleIndex; i++) {
left[i] = array[i];
}
for (int i = middleIndex; i < array.length; i++) {
right[i - middleIndex] = array[i];
}
sort(left);
sort (right);
merge(left, right, array);
}
}
public final void merge(T[] left, T[] right, T[] array){
Array<T> sortedArray = new Array<T>(array.length);
while (left.length > 0 || right.length > 0) {
if (left.length > 0 && right.length > 0) {
if (comparator.compare(left[0], right[0]) < 0) {
sortedArray.add(left[0]);
for (int i = 1; i < left.length; i++) {
left[i - 1] = left[i];
left[left.length - 1] = null;
}
}
else {
sortedArray.add(right[0]);
for (int i = 1; i < right.length; i++) {
right[i - 1] = right[i];
right[right.length - 1] = null;
}
}
}
else if (left.length > 0) {
sortedArray.add(left[0]);
for (int i = 1; i < left.length; i++) {
left[i - 1] = left[i];
left[left.length - 1] = null;
}
}
else if (right.length > 0) {
sortedArray.add(right[0]);
for (int i = 1; i < right.length; i++) {
right[i - 1] = right[i];
right[right.length - 1] = null;
}
}
}
for (int i = 0; i < array.length; i++) {
array[i] = sortedArray.get(i);
}
}
}
Suppose the array has length 2. Then left is:
T[] left = (T[]) new Object[array.length/2 + 1];
which is
T[] left = (T[]) new Object[2/2 + 1];
and this equals to
T[] left = (T[]) new Object[2];
And when you sort on left, this continues, and leads to an infinite recursion which might have caused the stack overflow error you posted.
Since you are copying the first middleIndex elements into left, middleIndex length should right fit the array left. So left should be a length array.length/2 array.