I need to implement a gnomesort to sort strings on how close they are to the string input. I measure this difference with the Levenshtein-algoritm.
The algoritm works fine but only with if I have two strings in the database. It then sorts it fine, but if there are more than two strings, it just prints them in the order they are in the database. I really can't find the problem
public static void retrieveFromDatabase(String string)
{
String[] sq = new String[database.size()];
database.toArray(sq);
int r = 0, index = 1, y = 2, tmp1 = 0;
String tmp2;
int[] ds = new int[sq.length];
for (int i = 0; i < database.size(); i++) {
ds[i] = sortLevenshtein(string, database.get(i), false);
}
for(index = 1; index < ds.length; index++) // gnomsort
{
if(ds[index - 1] <= ds[index] )
{
++index;
}
else
{
tmp1 = ds[index];
tmp2 = sq[index];
ds[index] = ds[index - 1];
sq[index] = sq[index - 1];
ds[index-1] = tmp1;
sq[index-1] = tmp2;
index--;
if (index == 0)
index++;
}
}
System.out.println("Best matches: ");
for(r=0; r<Math.min(3,sq.length); r++)
{
System.out.println(ds[r] + "\t" + sq[r]);
}
}
The problem
Your gnome sort is not sorting correctly when there are more than two elements to sort.
In your problematic case your ds contains 1, 1, 0 from the outset. In your for loop index is 1. You see that the elements at indices 0 and 1 are in the correct order (both elements are 1), so you increment index to 2 in the if statement. Next your for loop also increments index, so it is now 3. 3 is not less than ds.length (also 3), so the loop terminates.
I don’t know gnome sort, so I can’t tell you the fix. What I can tell you is that manipulating your for loop control variable — index in your code — inside the for loop is the sure way to code that is hard to understand and very hard to find errors in. I never ever do that.
for(index = 1; index < ds.length; index++) // OK: loop control variable is incremented here
{
if(ds[index - 1] <= ds[index] )
{
++index; // No-no: incrementing loop control variable, dangerous
}
else
{
tmp1 = ds[index];
tmp2 = sq[index];
ds[index] = ds[index - 1];
sq[index] = sq[index - 1];
ds[index-1] = tmp1;
sq[index-1] = tmp2;
index--; // No-no: decrementing loop control variable, problematic
if (index == 0)
index++; // No-no: incrementing loop control variable
}
}
Related
The arrays are always the size of powers of 2, and it can't be recursive.
If I've made any errors in asking my question this is my first time asking a question. Bear with me please.
The plan is to place markers in powers of two then loop through and place the ordered numbers into an array then putting them back in the array. Then should be placed into the original array in the groups that they were placed split into. Gradually getting bigger until the whole array is sorted.
public static void MergeSortNonRec(long[] a) {
//======================
//FILL IN YOUR CODE HERE
//======================
System.out.println(a.length); // print statement
if (a == null)
return;
int subArray1 = 0;
int subArray2 = 1;
int increment = 0;
int swapCounter = 0;
for (int i = 1; i <= a.length; i *= 2) {
// this loop determines the current size of the sub array
increment = i;
subArray1 = 0;
subArray2 = 0;
swapCounter = 0;
while (subArray2 <= a.length) {
// this will loop until we reach the end of the array
subArray2 += increment;
long[] spareArray = new long[2 * i];
swapCounter = 0;
while (swapCounter <= spareArray.length) {
System.out.println(subArray1 + " " + subArray2); // print statement
if (a[subArray1] < a[subArray2]) {
spareArray[swapCounter] = a[subArray1];
swapCounter++;
subArray1++;
} else
if (a[subArray1] > a[subArray2]) {
spareArray[swapCounter] = a[subArray2];
swapCounter++;
subArray2++;
} else
if (a[subArray1] == a[subArray2]) {
spareArray[swapCounter] = a[subArray1];
swapCounter++;
subArray1++;
System.out.println(swapCounter + " " + subArray1); // print statement
spareArray[swapCounter] = a[subArray1];
swapCounter++;
subArray2++;
}
} // this creates an array of the ordered elements
while (swapCounter == spareArray.length) {
subArray1 -= swapCounter / 2;
subArray2 -= swapCounter / 2;
// now the sub array pointers are back to the values they started at
int spareArrayPointer = 0;
for (; subArray1 <= subArray2; subArray1++) {
a[subArray1] = spareArray[spareArrayPointer];
spareArrayPointer++;
} // this places the values in the spare array into the original array
subArray1 -= spareArrayPointer;
spareArrayPointer = 0;
// takes the first pointer back to where it started
}
subArray1 += increment;
subArray2 += increment + increment;
} // end subArray2 <= a.length loop
} // end 2*i loop
} //MergeSortNonRec()
A non-recursive implementation of merge sort could still be based on top down merge sort, using a stack to push and pop pairs of indexes.
A more common implementation of non-recursive merge sort is bottom up, where an array of n elements is treated as n "sorted" runs of size 1 (since their size is 1, they can be considered sorted), then for each merge "pass", merge even and odd runs, which doubles the run size on each pass. Repeat until run size >= array size.
Wiki example. This example could be optimized by swapping A and B after each pass to change the direction of merge with each pass and avoid the copy back except for the lass pass (or determine number of passes in advance, and swap in place to start with run size = 2 before doing the merge passes).
https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation
I'm currently stuck on this one assignment where I don't know if I got the instructions wrong, or if the code is as it should be. The instructions is:
Replace each element except the first and last by the larger of its two neighbors.
I've completed the code, but the one problem I have is that the last element is being replaced even though it shouldn't. It'd very nice if you could take a look at my code.
public static void replaceWithNeighbours(int[] array) {
for (int i = 1; i < array.length - 1; i++) {
int larger = array[i - 1];
if (larger < array[i + 1]) {
larger = array[i + 1];
}
array[i] = larger;
}
}
A naive solution, the array management can be done better, however this works.
public static void replaceWithNeighbours(int[] array, int[] out) throws Exception
{
// checkif lengths match
if (array.length != out.length)
{
throw new Exception("Lengths don't match");
}
// replace values in output array
out[0] = array[0];
out[out.length - 1] = array[array.length - 1];
for (int i = 1; i < array.length - 1; i++) {
int larger = array[i - 1];
if (larger < array[i + 1]) {
larger = array[i + 1];
}
out[i] = larger;
}
}
Your main problem is that you iterate over the array and update it, however do not consider previous iterations. This means you can look at a neighbor who already holds an updated value and use this value, because the old is overwritten.
Since you also have a problem with the last element being updated:
Go through your code using the debugger or simple print statements and find out where exactly your index 9 is actually accessed. It is not in replaceWithNeighbours, so must be somewhere else. You can solve this by yourself however, just look what indices are used and when you see a 9, look for what is entered and where.
This can be done in a simple way:
public int[] replaceWithNeighbours(int[] arr) {
int[] ret = new int[arr.length];
for (int i = 0; i < arr.length; ++i) {
if (i == 0 || i == arr.length - 1) {
ret[i] = arr[i];
} else {
ret[i] = Math.max(arr[i-1], arr[i+1]);
}
}
return ret;
}
A short explanation: first we create a new array ret which will hold desired result and set it to the same length as original array. Then we loop over contents of original array. If we're dealing with first or last element we just copy them to ret. If we're dealing with other elements, we use Java's Math.max method to determine maximum value of 2 neighbours and set i-th element in ret to that value.
This is my insertion sort code. This code works but is this the way to write an insertion sort? I looked few tutorials but they do it in a different way.
int thirdArray[] = { 0, 22, 1, 10, 8, 5,39 };
for (int i = 0; i < thirdArray.length - 1; i++) {
for (int j = i + 1; j > 0; j--) {
if (thirdArray[j] < thirdArray[j - 1]) {
int index = thirdArray[j];
thirdArray[j] = thirdArray[j - 1];
thirdArray[j - 1] = index;
}
}
}
for (int number : thirdArray) {
System.out.print(number + "\t");
}
With Java 7 its so simple to do sorting now days.
Arrays.sort(thirdArray);
This would sort the elements of the array sorted.
In your code you are taking extra space for the swap operation. However, It's a valid approach, but you can optmize it in the following way
int thirdArray[] = { 0, 22, 1, 10, 8, 5,39 };
int key,j;
for(int i = 1 ; i < thirdArray.length ; i++)
{
key = thirdArray[i];
j = i - 1;
while(j >=0 && key < thirdArray[j])
{
thirdArray[j+1] = thirdArray[j];
j--;
}
arr[j+1] = key;
}
}
In the above code, you start comparing from the first index with it's previous, if it's smaller, overwrite it's values (you are already saving the current value in key) in the end place it in it's correct position. We can guarantee that after the sorting that all the element on the left are sorted. Insertion sort has Worst-case performance: О(n^2) Best-case performance: O(n). By swapping we are adding more complexity which you can avoid it.
I have an array which have 1 2 3 4 5 values.
array a = [ 1 , 2, 3, 4, 5]
Now i want to traverse it in circular manner.
like i want to print 2 3 4 5 1 or 3 4 5 1 2 or 5 1 2 3 4 and so on.
any algorithm on this?
Edit: I want to print all the combination in circular manner. i don't want to state starting point at its initial phase.
int start = ...
for (int i = 0; i < a.length; i++) {
System.out.println(a[(start + i) % a.length]);
}
(If you want to iterate the array backwards from start, change start + i to start - i in the array subscript expression.)
I should note that this is probably not the most efficient way of expressing the loop ... in terms of execution speed. However, the difference is small, and most likely irrelevant.
A more relevant point is whether using % in this way gives more readable code. I think it does, but maybe that's because I've seen / used this particular idiom before.
How about the following:
int start = // start position, must be in bounds
int i = start;
do {
....
i++;
if(i == a.length) i = 0;
} while(i != start);
int st = n ; // n is the starting position from where you print
for(int i = st; i < a.length; i++)
{
-- print each array[i];
}
if(st != 0)
{
for(int i = 0 ; i < st ; i++)
{
--- print each array[i];
}
}
Basically you just need to loop through the array, and change the current index if necessary (like move it to the start of the array when it meets the end)
public static void main(String[] args) {
int[] array = new int[] { 1, 2, 3, 4, 5 };
System.out.println(printCircularly(array, 4));
}
private static String printCircularly(int[] array, int startIndex) {
StringBuilder sb = new StringBuilder();
int currentIndex = startIndex;
do {
sb.append(array[currentIndex++]);
if (currentIndex > array.length - 1) {
currentIndex = 0;
}
}
while (currentIndex != startIndex);
return sb.toString();
}
In addition to Stephen C's answer
int start = ...
for (int i = 0; i < a.length; i++) {
System.out.println(a[(start - i + a.length) % a.length]);
}
Use this for reverse loop from start index. It's a little unclear, but in some cases very useful. For example: UI components like carousel.
And there's no ArrayIndexOutOfBoundsException!!!
Instead of using a for loop with indexes, which is harder to read, you can use Iterables from Google Guava as follows :
List<Integer> myList = List.of(1,2,3);
Iterator<Integer> myListIterator = Iterables.cycle(myList).iterator();
then you will only have to use myListIterator.next(). example :
System.out.println(myListIterator.next());
System.out.println(myListIterator.next());
System.out.println(myListIterator.next());
System.out.println(myListIterator.next());
This will print : 1 2 3 1
I am working on an algorithm that has three parts. The first is a recursive method that will wrap words to a specific length with the least penalty. The second is an algorithm that is a Dynamic implementation of the recursive method. The last one is a Greedy Algorithm of the problem. I already have the Greedy one coded but I'm struggling on the Recursive solution. I'm not quite sure where exactly I'm running into an issue with my Recursive method but I know it should be something similar to the Knuth-Plass Algorithm. The recursive algorithm is supposed to have a factorial running time, and used more to help with the dynamic solution. If anyone has a link to a Knuth-Plass implementation or can spot something huge in my code, any help would be appreciated.
Recursive Algorithm:
public static ArrayList<String> recursive(ArrayList<String> input, int size) {
if(input.size() <= 1)
return input;
ArrayList<String> temp1 = input;
ArrayList<String> temp2 = input;
for(int i = 0; i < input.size(); i++) {
if(input.size() - 1 >= size)
break;
else {
for(int j = 0; j < input.size(); j++) {
temp1.set(j, temp1.get(j) + " " + temp1.get(j + 1));
temp1.remove(j + 1);
if(totalPenalty(blankChars(temp1, size)) < totalPenalty(blankChars(temp2, size))) {
input = recursive(temp1, size);
} else {
input = recursive(temp2, size);
}
}
}
}
return input;
}
The totalPenalty() and blankChars return the amount of penalty at the end of each line.
EDIT: I'm still not seeing any immediate solutions. Any help would be appreciated.
That looks like Java, and in Java there is no implicit copy-constructor.
ArrayList<String> temp1 = input; <-- this will not create another object with the same content, but instead a reference to the same object.
You need to change line 4 and 5 to:
ArrayList<String> temp1 = new ArrayList<String>(input);
ArrayList<String> temp2 = new ArrayList<String>(input);
I haven't looked for any other mistakes, so try this out and update the question if you have any more problems.
About the Knuth-Pass breaking algorithm; You can find a Python implementation at http://oedipus.sourceforge.net/texlib/. I haven't looked closer at it, but the description seems to be what you are looking for.
I hope the following code runs. Here I have added the cost for the last line as well. Though word processors use greedy algorithms most of the time and they neglect the cost of the last line. Let me know if this is clear to you.
import java.lang.Math;
public int RCS(int[] l , int n , int m , int index) {
// first base condition - if index gets beyond the array 'l' , then return 0;
if (index > n - 1) return 0;
// second base condition - if index is the last word i.e there is only one word left in the
// array to be inserted in the line then return the cost if added in that line.
if (index == n - 1) return (m - l[n - 1]) * (m - l[n - 1]) * (m - l[n - 1]);
// make a global cost variable to be returned
int cost = Integer.MAX_VALUE;
// Here , we try to select words from the array and apply RCS on the rest of the array.
// From index to last element , we iteratvely select first , or first two and so on.
for (int i = index ; i < n ; i++) {
int current_space_sum = 0 ;
// we add the length of the selected word. We have selected words in array from index to i.
for (int k = index ; k <= i ; k++) {
current_space_sum = current_space_sum + l[k] ;
}
// Adding the space between the words choses. If 2 words are chosen , there is one space and so on
current_space_sum = current_space_sum + i - index;
// If the length of the chosen words is greater than the line can accept , no need of looking beyond.
if (current_space_sum > m) break;
// Iteratively find the minimum cost
cost = Math.min(cost , (m - current_space_sum) * (m - current_space_sum) * (m - current_space_sum) + RCS(l , n , m , i + 1));
}
return cost;
}
public static void main(String[] args) {
WordWrap w = new WordWrap();
int[] l = {3, 2 , 2 , 5};
int n = l.length;
int m = 6;
int result = w.RCS(l , n , m , 0);
System.out.println(result);
}