Can not print properly a quicksort arranged matrix - c

I can not properly print the steps given by the quicksort algorithm. This function works when N=1, which means that the values in the matrix only repeat once, but for N>1 it does not print it properly.
This is for a program I am writing to represent the different sorting algorithms steps with the console.
void quicksort(int *target, int left, int right) {
char charac[MAX*N][MAX]; // this is the array I am going to print on screen
if(left >= right)
return;
int i = left, j = right;
int tmp, pivot = target[i];
for(;;) {
while(target[i] < pivot)
i++;
while(pivot < target[j])
j--;
if(i >= j)
break;
tmp = target[i];
target[i] = target[j];
target[j] = tmp;
i++; j--; //normal quicksort until here
for(int k=0;k<MAX*N;k++){ /*Here begin two loops that put the cursor on a certain point on the screen and then gives values to char[][]*/
GotoXY(k+30,5);
for(int l=0;l<MAX;l++){
If(l<target[k]) // if the value of the given vector is lower than l writes a space
charac[k][l]=32;
else
charac [k][l]=219; // else a block
printf("%c ",charac[k][l]); // print the block or space
GotoXY(k+35,5+l); // go to the next point of the column
}
printf("\n");
}
system("cls"); // clear the screen for the next graph
}
quicksort(target, left, i-1);
quicksort(target, j+1, right);
}
I expect to sort the values properly even if they are repeated but the result are not even close to that.
Here it is for N=1 at the beginning:
At the end:
With N=2 it is generated properly:
But this is the result:
It is not even close to something fine.
Thanks for your time.

Related

Bubble Function sorting in C on an array of integers

I have coded out a Bubble Function that is supposed to Bubble sort an array of user input integers, but for some reason, my array is only working with arrays with size 6... otherwise the array outputs a zero for the largest number. Please run this code and help me identify the problem.
#include <stdio.h>
//prototype
void bubble(int array[], int size);
int main(void)
{
int n,i,j,size,temp,counter = 0;
//FOR SOME REASON, ONLY INPUT SIZE 6 WORKS PERFECTLY.
int k;
printf("How many numbers to sort?\n");
scanf("%d",&size);
int array[size];
for(i=0;i<size;i++)
{
printf("Enter number %d\n",i+1);
scanf("%d",&k);
array[i] = k;
}
printf("Array before sorting:\n");
for(i=0;i<size;i++)
{
printf("%d ",array[i]);
}
bubble(array,size);
return 0;
}
// use this if you want to test print an array
// for(i=0;i<size;i++)
// {
// printf("%d",array[i]);
// }
void bubble(int array[], int size)
{
int i, j, temp;
for(j=0;j<size;j++)
{
printf("\nIteration# %d\n",j+1);
for(i=0;i<size;i++)
{
if(array[i] > array[i+1])
{
temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
}
printf("%4d",array[i]);
}
}
}
// void select(int array[], int size)
// {
// int i, j, temp;
// min = array[0];
// for(j=0;j<size;j++)
// {
// if(array[j] < min)
// {
// array[j] = temp;
// min = array[j];
// }
// }
// }
Your inner-loop top-end conditional break is size, but within the loop you reference array[i+1], which means you're referring to array[size]. Since C arrays are zero-base indexed, the only allowable indexing is from 0...(size-1). Your code breaches that by one item repeatedly.
Changing the top-end of the inner loop to size-1 will work in your case. but there is arguably a better alternative that alleviates you from remembering the minus-1 in the first place. It involves modifying size as you sort to control the top-end of your inner loop directly. It also eliminates one local variable that you no longer need).
void bubble(int array[], int size)
{
while (size-- > 0)
{
for(int i=0; i<size; ++i)
{
if(array[i] > array[i+1])
{
int temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
}
}
}
}
Often called a "goes-down-to" expression (because it looks like a long arrow pointing at a limiting value), the outer loop has been changed to become while (size-- > 0). This takes the current value of size to a temporary, decrements size, and compares the temporary against > 0 (more or less). The result is size now reflects the top limit of your inner loop that you want. Each enumeration of the outer loop will shrink the next inner loop pass by one. The point of bubble sort is that, once an element has been "bubbled up" to its proper position, you need not visit that element ever again, something your code is not taking advantage of.
Bonus Optimization
Finally, you can optimize this further and give your bubblesort the one and only redeeming quality the algorithm can offer: O(n) in best case where the sequence is already sorted. You do this by doing "swap-detection". If you ever pass over the inner loop without making a single swap, it makes no sense to perform anymore sorting. The sequence is sorted and you're done. It's a near-freebie addition to the original algorithm above, and looks like this:
void bubble(int array[], int size)
{
int swapped = 1;
while (swapped && size-- > 0)
{
swapped = 0;
for(int i=0; i<size; ++i)
{
if(array[i] > array[i+1])
{
int temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
swapped = 1;
}
}
}
}
Given an already sorted sequence of a ten, a hundred, or a hundred-thousand elements, this will finish after only one pass. Worth noting: even one element out of position on one extreme end will make this optimization irrelevant. I.e. if any element that belongs near the beginning is originally near the end, it will take up to size iterations to bring it home, and with that the optimization becomes moot. In short, this sequence
1 3 4 5... 9998 9999 2
will completely foil the optimization above. There are techniques to combat this as well including a two pass inner loop enumeration, where you ascend to bubble up larger values, then reverse direction to descend, bubbling down smaller values. but at this point you're better off using a finer algorithm like quicksort or heapsort. The discussion of that, and indeed the latter half of this post, is beyond the scope of your question.
i<size in combination with i+1 will go past the bounds of the array.
You should replace this:
for(i=0;i<size;i++)
with this:
for(i=0;i<size-1;i++)

I dont understand this step particularly in mergesort [duplicate]

This question already has answers here:
How does the Pseudocode for merge sort work?
(2 answers)
Closed 6 years ago.
In the above code i dont understand this. it calls merge sort again but when do merge come into play as the function repeatedly calls mergesort
but when do merge happens
The code i could not understand is recursive one that how after breaking into halves and repeated calling of mergesort and breaking inrtoa single elment merge comes into play.
REAL QUESTION WAS HOW REAL COMES INTO PLAY
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 50000
void merge (int arr[], int start, int mid, int end){
/* two sorted arrays arr[start ... mid]
and arr[mid+1 ... end] merge them */
int tempvals[MAX_SIZE];
int ptr1, ptr2, ptrnew=0, idx;
ptr1 = start;
ptr2 = mid+1;
/* compare both the sorted arrays element by element
move the element that is smaller to the new aray */
while ( (ptr1 <= mid) && (ptr2 <= end)){
/* compare elements at ptr1 and ptr2 */
if (arr[ptr1] < arr[ptr2]){
tempvals[ptrnew] = arr[ptr1];
ptr1 ++; ptrnew++;
} else {
tempvals[ptrnew] = arr[ptr2];
ptr2 ++; ptrnew++;
}
}
/* at this point --> one of the pointers has reached the end */
while (ptr1 <= mid){
tempvals[ptrnew] = arr[ptr1];
ptr1 ++; ptrnew++;
}
while (ptr2 <= end){
tempvals[ptrnew] = arr[ptr2];
ptr2 ++; ptrnew++;
}
/* transfer back to arr */
for (idx = start, ptrnew = 0; idx <= end; idx++, ptrnew++)
arr[idx] = tempvals[ptrnew];
}
void merge_sort (int arr[], int start, int end){
int mid = (start + end)/2;
/* termination condition */
if( start >= end) return;
/* recurse */
merge_sort(arr,start, mid); /* first half */
merge_sort (arr, mid+1, end); /* second half */
merge (arr, start, mid, end); /* do the merging */
}
void print_array (int arr[], int size){
int i;
for (i=0; i < size; i++)
printf ("%d ",arr[i]);
printf ("\n");
}
int main(){
int arr[MAX_SIZE];
int i;
/* initialize */
for (i=0; i < MAX_SIZE; i++)
arr[i] = rand();
/* sort and print */
merge_sort (arr,0, MAX_SIZE - 1);
}
Blockquote
In the above code i dont understand this
it calls merge sort again but when do merge come into play as the function repeatedly calls mergesort
/* recurse */
merge_sort(arr,start, mid); /* first half */
merge_sort (arr, mid+1, end); /* second half */
merge (arr, start, mid, end); /* do the merging */
It's under the comment recurse, and called out in the line-by-line comments. You recur on merge_sort to sort the left part of the array, the right part. Then you call merge to reunite them, now in order.
You do not call merge_sort forever: note the base case (a.k.a. termination condition) at the top of merge_sort:
if( start >= end) return;
When you get to a list of no more than one element, you simply return -- it's already in order. Then you crawl back up that large call chain, merging single elements, then larger lists, ... until you're done.

quicksort comparison count intermittent results

SOLUTION the solution is unique to my code -- I placed srand(time(NULL)); inside the loop when it should've been placed outside
I'm trying to count the number of comparisons in a quick sort algorithm. I had a recursive version working fine, but it kept seg faulting because I was using large array sizes -- running out of stack space.
So now I've resulted to an iterative approach, and it works. That is, except for my counter for the number of comparisons.
It's returning intermittent results such as...
unsorted: [9][8][7][6][5][4][3][2][1][0]
sorted: [0][1][2][3][4][5][6][7][8][9]
Numer of comparisons: 22
unsorted: [9][8][7][6][5][4][3][2][1][0]
sorted: [0][1][2][3][4][5][6][7][8][9]
Numer of comparisons: 19749794
unsorted: [9][8][7][6][5][4][3][2][1][0]
sorted: [0][1][2][3][4][5][6][7][8][9]
Numer of comparisons: 6088231
my code for the iterative quick sort is...
#include <time.h>
#define BUFLEN 6400
extern int buf[BUFLEN];
extern int quick_count; //comparison count
struct stack {
int stk[BUFLEN];
int top;
};
struct stack s;
void push(int x);
int pop();
void iterative_quick_sort (int buf[], int n) {
int left_ptr, right_ptr, pivot_index, pivot, temp, l, r;
if (n < 2) //case the partitioning has reached the atomic element
return;
r = n - 1;
l = 0;
s.top = -1;
loop: do{
srand(time(NULL));
if ((r - l) == 0)
pivot_index = 1;
else {
pivot_index = rand() % (r - l);
pivot_index += l;
}
pivot = buf[pivot_index]; //pivot holds the value of the pivot element
left_ptr = l;
right_ptr = r;
if ((r - l) != 0 || (r - l) != 1){
while (1) {
while (buf[left_ptr] < pivot){ //loop and increment left_ptr until an element on the left side is larger than the pivot
left_ptr++;
} //now left_ptr holds the index of the value that needs to be swapped with an element from the right side
while (pivot < buf[right_ptr]){ //loop and increment right_ptr until an element on the right side is smaller than the pivot
right_ptr--;
} //now right_ptr holds the index of the value that needs to be swapped with an element from the left side
quick_count++;
if (left_ptr >= right_ptr)
break; //once the pivots reach or overlap each other, break the loop
//perform swap with temporary variable temp
temp = buf[left_ptr];
buf[left_ptr] = buf[right_ptr];
buf[right_ptr] = temp;
}
}
if (l == (n - 2))
break;
else if ((r - l) >= 2){
//goto loop with left side values
push(r);
r = pivot_index + 1;
goto loop;
}
else {
//goto loop with right side values
l = r;
r = pop();
goto loop;
}
}while(1);
}
//cite http://www.sanfoundry.com/c-program-stack-implementation/
void push (int x){
s.top = s.top + 1;
s.stk[s.top] = x;
}
int pop(){
int x = s.stk[s.top];
s.top = s.top - 1;
return x;
}
per request, I've added the function that calls quick sort (Note: quick_count is initialized to zero as a global variable -- used as an extern)
int unsorted_quick[] = {9,8,7,6,5,4,3,2,1,0}; //n = 10
//print unsorted_quick
printf("\nSecond, we sort the following array by using the quick sort algorithm\n");
for (i = 0; i < 10; i++){
printf("[%d]", unsorted_quick[i]);
}
printf("\n");
//fill buf with the unsorted quick array
for (i = 0; i < 10; i++){
buf[i] = unsorted_quick[i];
}
iterative_quick_sort(buf, 10); //call quick_sort()
//print sorted
for (i = 0; i < 10; i++){
printf("[%d]", buf[i]);
}
printf("\nNumber of comparisons: %d\n", quick_count); //print count
You are calling srand(time(NULL)) inside the loop that choose the random pivot. This function must be called once to initialise the state of the random number generator.
The generator needs a starting seed which is set by calling srand(). Then, given the seed, each subsequent call to rand() will give you a random number in a reproducible sequence.
Starting from the same seed you will get the same random sequence.
The problem is that you set the seed in the loop and the seed is the same number so you will always get the same "random" value. This happens because time(NULL) is taken from current time in seconds which means that the random number it's the same in the same second.
You must put it before the loop: do {
Here there is a nice explanation of what is happening: Problems when calling srand(time(NULL)) inside rollDice function
And also here: srand() — why call it only once?

Swaps and Comparisons in Quicksort

I think I have managed to figure the comparisons but I am trying to figure out how can I count the numbers of swaps. I have a problem with the value of swapcounter and the recursion. Any ideas?
int quicksort (int nums[],int n,int left,int right){//quicksort takes an array, the leftmost index and the rightmost index
int swapCounter=0;
int i=left,j=right,temp;
int comparisonCounter = 0;
int pivot = nums[(left + right) / 2];
/* partition */
while(i<=j){
comparisonCounter++;
while(nums[i]<=pivot)
i++;
while(nums[j]>pivot)
j--;
if(i<=j){
temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
i++;
j--;
swapCounter++;
}
}
/* recursion */
if (left < j)
comparisonCounter+=quicksort(nums,n, left, j);
if (i < right)
comparisonCounter+=quicksort(nums,n, i, right);
printf("\nSwaps=%d\n",swapCounter);
return comparisonCounter;
}
You can:
Make swapcounter global.
Make the function take a pointer to the variable.
Make the function call another function to do the counting, thus making maintaining the counter state Someone Else's problem.

C - merge part of merge sort

I am new to merge sorts and am trying to create one. My merge sort is not sorting the array I am sending it and I can't figure out why. here is a link to all of the code http://pastebin.com/M4RUzhUa
Here is my mergesort function
void merge_sort(int array[], int low, int high) {
int middle = (low + high) / 2;
if(low < high) {
merge_sort(array, low, middle);
merge_sort(array, middle+1, high);
merge(array, low, middle, high);
}
}
Here is my (updated) merge function
void merge(int array[], int low, int middle, int high) {
int size,left,right,i, j;
size = high - low + 1;
int array1[high];
left = low;
right = middle + 1;
i = low;
while ((left<=middle) && (right<=high)) {
if(array[left] < array[right]) {
array1[i] = array[left];
left++;
i++;
}
else {
array1[i] = array[right];
right++;
i++;
}
}
while (left <= middle) {
array1[i] = array[left];
left++;
i++;
}
while (right <= high) {
array1[i] = array[right];
right++;
i++;
}
for (j = low; j < i; j++) {
array[j] = array1[j];
}
}
In my program the input array is
9
3
2
1
5
and the output is
0
1
2
3
5
something is happening with the first element that i can't figure out
New comments for updated code:
It looks like you are waltzing past the end of your array. A way to test that would be to add some guard variables around your array, like this:
#define NUM_OF_INTS 5
#define DEBUG 1
int main()
{
int frontguard=-500;
int numbers[NUM_OF_INTS];
int backguard=-600;
int i;
srand(0);
//Fill the array
for( i = 0; i < NUM_OF_INTS; i++ )
{
//Use random numbers
//numbers[i] = rand()%10000;
//Use reverse sorted list
numbers[i] = NUM_OF_INTS-i;
//Use sorted list
//numbers[i] = i;
}
if (DEBUG == 1) printf( "Unsorted list\n" );
if (DEBUG == 1) printarray( numbers, 0, NUM_OF_INTS/2, NUM_OF_INTS );
if (DEBUG == 1) printf( "frontguard=%04d, backguard=%04d\n", frontguard, backguard);
merge_sort( numbers, 0, NUM_OF_INTS );
if (DEBUG == 1 ) printf( "\nSorted list\n");
if (DEBUG == 1) printarray( numbers, 0, NUM_OF_INTS/2, NUM_OF_INTS );
if (DEBUG == 1) printf( "frontguard=%04d, backguard=%04d\n", frontguard, backguard);
return 0;
}
printarray is a helper function I wrote to prettyprint what is happening in an array
void printarray( const int arr[], const int low, const int middle, const int high )
{
int i;
for (i = low; i < high; i++ )
{
if( i == low )
printf( " L%04d", i );
else if( i == middle )
printf( " M%04d", i );
else if( i == (high-1) )
printf( " H%04d", i );
else
printf( " *%04d", i );
}
printf( "\n" );
for( i = low; i < high; i++ )
printf( " %04d", arr[i] );
printf( "\n" );
}
It is common to have to create some helper debug functions such as this to get your code working if you do not have/want a debugger. Do not be afraid to write some throw-away code to understand what your code is doing! In this case, I didn't need the line of L/M/H, but it is still worthwhile to spend the time. I recommend leaving these types of functions in your code, commented out (using a #define such as DEBUG), in case a future maintainer needs them.
Here is the output of your function as-is:
Unsorted list
L0000 *0001 M0002 *0003 H0004
0005 0004 0003 0002 0001
frontguard=-500, backguard=-600
Sorted list
L0000 *0001 M0002 *0003 H0004
-600 0001 0002 0003 0004
frontguard=-500, backguard=0005
You can see that the backguard got overwritten and "stolen" into your output. (This behavior can differ on different CPU architectures, C implementations, and run specifics, btw.) The problem is that you call merge_sort from main() with high as the size of the array (5 in this case), however merge_sort expects high to be the last valid index in the array (numbers[4] is the last array item). Modify main() to
merge_sort( numbers, 0, NUM_OF_INTS-1 );
and test it against a sorted, reverse sorted, and random array of numbers.
Original comments:
Well, first off, you should be receiving a segementation fault, not just incorrectly sorted data.
size = high - low + 1;
//create a helper array and set it equal to the input array
int array1[size];
for (i = low; i <= high; i++) {
array1[i] = array[i];
}
Think about what happens here when low is not zero. Let's say l=6, m=6, h=7. You are setting the size of your helper array to 2, but you are accessing it with i=6, so you are trashing the stack.
The easiest fix for this is to declare int array1[high];. It's memory inefficient but it keeps the rest of the code simple, which is really more valuable.
Second, your for loop is indexing past the end of array, you need to use i < high. In C, arrays start at 0, so an array of size 5 has valid locations at 0,1,2,3,4. Your code as-is would try to read from array[5] (probably not fatal), and write to array1[5] (very possibly fatal). I'll bet this why you have a +1 in the size statement, since you were advancing past the end of array1 otherwise.
for (i = low; i < high; i++) {
These will fix your segmentation fault. With that fixed, you are still getting garbage data in your output.
Your middle else-if statement is never going to be executed - any equivalent data is going to be covered by the first if statement.
Your while loop does not properly handle the degenerate cases. It needs to detect if one of the two lists has been completely consumed, and if so, just copy the rest of the other list.
Also, the while loop needs separate tracker variables for low, mid, and the output array. You cannot use currentLow for both low and the output array.
Finally, when testing sorting, random data is not sufficient (esp. with a size of 5), you should always test the totally degenerate cases of a sorted and reverse-sorted lists.

Resources