Merge sort function in C - c

I have the following piece of code which represents a merge sort function
/* perform merge sort */
void merge_sort(int arr[], int left, int right) {
if (left < right) {
int middle = left + (right - left) / 2;
merge_sort(arr, left, middle);
merge_sort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
What is the use of this merge_sort(arr, middle + 1, right);?

The basic idea of the merge sort algorithm is to divide the sequence to be sorted in half, sort each half, and then merge them together. This is frequently done recursively, as in this case. As a result, there must be two recursive calls, one for each half of the sequence.
If the merge_sort(arr, middle+1, right); call were not present, the algorithm would not be complete and the sort would not work.
As an experiment, you could try writing an example program using the merge sort function you posted. Try it with and without the line in question and see what results you get.

Related

merge sort understanding recursion

I want to understand how does it work like I have this thing.
void merge_sort(int *a, int first, int last)
{
int middle;
if (first < last)
{
middle = (first + last) / 2;
merge_sort(a, first, middle); // 1
merge_sort(a, middle + 1, last); // 2
merge(a, first, middle, last); // 3
}
}
how does it work like if have an array of 3,4,2,1,5 it will first cut it in half from <--middle side and only then it will go to line 2-merge_sort(a, middle+1, last); and it will restart first and last until the condition is made and then it will go to line 3 like does all that stuff happen one after another or does it all happen at the same time all the 3 lines?
Yes, it sorts the first half, then it sorts the 2nd half and then it merges the two sorted parts together. This happens sequentially. The two recursive merge_sort() calls could happen in parallel (as they are non-overlapping) but it doesn't in this implementation.

How to choose pivot value in QuickSort?

I have been studying quick sort for a few hours and am confused about choosing a pivot value. Does the pivot value need to exist in the array?
For example if the array is 1,2,5,6 , can we use the value 3 or 4 as a pivot?
We use the position of pivot for dividing the array into sub-arrays but I am a little confused about what will be the pivot position after we move values < 5 to left of the array and values > 5 to right?
7,1,5,3,3,5,8,9,2,1
I dry runned the algo with the pivot 5 and came with the following result:
1,1,5,3,3,5,8,9,2,7
1,1,5,3,3,5,8,9,2,7
1,1,5,3,3,5,8,2,9,7
We can see that the value 2 is still not in the correct position. What am i doing wrong? Sorry if it's a silly question.
I came up with the following code but it's only working when pivot = left, I can't use a random pivot.
template <class T>
void quickSort(vector <T> & arr, int p, int r, bool piv_flag) {
if (p < r) {
int q, piv(p); counter++;
//piv = ((p + r) / 2); doesn't work
q = partition(arr, p, r, piv);
quickSort(arr, p, q - 1, piv_flag); //Sort left half
quickSort(arr, q + 1, r, piv_flag); //Sort right half
}
return;
}
int partition(vector <T> & arr, int left, int right, int piv) {
int i{ left - 0 }, j{ right + 0 }, pivot{ arr[piv] };
while (i < j) {
while (arr[i] <= pivot) { i++; }
while (arr[j] > pivot) { j--; }
if (i < j) (swap(arr[i], arr[j]));
else {
swap(arr[j], arr[piv]);
return j;
}
}
}
Thank you.
In many applications the pivot is chosen as some element in the array, but it can also be any value you may use to separate the numbers in the array into two. If pivot value you choose is a specific element in the array you need to place it between those two groups after you partition the array into two. If not, you can just proceed with the recursive sorting process by calling the indices properly. (i.e. keeping in mind that there is no pivot element in the array, but just the two groups of values)
See this response to a similar question for a concise explanation of some widely-used alternatives for selecting a pivot.
The most important function of the pivot as to serve as a boundary between the groups we are trying to create during the partitioning phase of quicksort. The goal/challenge here is to create those groups in such a way that they are equal or almost equal in size so that quicksort can work efficiently. That challenge is the reason so many pivot selection methods are conceived. (i.e. so that at least in most cases the numbers will be separated into groups of similar size)
As to the second part of your question regarding how the position of the pivot will change once the partitioning is done, see below for a sample partitioning phase.
Say we have an array A with elements [4,1,5,3,3,5,8,9,2,1] and we chose pivot to be the first element, namely 4. The letter E used below indicates the end of the elements that are smaller than the pivot. (i.e. the last element that is smaller than the pivot)
E
[4,1,5,3,3,5,8,9,2,1]
E
[4,1,3,5,3,5,8,9,2,1]
E
[4,1,3,3,5,5,8,9,2,1]
E
[4,1,3,3,2,5,8,9,5,1]
E
[4,1,3,3,2,1,8,9,5,5]
[1,1,3,3,2,4,8,9,5,5] // swap pivot with the rightmost element that is smaller than its value
After this partitioning, the elements are still not sorted, obviously. But all the elements that is to the left of 4 are smaller than 4, and all the ones to its right are larger than 4. To sort them, we recursively use Quicksort on those groups.
Based on your code, below is a sample partitioning code based on the procedure I described above. You may also observe its execution here.
template <class T>
int partition(vector<T>& arr, int left, int right, int piv) {
int leftmostSmallerThanPivot = left;
if(piv != left)
swap(arr[piv], arr[left]);
for(int i=left+1; i <= right; ++i) {
if(arr[i] < arr[left])
swap(arr[++leftmostSmallerThanPivot], arr[i]);
}
swap(arr[left], arr[leftmostSmallerThanPivot]);
return leftmostSmallerThanPivot;
}
template <class T>
void quickSort(vector<T>& arr, int p, int r) {
if (p < r) {
int q, piv(p);
piv = ((p + r) / 2); // works
q = partition(arr, p, r, piv);
quickSort(arr, p, q - 1); //Sort left half
quickSort(arr, q + 1, r); //Sort right half
}
}

What is the purpose of swap(v, left, (left + right)/2) in K&R's qsort() implementation?

in K&R second edition, section 5.11, page 107:
void qsort(void *v[], int left, int right, int (*comp)(void *, void *))
{
int i, last;
void swap(void *v[], int, int);
if (left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if ((*comp)(v[i], v[left]) < 0) /* Here's the function call */
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1, comp);
qsort(v, last+1, right, comp);
}
However, I am confused about the "swap(v, left, (left + right)/2);". I think it is useless... What's the purpose of this sentence?
If the sentence is absent, there is no problem if the array V[ ] is random data.
However, if V[ ] is sorted data, no swap is encountered,
and the variable last is not changed.
Thus, last qsort() is equivalent to qsort(v, left+1, right, comp).
It means that only one element decreased in recursive call.
When comparison number of times in the function is n,
comparison needs n + (n-1) + (n-2) + ... + 1 = n(n+1)/2 times to complete.
It takes a long time if n is big.
Furthermore, if V[ ] is very large, stack overflow error may be encountered.
The statement exists to prevent them.
In addition, (left + right) / 2 should be left + (right - left) / 2
to prevent overflow error.
This swap is meant to pick the pivot element and place it at the leftmost position. Then, the variable last is used to count how many elements were greater than the pivot hance belong to the right partition. We don't actually compute the number, though - but only a position of the leftmost element of the right partition. After that, we can safely place the pivot back to where it belongs (exactly to the left of the right partition) - this is what the second swap does - and form the left partition at no cost since we know for sure that all elements that are not the pivot or right partition must belong to the left one.
Still, I strongly recommend to to simply take a piece of paper, write some random integer array and try to walk through the code line by line to see how the partitioning process is performed.

Quick sort programmed in C

I am reading ANSI C by K&R. I came across the qsort program. I want a little help. Suppose I have 9 elements with index 0->8. Please read the comments to see if I am understanding it correct or not. Thanks a lot for you efforts
void qsort(int v[] , int left, int right)
{
int i, j, last;
void swap(int v[], int i, int j);
if(left >= right) /*if the array has only one element return it*/
return;
swap(v,left, (left+right)/2); /* now, left=(left+right)/2= 0+8/2= 4 we have 4 as left*/
last= left; /* putting left = last of the first partition group i.e. last=4*/
for(i=left+1; i<=right,i++) /* now looping from 4+1=5 to 8 with increment of 1*/
if(v[i] < v[left]) /*if value at 5th is less than value at 4th */
swap(v, ++last, i);
I have problem in this last swap step. As my values suggest swap ++4 i.e. to i i.e. 4+1= 5 (swapping 5 position with 5?). How can I understand this? There must be a swapping between 4 and 5, not 5 and 5 is it?
code continues
swap(v,left, last);
qsort(v,left,last-1);
qsort(v,last+1,right);
}
Firstly, you have a small misconception about the swap function. Let's say the prototype of the function is -
swap(int array[], int i, int j)
The swap function swaps the numbers at location array[i] and array[j]. So, the swap function swaps the elements in the array. So, the line -
swap(v, left, (left + right) / 2);
Means that, the middle element in the array is swapped with the leftmost element. Clearly, the quicksort is taking the middle element as the pivot. This swap has no effect on the local variables or parameters. According to your data input example, the value of 'left' = 0, and the value of right = '8', even after the swapping. This is where you got confused. The elements of array are swapped, not the values of variables. So, now, the line -
last = left;
makes, 'last' point to the location of the pivot ('left'), so here the value of 'last' = 0 not 4. So, the loop,
for(i = left + 1; i <= right; i++)
Runs from i = 1 to 8. BTW, you forgot the semicolon..! Then, the line,
if(v[i] < v[left])
checks if the current element ('v[i]') is less than the pivot ('v[left]') or not. Then, accordingly swaps the lesser elements as in the line,
swap(v, ++last, i);
from the location (last + 1) till where ever it increments to. So, the elements to the left of 'last' are less than pivot and the elements to the right are greater. I think you are missing another line, where we bring the pivot back to the middle which was at the location 'v[left]' during the execution of the algorithm. Then, the recursive calls play their roles. If you are looking for help with quicksort, this is a good place to start !
I hope my answer has helped you, if it did, let me know..! ☺

quicksort special case - seems to be a faulty algorithm from K&R

I have a problem understanding quicksort algorithm (the simplified version without pointers) from K&R. There is already a thorough explanation provided by Dave Gamble here explanation.
However I noticed that by starting with a slightly changed string we can obtain no swaps during many loops of the for loop.
Firstly the code:
void qsort(int v[], int left, int right)
{
int i, last;
void swap(int v[], int i, int j);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2); /* move partition elem */
last = left; /* to v[0] */
for (i = left + 1; i <= right; i++) /* partition */
if (v[i] < v[left])
swap(v, ++last, i);
swap(v, left, last); /* restore partition elem */
qsort(v, left, last-1);
qsort(v, last+1, right);
}
Walkthrough in my opinion:
we start with CADBE; left=0; right=4; D is the pivot
so according to algorithm we swap D with C obtaining DACBE
last = left =0
i = 1 if ( v1 < v[0] ) it is true so we swap v1 (because last is incremented before operation) with v1 so nothing changes, last = 1, still having DACBE;
now i = 2 if ( v[2] < v[0] ) -> true so we swap v[2] with v[2] nothing changed again; last = 2
now i = 3 if ( v[3] < v[0] ) -> true so we swap v[3] with v[3] nothing changed AGAIN (!), last = 3
So apparently something is wrong, algorithm does nothing.
Your opinions appreciated very much. I must be wrong, authors are better than me ;D
Thanks in advance!
The loop goes from left + 1 up to and including right. When i=4, the test fails and last does not get incremented.
Then the recursive calls sort BACDE with left=0,right=2 and left=4,right=4. (Which is correct when D is the pivot.)
Well, it just so happened that your input sub-array ACBE is already partitioned by D (ACB is smaller than D and E is bigger than D), so it is not surprising the partitioning cycle does not physically swap any values.
In reality, it is not correct to say that it "does nothing". It does not reorder anything in the cycle, since your input data need no extra reordering. But it still does one thing: it finds the value of last that says where smaller elements end and bigger elements begin, i.e. it separates ACBE into ACB and E parts. The cycle ends with last == 3, which is the partitioning point for further recursive steps.

Resources