What I am is doing is using a quicksort algorithm, so that my pivot element(which will always be the first element of the array gets positioned to its appropriate position in the sorted array and I am calling this method again until I do not position the element at a given rank. Is there a better solution?
Here is my code:
public static int arbitrary(int a[],int x,int y,int rank)//x and y are first and last indecies of the array
{
int j=y,temp;
if(x<y)
{
for(int i=y;i>x;i--)
{
if(a[i]>a[x])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
j--;
}
}
temp=a[x];
a[x]=a[j];
a[j]=temp;
//System.out.println("j is "+j);
if(j==rank)
return a[j];
else if(rank<j)
return arbitrary(a,x,j-1,rank);
else
return arbitrary(a,j+1,y,rank);
}
else
return 0;
}
The algorithm you have implemented is called Quickselect.
Just select a random pivot and to get rid of the worst case with O(n²) time complexity.
The expected runtime is now about 3.4n + o(n).
Quickselect is probably the best tradeoff between performance and simplicity.
An even more advanced pivot selection strategy results in 1.5n + o(n) expected time
(Floyd-Rivest Algorithm).
Fun Fact: With deterministic algorithms you can't go better than 2n. BFPRT for example needs about 2.95n to select the median.
Best way to find Rank element by using the QuickSort method:
In QuickSort, at every iteration you are able to get fixed one pivot element.
When the RankElement == PivotIndex, and break the condition and return the value.
public class FindRank {
public void find(int[] arr, int low, int high, int k) {
if (low < high) {
int pivot = partition(arr, low, high, k);
find(arr, low, pivot - 1, k);
find(arr, pivot + 1, high, k);
}
}
public int partition(int[] arr, int low, int high, int k) {
int pivotIndex = high;
while (low < high) {
while (low < high && arr[low] <= arr[pivotIndex]) {
low++;
}
while (low > high && arr[high] >= arr[pivotIndex]) {
high--;
}
if (low < high) {
swap(arr, low, high);
}
}
swap(arr, pivotIndex, high);
if (pivotIndex == k) {
System.out.println("Array Value:" + arr[k] + " index:" + k);
return k;
}
return high;
}
private void swap(int[] arr, int low, int high) {
int temp = arr[low];
arr[low] = arr[high];
arr[high] = temp;
}
}
Related
Hello everyone i have a question. It's my task which one is below:
Let A[] be a natural numbers array of length N, which is partially sorted, i.e. there exists such index i(0 < i < N-1), that the subaray A[0],...,A[i] is incrementally sorted and also the subarray A[i+1],...,A[N] is incrementally sorted. Design the algorithm, which sorts the whole array A[] and works in place (so has space complexity O(1)) and the result must be stored in the same array A[]. Describe the algorithm, its correctness and its time complexity approximation.
For this question which approaching is better? Bubble sorting or Insertion sort? Or is there more effective solution? I prefered bubble sorting for this task but i am open to other opinions
static void bubbleSort(int arr[], int n)
{
int i, j, temp;
boolean swapped;
for (i = 0; i < n - 1; i++)
{
swapped = false;
for (j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
// swap arr[j] and arr[j+1]
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (swapped == false)
break;
}
}
static void printArray(int arr[], int size)
{
int i;
for (i = 0; i < size; i++)
System.out.print(arr[i] + " ");
System.out.println();
}
public static void main(String args[])
{
int arr[] = { 1, 8, 45, 12, 22, 11, 90 };
int n = arr.length;
bubbleSort(arr, n);
System.out.println("Sorted array: ");
printArray(arr, n);
}
}
Bubble sort algorithm complexity is O(n^2). Even using if (swapped == false) break; this will not help to reduce the complexity (try for {2,3,4,5,1}, you will find out).
Since there exists such index i(0 < i < N-1), that the subaray A[0],...,A[i] is incrementally sorted and also the subarray A[i+1],...,A[N] is incrementally sorted.This problem can be solve in O(n) run time complexity. If we can find the index i where A[0:i] and A[i+1:n] are sorted, then we can think this problem as merging two sorted array into one array which can be done in O(n) time. Algorithm is given below:
void sortPartialSortedArray(int arr[], int n)
{
int pos = 0;
// find the position for which arr[0:pos] and arr[pos+1:n] is sorted
for(int i=0; i+1<n; i++) {
if(arr[i]>arr[i+1]) {
pos = i;
}
}
int i = pos, j= n-1;
// sort it from last position
while(i>=0 && j>=0) {
if(arr[i] > arr[j]) {
swap(arr[i],arr[j]);
}
j--;
if(i==j) {
i--;
}
}
}
I came across kth largest number problem in Leetcode
Input: [3,2,1,5,6,4] and k = 2, Output: 5
Suggested Solution:
public int findKthLargest(int[] nums, int k) {
shuffle(nums);
k = nums.length - k;
int lo = 0;
int hi = nums.length - 1;
while (lo < hi) {
final int j = partition(nums, lo, hi);
if(j < k) {
lo = j + 1;
} else if (j > k) {
hi = j - 1;
} else {
break;
}
}
return nums[k];
}
private int partition(int[] a, int lo, int hi) {
int i = lo;
int j = hi + 1;
while(true) {
while(i < hi && less(a[++i], a[lo]));
while(j > lo && less(a[lo], a[--j]));
if(i >= j) {
break;
}
exch(a, i, j);
}
exch(a, lo, j);
return j;
}
private void exch(int[] a, int i, int j) {
final int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
private boolean less(int v, int w) {
return v < w;
}
Doesn't partition take O(n) and the while loop in the main function take O(log n) so it should be O(nlog n)? This looks like it uses Quicksort but the runtime for quicksort is O(nlogn). If quicksort takes O(n), this makes sense but it does not. Please help me understand what is going on?
This is a randomized algorithm that has average/expected O(n) runtime. This is because after randomly shuffling the input list, we typically have pivots good enough to expect that after each partition function call if we don't find the target yet we reduce our list (to be search next) roughly by half. This means even though if we not lucky and have to continuously call partition function we continuously keep reducing our list's size by half, therefore the average runtime is still only O(n) since O(n) + O(n/2) + O(n/4) + ... + O(1) is still O(n).
wanted to analyse the complexity of recursive linear search ( using divide and conquer technique ). Is it log(n) or n ? if not log(n) then what is the actually complexity and how ?
int linear_search(int *a,int l,int h,int key){
if(h == l){
if(key == a[l])
return l;
else
return -1;
}
int mid =(l+h)/2;
int i = linear_search(a,l,mid,key);
if(i == -1)
i = linear_search(a,mid+1,h,key);
return i;
}
Yes it is O(n). But this algorithm doesn't make sense. All you have to do is go through the array and find if the element is found which is what this algorithm is doing but it is unnecessarily complex.
Yes, it's O(n). What the recursive method does is just a loop, so you would be better off using a real loop:
int linear_search(int *a,int l,int h,int key){
for (int i = l; i <= h; i++) {
if (a[i] == key) return i;
}
return -1;
}
If you want to use recursion to avoid a loop, there is one worse way of doing it, sometimes found in (bad) examples showing recursion:
int linear_search(int *a,int l,int h,int key){
if (l > h) {
return -1;
} else if (a[l] == key) {
return l;
} else {
return linear_search(a, l + 1, h, key);
}
}
It's still O(n), but it's worse because it will fill the stack if the array is too large. The divide and conquer approach at least will never nest deeper than the number of bits in an integer.
yes, it search all value in array till find them, and its time complexity is omega(n). and it looks to be in lg(n) but because of your if(h == l) it search all values of your array
I am trying to implement quick sort in java and I have one doubt. So here's my quick sort code:
package com.sorting;
public class QuickSort implements Sort {
#Override
public int [] sort(int[] arr) {
return quickSort(arr, 0, arr.length - 1);
}
private int [] quickSort(int[] numbers, int low, int high) {
if (low < high) {
int q = partitionTheArrayAroundPivot(numbers, low, high);
if (low < q)
quickSort(numbers, low, q);
if ((q+1) < high)
quickSort(numbers, q + 1, high);
}
return numbers;
}
private int partitionTheArrayAroundPivot(int[] numbers, int low, int high) {
int pivot = selectPivot(numbers, low, high);
int i = low;
int j = high;
while (true) {
while (numbers[i] < pivot) {
i++;
}
while (numbers[j] > pivot) {
j--;
}
if ( i <= j) {
swap(numbers, i, j);
i++;
j--;
} else {
return j;
}
}
}
private int selectPivot(int[] numbers, int low, int high) {
return numbers[high];
}
private void swap(int[] numbers, int i, int j) {
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
}
Doubt 1: We keep increasing the index i till we hit a number which is >= pivot
while (numbers[i] < pivot)
i++;
Similarly we keep decreasing the index j till we hit a number which is <= pivot
while (numbers[j] > pivot)
j--;
So, this means that both indexes will also come out of the loop if both hits pivots at two different places e.g. 1,0,1 here if pivot is 1, then i will be 0 and j will be 2. And the below condition will be satisfied
if (i <= j) {
....
}
but in that case it won't be able to sort the above array (1,0,1) because after swapping we are increasing i and decreasing j so the value become i = j = 1. After that i will hit the third element i.e 1 and will again come out of the loop with value i = 2 and similarly j = 0 and we will not be able to sort the array.
So where's the problem? Am I missing something?
I would rewrite the code a little so that selectPivot returns the index instead:
private int selectPivotIndex(int[] numbers, int low, int high) {
return high;
}
Then the partitioning funcion can move the pivot aside, and sort the remaining items according to pivot value. A single loop will do it, in this implementation duplicate pivots will end up on right side:
private int partitionTheArrayAroundPivot(int[] numbers, int low, int high) {
int pivotIndex = selectPivotIndex(numbers, low, high);
swap(numbers, pivotIndex, high); // Not needed if selectPivotIndex always returns high
int newPivotIndex = low;
for(int i = low; i < high; i++)
{
if(numbers[i] < numbers[pivotIndex])
{
swap(numbers, i, newPivotIndex);
newPivotIndex++;
}
}
swap(numbers, newPivotIndex, pivotIndex);
return newPivotIndex;
}
Finally, a small adjustment needs to be done in the quickSort method so that we don't end up in an eternal loop:
if (low < q)
quickSort(numbers, low, q - 1);
This approach is IMHO easier to understand and debug, hope it works for you.
Use
while (numbers[i] <= pivot) and
while (numbers[j] >= pivot) and your code will work
When given an array of elements, how can I count the amount of element comparisons the algorithm performs?
It's not as easy as just adding a counter to the partition method.
private void partition(int low, int high) {
int i = low, j = high;
// Get the pivot element from the middle of the list
int pivot = numbers[low + (high-low)/2];
// Divide into two lists
while (i <= j) {
if (array[i] < pivot) {
i++;
compareCount++; //it's not as easy as just adding this here
}
else if (numbers[j] > pivot) {
j--;
compareCount++;
}
else (i <= j) {
exchange(i, j);
i++;
j--;
}
}
You can't do this because it counts the comparison just made, and not any of the comparisons made when it evaluates to false.
I've tried changing the if (array[i] < pivot) to while (array[i] < pivot) (for j, too), but I feel like I'm still missing out on something if I do it that way.
Ideally you should be able to do it by analyzing the logic. But if you want to have the program do it for you during its run-time then, easy way to do this is to have a function for performing comparison operation. Let the function increment a global/static variable everytime it is called and then do the comparison. At the end of all your logic just print this global/Static variable.
public class Myclass{
public static int compareCount = 0;
}
/*
* PASS parameter comparisonMethod as following
* 0 for ==, 1 for >, 2 for >=, 3 for < and 4 for <==
* Method returns true or false by doing appropriate comparison based on comparisonMethod
*/
public bool compare(int i, int j, int comparisonMethod)
{
Myclass.compareCount++;
if(comparisionMethod ==0) return i==j?true:false;
if(comparisionMethod ==1) return i>j?true:false;
if(comparisionMethod ==2) return i>=j?true:false;
if(comparisionMethod ==3) return i<j?true:false;
if(comparisionMethod ==4) return i<=j?true:false;
}
private void partition(int low, int high) {
int i = low, j = high;
// Get the pivot element from the middle of the list
int pivot = numbers[low + (high-low)/2];
// Divide into two lists
while (compare(i, j, 4)) {
if (compare(array[i], pivot, 3)) {
i++;
}
else if (compare(numbers[j], pivot, 2)) {
j--;
}
else (compare(i, j, 4)) {
exchange(i, j);
i++;
j--;
}
}
// At the end of the logic, Myclass.compareCount wil give number of comparisons made.
The parition method of quick sort would be called till the size of array is not 1 in which case our array would be sorted.In your code when you have founf the position at which pivot would be swapped (in your else if portion)you are not supposed to incrment the comparecounter.
You can use this modified partition method
partition(A,p,r)
{
pivot=A[r]; // Taking last element as pivot
i=p;
j=r;
while (true)
{
while(A[i] < pivot && i <= r )
{
++comparecounter;
++i;
}
while(A[j] >= pivot && j >= 0)
{
--j;
++comparecount;
}
if(i < j)
{
Exchange A[i] and A[j]
}
else
{
return j;
}
In above algorithm you could make countcompare as global which would would incrment fro each call to partition.This would would count the no of comparisions made.
You can embed the compare count increment inside each if statement...
if ((compareCount++ != -1) && (array[i] < pivot))
...
else if ((compareCount++ != -1) && (numbers[j] > pivot))
...
else if ((compareCount++ != -1) && (i <= j))
It'll always evaluate the first clause of the if, always return true, and always then execute the second.