Quicksort Recursion - sorting

So I've successfully implemented a quicksort that uses the leftmost element as the pivot every time. I've been trying to implement quicksort using the middle element and having some complicated results. I have been working off of examples that has quicksort recursively call itself without wrapping the calls in any sort of condition and, as you might imagine, it gets stuck on the first call to itself.
The first calls to partition with the samples I've used partition the array correctly, then as it approaches the end, just swaps the two of the elements at the beginning over and over again.
The strategy that I am attempting is to pick the middle element from the list as the pivot, stow it away at the end of the array and then proceed to swap indices. After that pass it complete, I put the pivot between the partitioned arrays. Looks good after a couple of passes, but as I mentioned, gets stuck early on and never gets to the call that should sort the second partition.
any nudges would be greatly appreciated - I also was working in groovy, if you see anything off (and hopefully that isn't causing any issues, but I avoided duck typing for this
the original array is
[100, 305, 2, 2002, 18, 99, 211, 30, 50, 1000, 403, 4, 400, 77]
and when stack overflow is reached the array is
[2, 4, 18, 30, 50, 99, 77, 100, 211, 1000, 403, 305, 400, 2002]
class OtherQuickSort {
static void sort(int[] array){
quickSort(array, 0, array.length - 1)
}
static void quickSort(int[] array, int first, int last){
int pivotIndex = partition(array, first, last)
quickSort(array, first, pivotIndex - 1)
quickSort(array, pivotIndex, last)
}
static int partition(int[] array, int first, int last){
int pivotIndex = (first + last) / 2
int pivotValue = array[pivotIndex]
swapIndices(array, pivotIndex, last)
int indexFromRight = last - 1
int indexFromLeft = first
while(indexFromLeft <= indexFromRight){
while(array[indexFromLeft] < pivotValue){
indexFromLeft++
}
while(array[indexFromRight] > pivotValue){
indexFromRight--
}
if(indexFromLeft <= indexFromRight) {
swapIndices(array, indexFromLeft, indexFromRight)
indexFromLeft++
indexFromRight--
}
}
swapIndices(array, indexFromLeft, last)
indexFromLeft
}
static void swapIndices(int[] array, int left, int right){
int leftValue = array[left]
array[left] = array[right]
array[right] = leftValue
}
}

You need to update your quickSort method. Value at the pivotIndex is already in its sorted position so you need not pass it again.
static void quickSort(int[] array, int first, int last){
if(last > first){
int pivotIndex = partition(array, first, last);
quickSort(array, first, pivotIndex-1);
quickSort(array, pivotIndex+1, last);
}
}

Related

Could this algorithm be made better?

I have a question, in one of the algorithms, I had written, to seperate out, all the even numbers to the left and odd numbers to the right.
Example: Input:
{ 12, 10, 52, 57, 14, 91, 34, 100, 245, 78, 91, 32, 354, 80, 13, 67, 65 }
Output:
{12,10,52,80,14,354,34,100,32,78,91,245,91,57,13,67,65}
Below is the algorithm
public int[] sortEvenAndOdd(int[] combinedArray) {
int endPointer = combinedArray.length - 1;
int startPointer = 0;
for (int i = endPointer; i >= startPointer; i--) {
if (combinedArray[i] % 2 == 0) {
if (combinedArray[startPointer] % 2 != 0) {
int temp = combinedArray[i];
combinedArray[i] = combinedArray[startPointer];
combinedArray[startPointer] = temp;
startPointer = startPointer + 1;
} else {
while (combinedArray[startPointer] % 2 == 0 &&
(startPointer != i)) {
startPointer = startPointer + 1;
}
int temp = combinedArray[i];
combinedArray[i] = combinedArray[startPointer];
combinedArray[startPointer] = temp;
startPointer = startPointer + 1;
}
}
}
return combinedArray;
}
Anybody, have any suggestions, for it make it to O(n) or better ?
Your code is O(n), but it's a bit more complicated than it needs to be. Here's an improvement.
startPointer = 0;
endPointer = a.length - 1;
while (startPointer < endPointer)
{
if (a[startPointer] % 2 != 0)
{
// move endPointer backwards to even number
while (endPointer > startPointer && a[endPointer] % 2 != 0)
{
--endPointer;
}
swap(a[startPointer], a[endPointer]);
}
++startPointer;
}
By the way, the operation is more of a partition than a sort. I think a better function name would be partitionEvenOdd.
Make two queue one for even and another for odd . When any new number come push into respective queue and when all number finished then traverse first even queue and push into answer vector and then odd queue number . This is O(n) solution .I hope I am able to explain the solution .
Sorry for english.
If you want then I can post implementation but you should try.
You can't do it better than O(n) time, but you can make your code more concise.
Looking at your solution, since order of elements doesn't matter, you can simply keep a pointer variable which goes from last to first and keep swapping elements with this pointer.
Snippet:
private static void solve(int[] arr){
for(int i=arr.length-1,ptr = i;i>=0;--i){
if((arr[i] & 1) == 1){
swap(arr,i,ptr--);
}
}
}
private static void swap(int[] arr,int x,int y){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
Demo: https://onlinegdb.com/HyKNVMbwL
If the order of the elements matter
You can collect all odd ones in a new list.
Move all even ones to the left.
Assign all odd ones one by one from the list to the array from where even ones ended.
This will increase space complexity to O(n).

find permutation of an array with duplicates. Why pass by value in recursion (C++ implementation)

There are different ways to find all permutation of an integer array with duplicates. Here I only talk about the recursive method without using an additional "visited[]" array.
There correct way to do it is:
void helper(vector<vector<int>>& ans, vector<int> nums, int pos) {
if(pos == nums.size()-1) {
ans.push_back(nums);
return;
}
for(int i = pos; i < nums.size(); i++) {
if(i == pos || nums[i] != nums[pos]) {
swap(nums[i], nums[pos]);
helper(ans, nums, pos+1);
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
helper(ans, nums, 0);
return ans;
}
It is not so clear to me why it passes nums[] as a copy into the recursive function. So I looked around and on geeks for geeks , it says that "The idea is to fix the first character at first index and recursively call for other subsequent indexes". I was thinking that I can fix the first character then recursively call for the other subsequent indexes by passing nums[] as reference and "swap back" when recursion is done (as below). But unfortunately it did not work.
void helper(vector<vector<int>>& ans, vector<int>& nums, int pos) {
if(pos == nums.size()-1) {
ans.push_back(nums);
return;
}
for(int i = pos; i < nums.size(); i++) {
if(i == pos || nums[i] != nums[i-1]) {
swap(nums[i], nums[pos]);
helper(ans, nums, pos+1);
swap(nums[i], nums[pos]);
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
helper(ans, nums, 0);
return ans;
}
I am wondering what is wrong when passing nums[] as reference into recursion? Why passing nums[] by copy into recursion is correct?
I think I found the reason. Passing by value and passing by reference give two totally different algorithms. To understand that. Let's first note two important observations:
The first thing we did is to sort the array, why? because we want that all the permutations are visited in the "next permutation" order, i.e. 123, 132, 213, 231, 312, 321. So that there will be no duplicates.
The subproblem in the next recursion also maintained the sorted property. Let's use an example to illustrate this.
Input nums = [1,2,2,3] passing by value to recursion, with pos = 0,
i = 0: subproblem is [2,2,3],
i = 1: subproblem is [1,2,3],
i = 2: skipped,
i = 3 subproblem is [1,2,2].
All the subproblems in this level of recursion are all SORTED.
But if [1,2,2,3] is passed by reference, the subproblems are NOT sorted, so you can not reply on "next permutation" method to give you non-duplicated permutations.
If you are still confused, please take some time to read through this discussion:
https://discuss.leetcode.com/topic/8831/a-simple-c-solution-in-only-20-lines/28?page=2

using binary search to count occurrences

assume I have sorted array A in length n so 1
I need to write pseuodocode of a program that give output of all occurrences of each element.
the algorithm runtime has to be maximum k(c1+c2*log(n)).
example - A=[1,1,2,2,2,5,5,5,5] ----> (1,2)(2,3)(5,4)
I thought about using binary search when the first element I want to count is A[1] and I need to find his last occurrence.
then the next element is A[last occurrence index + 1] and so on.
I have a bit difficult with the idea and writig it down as pseuodocode.
tnx
Recursive algorithm, it gets left and right position and calculates middle position. Going deeper if there is number change, en edge. Up to here it is simple binary search. But once it detects (on distance=1) an edge, change of numbers, it will return it in 4 values: 'what number sequence ended', 'on what position', 'what started', 'on what position'. Parent node then merges these 4 values from left and right side and if it detects complete sequence 'in the middle', it immediately prints it and pass just ending edge (from left side) and starting edge (from right).
It is not possible to achieve that asymptotic complexity.
The reason is no matter what algorithm it is, When all the n elements are distinct, It has to return all the elements.That implies it has to read all of them.Of course, this operation takes O(n).
You can count number of occurrences for one entry in O(log(n))
static int count(int[] array, int target, int start, int end, Func<int, int, bool> compare)
{
if (end < start) { return start; }
int m = (start + end) / 2;
if (compare(target, array[m])) { return count(array, target, start, m - 1, compare); }
else { return count(array, target, m + 1, end, compare); }
}
static void Main(string[] args)
{
int[] a = { 1, 3, 8, 12, 12, 12, 25, 88 };
int r1 = count(a, 12, 0, a.Length - 1, (x1, x2) =>
{
return x1 < x2;
});
int r2 = count(a, 12, 0, a.Length - 1, (x1, x2) =>
{
return x1 <= x2;
});
Console.Out.WriteLine("count=" + (r1 - r2).ToString());
}

Odd elements at odd and even elements at even position

This is question asked in one of the interview. Please suggest some view.
Given an array containing all positive integers. You have to arrange elements in such a way that odd elements are at odd position and even elements are at even positions.
PS. No extra space. O(N) solution
Iterate over the even positions until you find an odd number. Iterate over the odd positions until you find and even number (using a different index). Swap the two numbers, and repeat.
Are you allowed to double the size of the array? Otherwise, the question doesn't make sense. Why?!? assume you are given an array full of odd numbers, can you think of any solution then? No, there is not.
So, I assume that you are allowed to double the size of the array. Then for any i, put the i-element ( a(i) ) into the location 2*i or 2*i +1 depending on whether a(i) is even or odd resp.
Two two new Arrays OddArray and EvenArray of same size as that of given array. Traverse through the given array and keep sending all the odd to OddArray and keep at odd positions and even number to EvenArray keeping numbers at even positions.
The efficiency will be O(n) and extra memory will be 2n where n is the size of original array.
list1 = [5, 7, 6, 8, 10, 3, 4, 9, 2, 1, 12]
odd_list = []
even_list = []
for i in range(len(list1)):
if((list1[i] % 2) == 0):
even_list.append(list1[i])
else:
odd_list.append(list1[i])
print(list1)
j = 0
k = 0
for i in range(0, len(list1)):
if((i % 2 == 0) and (j < len(odd_list))):
list1[i] = odd_list[j]
j += 1
elif(k < len(even_list)):
list1[i] = even_list[k]
k += 1
print(list1)
//Putting even number on even position and odd number on odd position
package com.learnJava;
public class ArrangeArray {
private int [] array={2,5,7,8,1,6,9};
private int len=array.length;
public static void main(String [] args)
{
ArrangeArray a=new ArrangeArray();
a.print();
a.arrange();
a.print();
}
public void print()
{
for(int i=0;i<array.length;i++)
{
System.out.print(array[i] + " ");
}
System.out.println();
}
public void arrange()
{
int oddinx=1;
int evenidx=0;
while(true)
{
while(evenidx<len && array[evenidx]%2==0)
{
evenidx+=2;
}
while(oddinx<len && array[oddinx]%2==1)
{
oddinx+=2;
}
if (evenidx < len && oddinx < len)
swap (evenidx, oddinx);
else
break;
}
}
public void swap(int a,int b)
{
int tmp=array[b];
array[b]=array[a];
array[a]=tmp;
}
}

Find Second largest number in array at most n+log₂(n)−2 comparisons [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question 12 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
You are given as input an unsorted array of n distinct numbers, where n is a power of 2. Give an algorithm that identifies the second-largest number in the array, and that uses at most n+log₂(n)−2 comparisons.
Start with comparing elements of the n element array in odd and even positions and determining largest element of each pair. This step requires n/2 comparisons. Now you've got only n/2 elements. Continue pairwise comparisons to get n/4, n/8, ... elements. Stop when the largest element is found. This step requires a total of n/2 + n/4 + n/8 + ... + 1 = n-1 comparisons.
During previous step, the largest element was immediately compared with log₂(n) other elements. You can determine the largest of these elements in log₂(n)-1 comparisons. That would be the second-largest number in the array.
Example: array of 8 numbers [10,9,5,4,11,100,120,110].
Comparisons on level 1: [10,9] ->10 [5,4]-> 5, [11,100]->100 , [120,110]-->120.
Comparisons on level 2: [10,5] ->10 [100,120]->120.
Comparisons on level 3: [10,120]->120.
Maximum is 120. It was immediately compared with: 10 (on level 3), 100 (on level 2), 110 (on level 1).
Step 2 should find the maximum of 10, 100, and 110. Which is 110. That's the second largest element.
sly s's answer is derived from this paper, but he didn't explain the algorithm, which means someone stumbling across this question has to read the whole paper, and his code isn't very sleek as well. I'll give the crux of the algorithm from the aforementioned paper, complete with complexity analysis, and also provide a Scala implementation, just because that's the language I chose while working on these problems.
Basically, we do two passes:
Find the max, and keep track of which elements the max was compared to.
Find the max among the elements the max was compared to; the result is the second largest element.
In the picture above, 12 is the largest number in the array, and was compared to 3, 1, 11, and 10 in the first pass. In the second pass, we find the largest among {3, 1, 11, 10}, which is 11, which is the second largest number in the original array.
Time Complexity:
All elements must be looked at, therefore, n - 1 comparisons for pass 1.
Since we divide the problem into two halves each time, there are at most log₂n recursive calls, for each of which, the comparisons sequence grows by at most one; the size of the comparisons sequence is thus at most log₂n, therefore, log₂n - 1 comparisons for pass 2.
Total number of comparisons <= (n - 1) + (log₂n - 1) = n + log₂n - 2
def second_largest(nums: Sequence[int]) -> int:
def _max(lo: int, hi: int, seq: Sequence[int]) -> Tuple[int, MutableSequence[int]]:
if lo >= hi:
return seq[lo], []
mid = lo + (hi - lo) // 2
x, a = _max(lo, mid, seq)
y, b = _max(mid + 1, hi, seq)
if x > y:
a.append(y)
return x, a
b.append(x)
return y, b
comparisons = _max(0, len(nums) - 1, nums)[1]
return _max(0, len(comparisons) - 1, comparisons)[0]
The first run for the given example is as follows:
lo=0, hi=1, mid=0, x=10, a=[], y=4, b=[]
lo=0, hi=2, mid=1, x=10, a=[4], y=5, b=[]
lo=3, hi=4, mid=3, x=8, a=[], y=7, b=[]
lo=3, hi=5, mid=4, x=8, a=[7], y=2, b=[]
lo=0, hi=5, mid=2, x=10, a=[4, 5], y=8, b=[7, 2]
lo=6, hi=7, mid=6, x=12, a=[], y=3, b=[]
lo=6, hi=8, mid=7, x=12, a=[3], y=1, b=[]
lo=9, hi=10, mid=9, x=6, a=[], y=9, b=[]
lo=9, hi=11, mid=10, x=9, a=[6], y=11, b=[]
lo=6, hi=11, mid=8, x=12, a=[3, 1], y=11, b=[9]
lo=0, hi=11, mid=5, x=10, a=[4, 5, 8], y=12, b=[3, 1, 11]
Things to note:
There are exactly n - 1=11 comparisons for n=12.
From the last line, y=12 wins over x=10, and the next pass starts with the sequence [3, 1, 11, 10], which has log₂(12)=3.58 ~ 4 elements, and will require 3 comparisons to find the maximum.
I have implemented this algorithm in Java answered by #Evgeny Kluev. The total comparisons are n+log2(n)−2. There is also a good reference:
Alexander Dekhtyar: CSC 349: Design and Analyis of Algorithms. This is similar to the top voted algorithm.
public class op1 {
private static int findSecondRecursive(int n, int[] A){
int[] firstCompared = findMaxTournament(0, n-1, A); //n-1 comparisons;
int[] secondCompared = findMaxTournament(2, firstCompared[0]-1, firstCompared); //log2(n)-1 comparisons.
//Total comparisons: n+log2(n)-2;
return secondCompared[1];
}
private static int[] findMaxTournament(int low, int high, int[] A){
if(low == high){
int[] compared = new int[2];
compared[0] = 2;
compared[1] = A[low];
return compared;
}
int[] compared1 = findMaxTournament(low, (low+high)/2, A);
int[] compared2 = findMaxTournament((low+high)/2+1, high, A);
if(compared1[1] > compared2[1]){
int k = compared1[0] + 1;
int[] newcompared1 = new int[k];
System.arraycopy(compared1, 0, newcompared1, 0, compared1[0]);
newcompared1[0] = k;
newcompared1[k-1] = compared2[1];
return newcompared1;
}
int k = compared2[0] + 1;
int[] newcompared2 = new int[k];
System.arraycopy(compared2, 0, newcompared2, 0, compared2[0]);
newcompared2[0] = k;
newcompared2[k-1] = compared1[1];
return newcompared2;
}
private static void printarray(int[] a){
for(int i:a){
System.out.print(i + " ");
}
System.out.println();
}
public static void main(String[] args) {
//Demo.
System.out.println("Origial array: ");
int[] A = {10,4,5,8,7,2,12,3,1,6,9,11};
printarray(A);
int secondMax = findSecondRecursive(A.length,A);
Arrays.sort(A);
System.out.println("Sorted array(for check use): ");
printarray(A);
System.out.println("Second largest number in A: " + secondMax);
}
}
the problem is:
let's say, in comparison level 1, the algorithm need to be remember all the array element because largest is not yet known, then, second, finally, third. by keep tracking these element via assignment will invoke additional value assignment and later when the largest is known, you need also consider the tracking back. As the result, it will not be significantly faster than simple 2N-2 Comparison algorithm. Moreover, because the code is more complicated, you need also think about potential debugging time.
eg: in PHP, RUNNING time for comparison vs value assignment roughly is :Comparison: (11-19) to value assignment: 16.
I shall give some examples for better understanding. :
example 1 :
>12 56 98 12 76 34 97 23
>>(12 56) (98 12) (76 34) (97 23)
>>> 56 98 76 97
>>>> (56 98) (76 97)
>>>>> 98 97
>>>>>> 98
The largest element is 98
Now compare with lost ones of the largest element 98. 97 will be the second largest.
nlogn implementation
public class Test {
public static void main(String...args){
int arr[] = new int[]{1,2,2,3,3,4,9,5, 100 , 101, 1, 2, 1000, 102, 2,2,2};
System.out.println(getMax(arr, 0, 16));
}
public static Holder getMax(int[] arr, int start, int end){
if (start == end)
return new Holder(arr[start], Integer.MIN_VALUE);
else {
int mid = ( start + end ) / 2;
Holder l = getMax(arr, start, mid);
Holder r = getMax(arr, mid + 1, end);
if (l.compareTo(r) > 0 )
return new Holder(l.high(), r.high() > l.low() ? r.high() : l.low());
else
return new Holder(r.high(), l.high() > r.low() ? l.high(): r.low());
}
}
static class Holder implements Comparable<Holder> {
private int low, high;
public Holder(int r, int l){low = l; high = r;}
public String toString(){
return String.format("Max: %d, SecMax: %d", high, low);
}
public int compareTo(Holder data){
if (high == data.high)
return 0;
if (high > data.high)
return 1;
else
return -1;
}
public int high(){
return high;
}
public int low(){
return low;
}
}
}
Why not to use this hashing algorithm for given array[n]? It runs c*n, where c is constant time for check and hash. And it does n comparisons.
int first = 0;
int second = 0;
for(int i = 0; i < n; i++) {
if(array[i] > first) {
second = first;
first = array[i];
}
}
Or am I just do not understand the question...
In Python2.7: The following code works at O(nlog log n) for the extra sort. Any optimizations?
def secondLargest(testList):
secondList = []
# Iterate through the list
while(len(testList) > 1):
left = testList[0::2]
right = testList[1::2]
if (len(testList) % 2 == 1):
right.append(0)
myzip = zip(left,right)
mymax = [ max(list(val)) for val in myzip ]
myzip.sort()
secondMax = [x for x in myzip[-1] if x != max(mymax)][0]
if (secondMax != 0 ):
secondList.append(secondMax)
testList = mymax
return max(secondList)
public static int FindSecondLargest(int[] input)
{
Dictionary<int, List<int>> dictWinnerLoser = new Dictionary<int, List<int>>();//Keeps track of loosers with winners
List<int> lstWinners = null;
List<int> lstLoosers = null;
int winner = 0;
int looser = 0;
while (input.Count() > 1)//Runs till we get max in the array
{
lstWinners = new List<int>();//Keeps track of winners of each run, as we have to run with winners of each run till we get one winner
for (int i = 0; i < input.Count() - 1; i += 2)
{
if (input[i] > input[i + 1])
{
winner = input[i];
looser = input[i + 1];
}
else
{
winner = input[i + 1];
looser = input[i];
}
lstWinners.Add(winner);
if (!dictWinnerLoser.ContainsKey(winner))
{
lstLoosers = new List<int>();
lstLoosers.Add(looser);
dictWinnerLoser.Add(winner, lstLoosers);
}
else
{
lstLoosers = dictWinnerLoser[winner];
lstLoosers.Add(looser);
dictWinnerLoser[winner] = lstLoosers;
}
}
input = lstWinners.ToArray();//run the loop again with winners
}
List<int> loosersOfWinner = dictWinnerLoser[input[0]];//Gives all the elemetns who lost to max element of array, input array now has only one element which is actually the max of the array
winner = 0;
for (int i = 0; i < loosersOfWinner.Count(); i++)//Now max in the lossers of winner will give second largest
{
if (winner < loosersOfWinner[i])
{
winner = loosersOfWinner[i];
}
}
return winner;
}

Resources