Am suppose to return the number of character comparisons. In the while() loop i compare the index of the characters and update the counter. My question is, is it right to do it that way or i have to compare the characters themselves. I think comparing the index and updating the counter is the same as comparing the characters themselves. Any idea?
Need help.
The following is the code of the algorithm.
// Sort an array of strings using quick sort
// Always pivot on the first element
// Return the number of CHARACTER comparisons
public int stringQuickSort(ComparableByte[][] strings) {
Counter nCompares = new Counter();
sortStringQuickSort(strings, 0, strings.length-1, 0, nCompares, false);
return nCompares.value;
}
public void sortStringQuickSort(ComparableByte[][] strings, int lo, int hi, int d, Counter nCompares, boolean switchToOtherAlgorithm){
if(!switchToOtherAlgorithm){
if(hi <= lo)
return;
}else if(hi <= lo+10){
stringInsertionSort(strings);
return;
}
int lt = lo, gt = hi;
int v = characterAt(ComparableByte.toString(strings[lo]), d);
int i = lo+1;
while(i <= gt){
int t = characterAt(ComparableByte.toString(strings[i]), d);
nCompares.value++;
if (t < v){
swapTwoComparableByteElements(strings, lt++, i++);
nCompares.value++;
}
else if(t > v){
swapTwoComparableByteElements(strings, i, gt--);
}
else
i++;
}
sortStringQuickSort(strings, lo, lt-1, d, nCompares, switchToOtherAlgorithm);
if(v >= 0){
sortStringQuickSort(strings, lt, gt, d+1, nCompares, switchToOtherAlgorithm);
}
sortStringQuickSort(strings, gt+1, hi, d, nCompares, switchToOtherAlgorithm);
}
Thanks for your help
Usually these things are used to provide an empirical estimate of comparisons needed by algoritms to study if the expected behaviour is correct.
So, yes, it doesn't matter exactly what you count if you take care to count the correct operations. You don't care if they are characters of indices as long as you are actually counting whenever you program needs to compute a < > <= >= = operation related to the input and the current implementation.
Related
I have an assignment to write a binary search that returns the first iteration of the value we are looking for. I've been doing some research online and my search looks a lot like what i'm finding but i'm having an issue. If I pass this code an array that looks like this {10,5,5,3,2} it find the 5 at in the middle(The first thing it checks) and then just returns it. But that is not the first iteration of the 5 it is the second. What am I doing wrong? Is this even possible?
Thanks in advance!
The code(I'm using Java):
public static int binarySearch(int[] arr, int v){
int lo = 0;
int hi = arr.length-1;
while(lo <= hi){
int middle = (lo+hi)/2;
if(v == arr[middle]){
return middle;
}
else
{
if(v < arr[middle]){
lo = middle+1;
}
else
{
hi = middle-1;
}
}
}
return -1;
}
Here is a modified algorithm that works.
public static int binarySearch(int[] arr, int v) {
int lo = -1;
int hi = arr.length - 1;
while (hi - lo > 1 ) {
int middle = (lo + hi) / 2;
if (arr[middle] > v) {
lo = middle;
} else {
hi = middle;
}
}
if (v == arr[hi]) {
return hi;
} else {
return -1;
}
}
The key points are:
The interval (lo, hi] is exclusive to the left, inclusive to the right.
At each step we throw away one half of the interval. We stop when we are down to one element. Attempts to terminate early offer only a minimal performance boost, while they often affect code legibility and/or introduce bugs.
When arr[middle] = v we assign hi = middle, thus throwing away the right half. This is safe to do because we don't care any occurrences of v past middle. We do care about arr[middle], which may or may not be the first occurrence, and it is for this reason that we made (lo, hi] inclusive to the right. If there are occurrences of v before middle, we will find them in subsequent iterations.
As a side note, the more natural definition [0, n) inclusive to the left, exclusive to the right, can be used to find the last occurrence of v.
In my experience, this inclusive-exclusive interval definition produces the shortest, clearest and most versatile code. People keep trying to improve on it, but they often get tangled up in corner cases.
I've been looking for a recursive selection sort, using only 2 parameters:
The array that has to be sorted
a value k, which indicates till which
element it has to be sorted.
Example: SelectionSort(array[] a, int k) with a being {6,3,5,7,2} and k being 2 will sort the first 3 elements, and will keep the last elements untouched.
I was thinking about starting with an if-statement for k being 0, and if that was the case, it would just return the array as it is, since you cant sort an array of size 1.
Something like:
public int[] sort(int[] a){
a = selectionSort(a, n-1);
return a;
}
public int[] selectionSort(int[] a, int k){
if (k = 0){
return a;
}
else{
selectionSort(a, k-1 );
... (part i really don't know)
}
I have no clue how to do the 'else' part since I only know that it has to call the method again.
I'm not allowed to create other methods. I also need to make sure I use exactly 2 parameters, nothing more, nothing less.
I have to work it out in pseudocode, but I understand some Java, so if someone could help me by using either pseudo, or Java, it would be so helpful
First some remarks to your code:
Your methods sort and selectionSort don't need to return an int[] array,
since the array object a stays the same all the time.
It is only the content within this array which changes.
Hence, you can use void as return-type.
In your if use (k == 0) instead of (k = 0)
You already figured out the first part.
Here it is how you can do the second part in pseudo code:
public void selectionSort(int[] a, int k) {
if (k == 0) {
return;
}
else {
selectionSort(a, k-1 );
find x such that a[x] is the smallest of a[k] ... a[a.length - 1]
if (a[k-1] > a[x]) {
swap a[k-1] and a[x]
}
}
}
I'm sure you are able to refine the pseudo code to real Java code.
By doing a simple google search, I found the biggest part of the code below on this site. I added the selectionSort method myself to suit your parameters.
public void selectionSort(int a[], int n)
{
recurSelectionSort(a, n, 0);
}
// Recursive selection sort. n is size of a[] and index
// is index of starting element.
static void recurSelectionSort(int a[], int n, int index)
{
// Return when starting and size are same
if (index == n)
return;
// calling minimum index function for minimum index
int k = minIndex(a, index, n-1);
// Swapping when index nd minimum index are not same
if (k != index){
// swap
int temp = a[k];
a[k] = a[index];
a[index] = temp;
}
// Recursively calling selection sort function
recurSelectionSort(a, n, index + 1);
}
// Return minimum index
static int minIndex(int a[], int i, int j)
{
if (i == j)
return i;
// Find minimum of remaining elements
int k = minIndex(a, i + 1, j);
// Return minimum of current and remaining.
return (a[i] < a[k])? i : k;
}
I am trying to do the following exercise (found on Codility):
The way I have approached it is by using pointers. E.g. the binary representation of 25 is 11001. We start off with i = 0, j = 1, and a variable gLength = 0 that keeps track of the length of the gap.
If the i'th index is 1, check for the j'th index. If the j'th index is 0, increment gLength. If the j'th index is 1, check if gLength is greater than 0. If it is, then we need to store this length in an ArrayList as we have reached the end of the gap. Increment i and j, and repeat.
Here's the method in code:
public static int solution(int N) {
String binaryStr = Integer.toBinaryString(N);
// pointers
int i = 0;
int j = 1;
// length of gap
int gLength = 0;
while (j < binaryStr.length() && i < j) {
if (binaryStr.charAt(i) == 1) {
if (binaryStr.charAt(j) == 0) {
gLength++; // increment length of gap
} else if (binaryStr.charAt(j) == 1) {
// if the digit at the j'th position is the end of a gap, add the gap size to list.
if (gLength > 0)
gapLengths.add(gLength);
i++; // increment i pointer
}
} else {
i++; // increment i pointer
}
j++; // increment j pointer
}
Collections.sort(gapLengths);
// Line 45 (ERROR)
int maxGap = gapLengths.get(gapLengths.size() - 1);
return maxGap;
}
I get the following error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:400)
at java.util.ArrayList.get(ArrayList.java:413)
at Codility.solution(Codility.java:45)
at Codility.main(Codility.java:15)
I've marked down where line 45 is in the comments. After further investigating (with the debugger), I found out that I get the error because no length(s) seems to be getting added to the ArrayList. Does anybody know why?
I hope this was clear, if not please let me know. I'm not sure if this method would execute in O(log n) time like required, but for now I just want to have something working - then I will think about the time complexity aspect of it.
Big thanks for any help.
The problem is if (binaryStr.charAt(i) == 1). You are comparing char with int.
Replace:
if (binaryStr.charAt(i) == 1)
and
if (binaryStr.charAt(j) == 0)
With:
if (binaryStr.charAt(i) == '1')
and
if (binaryStr.charAt(j) == '0')
Edit: (As pointed out by Andy)
Before doing int maxGap = gapLengths.get(gapLengths.size() - 1);, you need to check if gapLengths.size() > 0 to make sure you have atleast 1 element in the the ArrayList.
I don't want to be annoying, I think the guys have offered great help for your algorithm. I propose, well, I believe it is an easier approach to use
String[] result = binaryStr.split("1");
And then go about just checking the biggest element of the array.
Edit: apparently I missed the part regarding the big O restriction, so I worked a different algorithm:
If you take a look at this page http://www.convertbinary.com/numbers.php
you'll notice that the gap starts at 5 (0 gap) then 9 (00 gap) then 17 (000 gap) etc..(in increasing order), the quick relation I noticed is if you start at 5 then add (5-1=4 to it) you'll get the 00 gap at 9, then 9+8 = 17 (000 gap) etc..
I believe you might be able to come up with a certain fixed calculation to get the best performance out of this without having to do String or Char work.
A simple solution in Swift:
let number = 5101
let binrygap = String(num, radix:2).componentsSeparatedByString("1").map { (a) -> Int in
a.characters.count}.maxElement()
Simple solution 100%
public int solution(final int N) {
//Convert number to Binary string
String bin = Integer.toString(N, 2);
System.out.println("binary equivalent = " + bin);
int gap = 0;
int maxGap = 0;
for (int i = 1; i < bin.length(); i++) {
if (bin.charAt(i) == '0') {
gap++;
}
else if (bin.charAt(i) == '1') {
if (gap > maxGap) {
maxGap = gap;
}
gap = 0;
}
}
return maxGap;
}
Java 8 implementation.
`
class Solution {
public int solution(int N) {
while(N%2 == 0){
N /= 2;
}
String binaryString = Integer.toBinaryString(N);
String[] matches = binaryString.split("1");
Optional maxValueOptional = Arrays.stream(matches).max(String::compareTo);
return maxValueOptional.isPresent()? ((String) maxValueOptional.get()).length():0;
}
}
`
I have array with constant size (size = 20 in real life), duplicates are allowed For example:
1 2 2 3 3 4 5 6 7 8 9
Now exactly one element updates:
1 5 2 3 3 4 5 6 7 8 9
I need to resort this array. Should I just use bubblesort?
update I don't know how to call what I wrote. But i suppose it is not possible to sort faster. comments are welcome!
// array is already almost sorted and INCREASING, element at pos need to be inserted to the right place
private void SortQuotes(List<Quote> quoteList, int pos)
{
var quoteToMove = quoteList[pos];
if (pos == 0 || quoteList[pos - 1].Price < quoteToMove.Price)
{
MoveElementsDown(quoteList, pos);
} else if (pos == quoteList.Count - 1 || quoteList[pos + 1].Price > quoteToMove.Price)
{
MoveElementsUp(quoteList, pos);
}
}
private void MoveElementsDown(List<Quote> quoteList, int pos)
{
var quoteToInsert = quoteList[pos];
var price = quoteToInsert.Price;
for (int i = pos - 1; i >= 0; i--)
{
var nextQuote = quoteList[i];
if (nextQuote.Price > price)
{
quoteList[i + 1] = quoteList[i];
if (i == 0) // last element
{
quoteList[i] = quoteToInsert;
}
}
else
{
quoteList[i + 1] = quoteToInsert;
break;
}
}
}
private void MoveElementsUp(List<Quote> quoteList, int pos)
{
var quoteToInsert = quoteList[pos];
var price = quoteToInsert.Price;
for (int i = pos + 1; i < quoteList.Count; i++)
{
var nextQuote = quoteList[i];
if (nextQuote.Price < price)
{
quoteList[i - 1] = quoteList[i];
if (i == quoteList.Count - 1) // last element
{
quoteList[i] = quoteToInsert;
}
}
else
{
quoteList[i - 1] = quoteToInsert;
break;
}
}
}
updated i do know which element is odd, i.e. it's position is known!
This solution shifts each element by one until the right position for the odd element is found. As it has been overwritten already in the first step, it is saved in a temporary variable 'h' and then written to the final position. It requires the minimum of comparisions and shift operations:
static void MoveOddElementToRightPosition(int[] a, int oddPosition)
{
int h = a[oddPosition];
int i;
if (h > a[oddPosition + 1])
for (i = oddPosition; i < a.Count()-1 && a[i+1] <= h; i++)
a[i] = a[i+1];
else
for (i = oddPosition; i > 0 && a[i-1] >= h; i--)
a[i] = a[i - 1];
a[i] = h;
}
Bubblesort will use n^2 time if the last element needs to get to the front. Use insertion sort.
As the array is small, insertion sort takes roughly ~O(n) time for small arrays and if you are just updating 1 value, insertion sort should fulfil your purpose in the best possible way.
It can be done in O(n). If you don't know the element then search for the element in O(n) and then You just need to compare and swap for each element and that would take O(n). So total 2n which means O(n).If you know the element which has been modified then compare and swap for each element.
If you're interested in replacing an element quickly, then you can also use a structure where deletion and insertion is fast, like for example a TreeSet in Java. That means O(log(n)) theoretically, but if you just manipulate arrays of 20 elements it may not be worth it
If the set of all different elements is finite, like in your example where you just use numbers for 1 to 9, then there is a solution in O(1). Instead of having a sorted list you just keep an array with the number of occurrences of your elements.
If you still want to keep everything in an array, then the fastest way is this
find the position A of of the element you're going to remove by bisection in O(log(n)).
find the position B of where your new element is going to end up in the same way. More precisely B is the smallest index where new_element < a[k] for every k > B
if A < B, move all elements between A + 1 and B to their left, then set the new element to position B. if B > A, you do the same thing but to the right. Now this step is in O(n), but there's no logic, it's just moving memory around. In C you'd use memmove for this and it's heavily optimized, but I don't know any Java equivalent.
You don't need to sort it again.
Only one element changes. So you just need to go through the list and put the changed number to appropriate place. This will be of O(n) complexity.
int a[] = {1, 5, 2, 3, 3, 4, 5, 6, 7, 8, 9};
int count = 0;
//find the odd element
for(int jj=1; jj< a.length; jj++){
if(a[jj] < a[count])
break;
else count++;
}
System.out.println(" Odd position " + count);
//put odd element to proper position
for(int k= count+1; k<a.length; k++){
if(a[count] > a[k]){
int t = a[count];
a[count] = a[k];
a[k] = t;
count++;
}
}
Above is the working code tested for given input.
Enjoy.
Bubblesort is quite OK in this case with 20 compares max.
But finding the new position with binary search is O(log(n)), that is 5 compares in this case.
Somewhat faster, if you need the last bit odd speed use the binary search otherwise you can stick with bubble sort.
Here is a naive implementation in plain C. Remove the fprintf(stderr, ... after testing. The ITEM can be anything, as long as a comparison function is possible. Otherwise: use pointers to ITEM, (and maybe add an extra sizeofelem argument, ala qsort)
#include <stdio.h>
#include <string.h>
typedef int ITEM;
int item_cmp(ITEM one, ITEM two);
unsigned one_bubble( ITEM *arr, unsigned cnt, unsigned hot , int (*cmp)(ITEM,ITEM) );
int item_cmp(ITEM one, ITEM two)
{
fprintf(stderr,"Cmp= %u to %u: %d\n", one, two, one-two);
if (one > two) return 1;
else if (one < two) return -1;
else return 0;
}
unsigned one_bubble( ITEM *arr, unsigned cnt, unsigned hot , int (*cmp)(ITEM,ITEM) )
{
unsigned goal = cnt;
int diff;
ITEM temp;
/* hot element should move to the left */
if (hot > 0 && (diff=cmp( arr[hot-1], arr[hot])) > 0) {
/* Find place to insert (this could be a binary search) */
for (goal= hot; goal-- > 0; ) {
diff=cmp( arr[goal], arr[hot]);
if (diff <= 0) break;
}
goal++;
fprintf(stderr,"Move %u LEFT to %u\n", hot, goal);
if (goal==hot) return hot;
temp = arr[hot];
/* shift right */
fprintf(stderr,"memmove(%u,%u,%u)\n", goal+1, goal, (hot-goal) );
memmove(arr+goal+1, arr+goal, (hot-goal) *sizeof temp);
arr[goal] = temp;
return goal; /* new position */
}
/* hot element should move to the right */
else if (hot < cnt-1 && (diff=cmp( arr[hot], arr[hot+1])) > 0) {
/* Find place to insert (this could be a binary search) */
for (goal= hot+1; goal < cnt; goal++ ) {
diff=cmp( arr[hot], arr[goal]);
if (diff <= 0) break;
}
goal--;
fprintf(stderr,"Move %u RIGHT to %u\n", hot, goal);
if (goal==hot) return hot;
temp = arr[hot];
/* shift left */
fprintf(stderr,"memmove(%u,%u,%u)\n", hot, hot+1, (goal-hot) );
memmove(arr+hot, arr+hot+1, (goal-hot) *sizeof temp);
arr[goal] = temp;
return goal; /* new position */
}
fprintf(stderr,"Diff=%d Move %u Not to %u\n", diff, hot, goal);
return hot;
}
ITEM array[10] = { 1,10,2,3,4,5,6,7,8,9,};
#define HOT_POS 1
int main(void)
{
unsigned idx;
idx = one_bubble(array, 10, HOT_POS, item_cmp);
printf("%u-> %u\n", HOT_POS, idx );
for (idx = 0; idx < 10; idx++) {
printf("%u: %u\n", idx, array[idx] );
}
return 0;
}
I am facing some problem with the recursive quick sort algorithm. The elements are not sorted in the correct order. The input data are Strings with duplicate entries as well. I am using an integer to differentiate between ascending order( 1 ) and descending order ( -1) sort. The pivot is the mid element. Whenever the duplicate entries are compared( compareTo(String s) will return 0), i compare the current indices and return a negative number if the index of the string being compared is more than the index of the other.I am not sure as to what exactly is going wrong.
Below is the code
// Quick sort Algorithm
public void sort(int left, int right)
{
int i = left, j = right;
String mid;
mid = (String)vect.elementAt((left + right)/2);
while (i <= j)
{
// Compare the elements to the left
while ((i < right) &&
(compare((String)vect.elementAt(i), mid) < 0))
i++;
// Compare the elements to the right
while ((j > left) && (compare((String)vect.elementAt(j), mid) > 0))
j--;
if (i <= j)
{
if(i!=j)
swap(i, j);
i++;
j--;
}
}
// Recursively call the sort method until indices cross.
if(left < j)
sort(left, j);
if(i < right)
sort(i, right);
}
/*
* Compare method to compare the elements.
* type = 1, for ascending sort
* type = -1, for descending sort
*/
public int compare(String firstObj, String secondObj)
{
int resCompare = firstObj.compareTo(secondObj)*type;
if(resCompare == 0)
{
int index_firstObj = vect.indexOf(firstObj);
int index_secObj = vect.indexOf(secondObj);
if(index_firstObj < index_secObj)
return -1;
else
return 1;
}
return resCompare;
}
// Swap the elements at i and j.
public void swap(int i, int j)
{
String tmp1 = (String)vect.elementAt(i);
String tmp2 = (String)vect.elementAt(j);
vect.setElementAt(tmp1, j);
vect.setElementAt(tmp2, i);
}
Example :
input = {"AA","BB","zz","cc","aa","AA","PP","hh" };
Ascending sort
output = {"AA","AA","BB","PP","aa","cc","hh","zz"};
Descending sort
output = {"zz","hh","cc","BB","aa","PP","AA","AA"};
The problem in the algorithm may not work for ascending order sort as well on some other input data. So any help in finding the glitch in the code/logic will be really helpful.Thanks in advance.
Solved:
There is no need to find index_firstObj and index_SecondObj. Just don't do anything if the resCompare is zero.
public int compare(String firstObj, String secondObj)
{
int resCompare = firstObj.compareTo(secondObj)*type;
return resCompare;
}
What if i or j become the mid? and the other one is yet not the mid? doesnt that arise problems also? You might need to check if one of them becomes the mid.