Element with left side smaller and right side greater in C - arrays

I'm very confused about the function implemented for the following code. What does the returning of 'i' mean? What is the exact logic behind it? If I do the dry run and return 'i', where is this 'i' getting returned to?
Given an array, find an element before which all elements are smaller than it, and after which all are greater than it. Return the index of the element if there is such an element, otherwise, return -1.
Input: arr[] = {5, 1, 4, 3, 6, 8, 10, 7, 9};
Output: 4
int SlideToTheLeft(int a[],int n){
int left[n], i;
left[0]=0;
for(i=1;i<n;i++){
left[i]=Max(left[i-1],a[i-1]);
}
int right=100;
for(i=n-1;i>=0;i--){
if(left[i]<a[i] && right>a[i]){
return i;
}
right=Min(right,a[i]);
}
return -1;
}

The first loop populates the "left" array. This array stores the largest value to the left of a given index. So for example, if left[3] is 7, we know that a[0], a[1], and a[2] are less than or equal to 7.
The second loop traverses the array from right to left, keeping track of the largest value to the right of the current index. We start with a value of right=100. This assumes that all values of a[] will be less than 100. We then traverse the array and update "right" if we encounter lower values of a[] than our current lowest. This is done in "right=Min(right,a[i]);".
Every time we go through the loop, we check for the condition where left[i]<a[i] (all indexes to the left are smaller than a[i], and right>a[i] (all indexes to the right are greater than a[i]. If we meet this condition, we return i (since this is the index which meets this condition).

Related

Counting Sort issue in array

I am making an algorithm for counting sort. In first step i have initialized the second array with 0. Secondly i counted the frequency of elements in second for loop. In third loop i am trying to sort the array. The third loop does not run in code blocks. Also it's not giving me right sorted result.Any issue with third loop. As it changes array to 1-1-2-0-2-2-0-1-1 rather it should be 0-0-0-1-1-1-1-2-2-2
printf("Hello world!\n");
unsigned m=3;
unsigned n=10;
unsigned x;
unsigned k;
unsigned data[10] = {0, 2, 1, 1, 0, 2, 2, 0, 1, 1};
unsigned *count;
count =(unsigned *)malloc(sizeof(unsigned)*m);
int y=sizeof(data);
for(int i=0;i<m;i++)
{
count[i]=0;
}
for(int j=0;j<n;j++)
{
x=data[j];
count[x]++;
}
for(k=n-1;k>=0;k--)
{
data[count[data[k]]-1]=data[k];
count[data[k]]=count[data[k]]-1;
}
for(int i=0;i<n;i++)
{
printf("%d \n",data[i]);
}
return 0;
}
In this line
for(k=n-1;k>=0;k--)
k is unsigned so k >= 0 is always true. When an unsigned integer would go below zero, its value "wraps".
Also, your sorting loop does not sort anything. It can't because there are no comparisons. You may like to review your algorithm.
The problem (in addition to the loop condition error mentioned in another answer) is that this appears to be a combination of two incompatible counting sort approaches.
The "traverse the input array backwards, inserting each element into the appropriate place in the output array" approach requires a separate output array. Consider the simple case of sorting {2, 1}: if we copy the 1 into the appropriate slot in the same array, it becomes {1, 1}, which will end up being our final output. Instead, that 1 needs to be placed into the appropriate slot of a separate array so that we don't overwrite the 2.
Additionally, this approach requires us to make a second pass over the count array to change its semantic meaning from "count of elements with value n" to "index of first element with value > n". This is accomplished by adding the total so far to each element of count (so in your case, count would go from {3, 4, 3} to {3, 7, 10}). After this step, count[n] - 1 is the index in the output array at which the next n should be placed.
Given that you're sorting integers, a second (easier) approach is also possible: once you've finished your initial traversal of the input array, count holds all the information you need, so you can freely overwrite the input array. Just start at the beginning and insert count[0] 0s, count[1] 1s, etc. This approach doesn't require any postprocessing of count or any separate output array.

Why is this code for implementing mergesort not producing correct result?

Here in I'm trying to implement mergesort on array of 10 elements. On providing the input a[10]={9,8,7,6,5,4,3,2,1,0} , I obtain the output as {0,0,1,1,0, 4,4,4,3,2} while the expected output is {0,1,2,3,4,5,6,7,8,9}. I am calling the mergesort in main with l=0,h=9.
void mergesort(int a[],int l,int h)
{
int c[10];
int m=(l+h)/2;
if(l<h)
{
mergesort(a,l,m); // Recursive call to sort first half
mergesort(a,m+1,h); // Recursive call to sort second half
}
int i,k=l,j=l;
while(k<=h) // Merging the first and second half of the array
{
if(a[j]<a[m+1])
{
c[k]=a[j];
k++;
j++;
}
else
{
c[k]=a[m+1];
k++;
m++;
}
}
for(i=l;i<=h;i++)
a[i]=c[i];
}
One of the few problems: Your value of l is no longer a valid left limit after the while loop since you are incrementing it. So when you are copying from array c to a later in the for loop, you are copying invalid data.
The problem is that in your while loop you are sometimes looking outside the bounds you should be.
Assuming you put in a check at the beginning of your function saying if l==h then return (since sorting a one element array is unnecessary) then the first time it will do anything is when it recurses to mergesort(a, 0,1). Here we are basically merging two single element arrays.
When going through your loop the first time we have i,j,k,m=0. We will go into the else part of the if because element 0 is greater than 1. We thus write out a[1] into the output array and we now have i,j=0 and k,m=1. What we now should do is note that our second array is exhausted and fill from the remaining elements in the first array.
Instead what we do is compare elements j and m+1 (ie 0 and 2). This is clearly wrong because element 2 shouldn't appear in the array. We of course find element 2 is smaller and thus put that into the output array at position two. Once we copy this over a we get {8, 7, 7, 6, 5, 4, 3, 2, 1, 0} and this is where it all goes wrong.

Algorithm:Sort using Median and Just 1 comparison in $ O(n \log n) $

I am trying to write an sorting algorithm which takes an input array and produces the sorted array. Following are the constraints for an algorithm.
Time complexity = $O(n \log n)$
Only one comparison operation throughout the algorithm.
We have a function which can provide an median for a set of three elements.
I have tried finding a solution and following is my result.
we use the median function to get the smallest and the largest pair.
Example: Give an array A[1..n], we get the median of the first three elements, lets call it a set and we receive a $Median$. In next Iteration we remove the received median from the set and add next element to the set and again call Median function. This step when repeated over the length produces a pair of the largest and the smallest element for the entire array.
We use this pair, use the comparison operation and place them at position A[0] & A[n-1].
We repeat the same operation over the array A[1..n-2] to get another pair of the largest and smallest.
We take the median with the A[0] and newly received pair.
Median Value is placed at the A[1].
We take the median with the A[n-1] and newly received pair.
Median Value is placed at the A[n-2].
Step 3~7 are repeated to get a sorted array.
This algorithm satisfies the condition 2 & 3 but not the time complexity. I hope if someone can provide some guidance how to proceed further.
Quicksort (presented in reverse order) works like this. Suppose you have an array:
[1, 4, 5, 2, 3]
Quicksort in the abstract basically works by sliding towards the middle of the array from both the left and the right side. As we slide inwards, we want to swap items such that big things get moved to the right, and small things get moved to the left. Eventually we should have an array where all the small stuff is on the left, and all the big stuff is on the right.
The upshot of this process also guarantees that one element will be placed in the correct location (because everything to the left of it will be smaller, and everything to the right will be bigger, so it must be in the right position). That value is called the pivot. The first step of quicksort is to ensure the pivot is in the right place.
The way we do this is by selecting a random element to be our pivot - the item we wan to put into it's correct place. For this simple example we'll just use the last number (3). The pivot is our comparison value.
Once we have selected our pivot/comparison value, we then monitor the left-most element (1), and the right-most element (3). We'll call these the left-pointer and the right-pointer. The left-pointers job is to slide towards the middle of the array, stopping when it finds something that is larger than the pivot. The right pointer does the same thing, but it slides inward looking for values less than the pivot. In code:
while (true) {
while (array[++left] < pivot);
while (array[--right] > pivot) if (left == right) break;
if (left >= right) break; // If the pointers meet then exit the loop
swap(array[left], array[right]); // Swap the values otherwise.
}
So in our example above, when the left-pointer hits (4) it recognizes that that is higher than our pivot element and stops moving. The right pivot does the same thing from the right side, but stops when it hits (2) because that's lower than the pivot. When both sides stop, we do a swap, so we end up with:
[1, 2, 5, 4, 3]
Notice that we are getting closer to sorted. We continue to move both pointers inward until they both point to the same element, or they cross - whichever comes first. When that happens, we make one final step, which is to replace the pivot element (3) with whatever point the left/right-pointers are pointing to, which in this case would be (5) because they would both stop right in the middle. Then we swap, so that we get:
[1, 2, 3, 4, 5]
(Notice that we swap the original pivot (3) with the value pointed to by both sides (5))
This whole process is called a partition. In code it looks like this:
int partition(int *array, int lBound, int rBound) {
int pivot = array[rBound]; // Use the last element as a pivot
int left = lBound - 1; // Point to one before the first element
int right = rBound; // Point to the last element;
// We'll break out of the loop explicity
while (true) {
while (array[++left] < pivot);
while (array[--right] > pivot) if (left == right) break;
if (left >= right) break; // If the pointers meet then exit the loop
swap(array[left], array[right]); // Swap the pointers otherwise.
}
swap(array[left], array[rBound]); // Move the pivot item into its correct place
return left; // The left element is now in the right place
}
It's important to note that although the partition step fully sorted our array in this example, that's not ordinarily the point of the partition step. The point of the paritition step is to put one element into it's correct place, and to ensure that everything left of that element is less and everything to the right is more. Or in other words, to move the pivot value into its correct location and then guarantee that everything left of the pivot is smaller than it, and everything to the right is bigger. So although in this example the array was completely sorted, in general we can only guarantee that one item and one item only is in the correct location (and everything to the left and right is bigger/smaller respectively). This is why the partition method above returns left, because it tells the calling function that this one element is in the correct location (and the array has been correctly partitioned).
That is if we start with an array like:
[1, 7, 5, 4, 2, 9, 3]
Then the partition step would return something like this:
[1, 3, 2, [4], 7, 5, 9]
Where [4] is the only value guaranteed to be in the right place, but everything to the left is smaller than [4] and everything to the right is bigger (though not necessarily sorted!).
The second step is to perform this step recursively. That is, if we can put one element into it's correct location, then we should be able to eventually put all items into their correct location. That is the quicksort function. In code:
int *quicksort(int *array, int lBound, int rBound) {
if (lBound >= rBound) return array; // If the array is size 1 or less - return.
int pivot = partition(array, lBound, rBound); // Split the array in two.
quicksort(array, lBound, pivot - 1); // Sort the left size. (Recursive)
quicksort(array, pivot + 1, rBound); // Sort the right side. (Recursive)
return array;
}
Notice that the first step is to ensure that we have an array side of at least 2. It doesn't make sense to process anything smaller than that so we return if that condition isn't met. The next step is to call our partition function which will split the array according to the process outlined above. Once we know that the array has one element that is in correct position, we simply call quicksort again, but this time on the left side of the pivot, and then again on the right side of the pivot. Notice we don't include the pivot because the partition is guaranteed to put that into the correct location!
If we continue to call quicksort recursively, eventually we'll halve the array and partition it until we get arrays of size-one (which by definition is already sorted). So we partition, then halve, partition, halve, etc. until the entire array is sorted (in place). This gives us a sort in O(n lg(n)) time. Cool!
Here's a quick example of it's use:
int main() {
int array [] {1, 0, 2, 9, 3, 8, 4, 7, 5, 6};
quicksort(array, 0, 9); // Sort from zero to 9.
// Display the results
for (int index = 0; index != 10; ++index) {
cout << array[index] << endl;
}
return 0;
}
A good visual demonstration can be found here: http://www.youtube.com/watch?v=Z5nSXTnD1I4
Steps 1 and 2 are indeed the first steps of a correct solution. Once you know the smallest and largest elements, though, the median oracle is a comparison oracle; if you want to compare a[i] with a[j], then a[i] < a[j] exactly when a[i] = median(a[i], a[j], a[0]) where a[0] is the smallest element. So you can run straight quicksort or mergesort or whathaveyou.

Swap number array from lowest to highest

I'm trying to come up with an algorithm to sort
number array { 5,3,6,5,4} into the result {3,4,5,5,6} from lowest to highest highest.
I have a basic idea: treat element 0 to be your min variable. if that min is greater than the next element then swap. then test if second element is greater than the third element and swap. but the result are not coming out right
I came up with a swap formula but it only works for two elements
int temp = numArray[0];
numArray[0]= numArray[1];
numArray[1]= temp;
You're looking for Bubblesort. Your method of just checking consecutive elements won't work.
For example, it won't work for the input [1, 3, 2, 5, 4, 3, 6].

Interleave array in constant space

Suppose we have an array
a1, a2,... , an, b1, b2, ..., bn.
The goal is to change this array to
a1, b1, a2, b2, ..., an, bn in O(n) time and in O(1) space.
In other words, we need a linear-time algorithm to modify the array in place, with no more than a constant amount of extra storage.
How can this be done?
This is the sequence and notes I worked out with pen and paper. I think it, or a variation, will hold for any larger n.
Each line represents a different step and () signifies what is being moved this step and [] is what has been moved from last step. The array itself is used as storage and two pointers (one for L and one for N) are required to determine what to move next. L means "letter line" and N is "number line" (what is moved).
A B C D 1 2 3 4
L A B C (D) 1 2 3 4 First is L, no need to move last N
N A B C (3) 1 2 [D] 4
L A B (C) 2 1 [3] D 4
N A B 1 (2) [C] 3 D 4
L A (B) 1 [2] C 3 D 4
N A (1) [B] 2 C 3 D 4
A [1] B 2 C 3 D 4 Done, no need to move A
Note the varying "pointer jumps" - the L pointer always decrements by 1 (as it can not be eaten into faster than that), but the N pointer jumps according to if it "replaced itself" (in spot, jump down two) or if it swapped something in (no jump, so the next something can get its go!).
This problem isn't as easy as it seems, but after some thought, the algorithm to accomplish this isn't too bad. You'll notice the first and last element are already in place, so we don't need to worry about them. We will keep a left index variable which represents the first item in the first half of the array that needs changed. After that we set a right index variable to the first item in the 2nd half of the array that needs changed. Now all we do is swap the item at the right index down one-by-one until it reaches the left index item. Increment the left index by 2 and the right index by 1, and repeat until the indexes overlap or the left goes past the right index (the right index will always end on the last index of the array). We increment the left index by two every time because the item at left + 1 has already naturally fallen into place.
Pseudocode
Set left index to 1
Set right index to the middle (array length / 2)
Swap the item at the right index with the item directly preceding it until it replaces the item at the left index
Increment the left index by 2
Increment the right index by 1
Repeat 3 through 5 until the left index becomes greater than or equal to the right index
Interleaving algorithm in C(#)
protected void Interleave(int[] arr)
{
int left = 1;
int right = arr.Length / 2;
int temp;
while (left < right)
{
for (int i = right; i > left; i--)
{
temp = arr[i];
arr[i] = arr[i - 1];
arr[i - 1] = temp;
}
left += 2;
right += 1;
}
}
This algorithm uses O(1) storage (with the temp variable, which could be eliminated using the addition/subtraction swap technique) I'm not very good at runtime analysis, but I believe this is still O(n) even though we're performing many swaps. Perhaps someone can further explore its runtime analysis.
First, the theory: Rearrange the elements in 'permutation cycles'. Take an element and place it at its new position, displacing the element that is currently there. Then you take that displaced element and put it in its new position. This displaces yet another element, so rinse and repeat. If the element displaced belongs to the position of the element you first started with, you have completed one cycle.
Actually, yours is a special case of the question I asked here, which was: How do you rearrange an array to any given order in O(N) time and O(1) space? In my question, the rearranged positions are described by an array of numbers, where the number at the nth position specifies the index of the element in the original array.
However, you don't have this additional array in your problem, and allocating it would take O(N) space. Fortunately, we can calculate the value of any element in this array on the fly, like this:
int rearrange_pos(int x) {
if (x % 2 == 0) return x / 2;
else return (x - 1) / 2 + n; // where n is half the size of the total array
}
I won't duplicate the rearranging algorithm itself here; it can be found in the accepted answer for my question.
Edit: As Jason has pointed out, the answer I linked to still needs to allocate an array of bools, making it O(N) space. This is because a permutation can be made up of multiple cycles. I've been trying to eliminate the need for this array for your special case, but without success.. There doesn't seem to be any usable pattern. Maybe someone else can help you here.
It's called in-place in-shuffle problem. Here is its implementation in C++ based on here.
void in_place_in_shuffle(int arr[], int length)
{
assert(arr && length>0 && !(length&1));
// shuffle to {5, 0, 6, 1, 7, 2, 8, 3, 9, 4}
int i,startPos=0;
while(startPos<length)
{
i=_LookUp(length-startPos);
_ShiftN(&arr[startPos+(i-1)/2],(length-startPos)/2,(i-1)/2);
_PerfectShuffle(&arr[startPos],i-1);
startPos+=(i-1);
}
// local swap to {0, 5, 1, 6, 2, 7, 3, 8, 4, 9}
for (int i=0; i<length; i+=2)
swap(arr[i], arr[i+1]);
}
// cycle
void _Cycle(int Data[],int Lenth,int Start)
{
int Cur_index,Temp1,Temp2;
Cur_index=(Start*2)%(Lenth+1);
Temp1=Data[Cur_index-1];
Data[Cur_index-1]=Data[Start-1];
while(Cur_index!=Start)
{
Temp2=Data[(Cur_index*2)%(Lenth+1)-1];
Data[(Cur_index*2)%(Lenth+1)-1]=Temp1;
Temp1=Temp2;
Cur_index=(Cur_index*2)%(Lenth+1);
}
}
// loop-move array
void _Reverse(int Data[],int Len)
{
int i,Temp;
for(i=0;i<Len/2;i++)
{
Temp=Data[i];
Data[i]=Data[Len-i-1];
Data[Len-i-1]=Temp;
}
}
void _ShiftN(int Data[],int Len,int N)
{
_Reverse(Data,Len-N);
_Reverse(&Data[Len-N],N);
_Reverse(Data,Len);
}
// perfect shuffle of satisfying [Lenth=3^k-1]
void _PerfectShuffle(int Data[],int Lenth)
{
int i=1;
if(Lenth==2)
{
i=Data[Lenth-1];
Data[Lenth-1]=Data[Lenth-2];
Data[Lenth-2]=i;
return;
}
while(i<Lenth)
{
_Cycle(Data,Lenth,i);
i=i*3;
}
}
// look for 3^k that nearnest to N
int _LookUp(int N)
{
int i=3;
while(i<=N+1) i*=3;
if(i>3) i=i/3;
return i;
}
Test:
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int length = sizeof(arr)/sizeof(int);
in_place_in_shuffle(arr, length);
After this, arr[] will be {0, 5, 1, 6, 2, 7, 3, 8, 4, 9}.
If you can transform the array into a linked-list first, the problem becomes trivial.

Resources