Is there a way to optimize the first defined function in attached code?
I wonder if the exercise I've done can be optimized for readability and performance. The exercise was about determining if the array, which stores the integer values is incrementally well sorted (every digit is greater than the previous [i.e. 1,2,3,4,5]), just incrementally sorted (the numbers are generally incrementally sorted, but there can be few with the same values in a row [i.e. 1,3,3,5]), or not sorted at all incrementally [i.e. 4,2,1].
The exercise has to be done by using recursive approach in the most optimized way. Below is my solution proposition:
// find if the array is well sorted incrementally, sorted incrementally or not sorted at all
// the function should return 1 if array is well sorted or just sorted and return 0 otherwise
// the function should pass by refference 1 if the array is well sorted or 0 otherwise
// the result will be thus determined based on those two parameters in separate function
// recursive approach
#include <stdio.h>
#define SIZE1 5 // constants for ready arrays tests
#define SIZE2 4 // ...
#define SIZE3 3 // ...
int findIfArrayIsSorted(int array[], int size, int *precision);
void printResult(int result, int precision);
void specifyInputArraySize(int *size);
void inputArrayElements(int array[], int size);
void printArrayElements(int array[], int size);
int findIfArrayIsSorted(int array[], int size, int *precision)
{
if (size > 1)
{
if (array[size-1] < array[size-2])
{
*precision = 0;
return 0;
}
else if (array[size-1] == array[size-2])
{
*precision = 0;
return findIfArrayIsSorted(array, size - 1, precision);
}
else if (array[size-1] > array[size-2])
return findIfArrayIsSorted(array, size - 1, precision);
}
return 1;
}
void printResult(int result, int precision)
{
if (result == 1 && precision == 1)
printf("This array is well sorted\n");
else if (result == 1 && precision == 0)
printf("This array is sorted\n");
else
printf("This array isn't sorted\n");
}
void specifyInputArraySize(int *size)
{
printf("Please enter the size: ");
scanf("%d", size);
}
void inputArrayElements(int array[], int size)
{
int i;
printf("Please input array elements (one by one):\n");
for (i = 0; i < size; i++)
scanf("%d", &array[i]);
}
void printArrayElements(int array[], int size)
{
int i;
printf("The elements stored in an array are:\n");
for (i = 0; i < size; i++)
printf("Element[%d] is %d\n", i, array[i]);
}
int main(void)
{
int result;
int precision;
// tests for ready arrays
int numArrayW[SIZE1] = {1, 2, 3, 4, 5};
int numArrayS[SIZE2] = {1, 3, 3, 5};
int numArrayU[SIZE3] = {4, 2, 1};
precision = 1; // default assumption
printArrayElements(numArrayW, SIZE1);
result = findIfArrayIsSorted(numArrayW, SIZE1, &precision);
printResult(result, precision);
precision = 1; // default assumption
printArrayElements(numArrayS, SIZE2);
result = findIfArrayIsSorted(numArrayS, SIZE2, &precision);
printResult(result, precision);
precision = 1; // default assumption
printArrayElements(numArrayU, SIZE3);
result = findIfArrayIsSorted(numArrayU, SIZE3, &precision);
printResult(result, precision);
// test for inputted array
int size;
precision = 1; // default assumption
specifyInputArraySize(&size);
int numInputtedArray[size];
inputArrayElements(numInputtedArray, size);
printArrayElements(numInputtedArray, size);
result = findIfArrayIsSorted(numInputtedArray, size, &precision);
printResult(result, precision);
return 0;
}
I would really appreciate if someone will find more optimized solution, thanks.
This variant optimizes for neither readability nor performance, but rather for usability and conformance, because it doesn't require the caller to preset the reference argument with the default assumption 1.
int findIfArrayIsSorted(int array[], int size, int *precision)
{
if (size <= 1) return *precision = 1;
if (array[size-1] < array[size-2]) return *precision = 0;
int sorted = findIfArrayIsSorted(array, size-1, precision);
*precision &= array[size-1] > array[size-2];
return sorted;
}
Related
CSS student here. I was given an exercise by my prof but I don't know how to solve this problem. A specific n is wanting to be accessed in printf but the given elements in the array are below the n that is asked.
This is the code I wrote but in this paticular test it's not giving me the right solution. Any tips?
#include <stdio.h>
int max(int arr[], int n) {
int numMax = 0, indexMax = 0;
for (int i = 0; i <= n; i++) {
if (arr[i] >= numMax) {
numMax = arr[i];
indexMax = i;
}
}
return indexMax;
}
int main () {
int arr[5]={-88, -91, -45, -90, -13};
printf("The index of the highest number is: %d\n", max(feld, 5));
// solution: 5
return 1;
}
Your array is called arr and not feld.
In your function you can initialize numMax with the first value of the array and then loop through it to test the following ones.
#include <stdio.h>
int max(int arr[], int n)
{
int numMax = arr[0], indexMax = 0;
for (int i = 1; i < n; i++)
{
if (arr[i] >= numMax)
{
numMax = arr[i];
indexMax = i;
}
}
return indexMax;
}
int main(void)
{
int arr[5] = {-88, -91, -45, -90, -13};
printf("The index of the highest number is: %d\n", max(arr, 5));
return 0;
}
With: for (int i = 0; i <= n; i++), the OP program is stepping out of the boundaries of the array. (zero based indexing is tricky for beginners.)
The array elements aren't going anywhere.
Simply pick the last element, and update that pick if a higher value is found during a scan toward the 0th element.
int maxVal( int arr[], int n ) {
int maxInd = --n;
while( --n >= 0 )
if( arr[n] > arr[MaxInd] ) maxInd = n;
return maxInd;
}
Fewer variables to keep track of is always an advantage.
The function returns the index, not the value.
printf("The index of the highest number is: %d\n", max(arr, 5) );
EDIT:
Let's visit main() to improve it a bit.
int main( void ) { // more conventional
// the compiler counts more accurately than most people:
int arr[] = { -88, -91, -45, -90, -13 };
size_t nElem = sizeof arr/sizeof arr[0];
// Notice that maxVal() should return a 'size_t', too.
// Use the appropriate format specifier
// The name "maxVal()" is misleading. Fix that...
printf("The index of the highest number is: %sz\n", maxValInd( arr, nElem ) );
return 0; // 0 means all good, non-zero indicates an error occurred.
}
Now, since that uses size_t (better for non-negative values like the number of elements in an array or bytes in a file), we should improve the function, too:
size_t maxValInd( int arr[], size_t n ) {
size_t maxInd = 0; // pick 0th as first pick...
while( --n > 0 ) // test all values down to, but not, arr[0].
if( arr[n] > arr[MaxInd] ) maxInd = n;
return maxInd;
}
NB: size_t is an unsigned datatype that will underflow if decremented below zero. Handle with care to avoid infinite-loops.
int arr[6] and passing 5 as argument to max should do the work.
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
#include<stdio.h>
int* twoSum(int* nums, int numsSize, int target);
int main(){
int*array;
int arraySize;
scanf("%d",&arraySize);
for (int i=0;i<arraySize;i++){
scanf("%d",&array[i]);
}
int target;
scanf("%d",&target);
int* positions=twoSum(array, arraySize, target);
printf("The positions are: %p",positions);
return 0;
}
int* twoSum(int* nums, int numsSize, int target){
int *returnSize = NULL;
for(int i=0,sum=0;i<numsSize;i++){
for(int j=0;j<numsSize;j++){
sum =sum+nums[i]+nums[j];
if(sum==target){
returnSize[0]=nums[i];
returnSize[1]=nums[j];
}
else
returnSize[0]= -1;
returnSize[1]= -1;
}
}
return returnSize;
}
The error I am getting makes reference to a line that is empty in my code. Please help
there are mistakes in this code.First you should allocate memory for int*array; after taking int arraySize; as input , you can do it like this
array = malloc(sizeof(int) * arraySize);
then here %p is not appropriate , instead use %d. Take look here for more information about %p %p format specifier and also since you want to print 2 positions you need to call two arguments in printf like this printf("The positions are: %d %d", positions[0], positions[1]);
In your twoSum function , you need to allocate memory for int* returnSize ; like this returnSize = malloc(sizeof(int) * 2);
and here you are not returning positions of found elements , you are returning elements themselfs.
if(sum==target){
returnSize[0]=nums[i];
returnSize[1]=nums[j];
}
also you need to add return in this if-statement other wise , you will traverse array completely and returnSize elements will become -1 again(unless answer is too last element of array)
so this if should be like this:
if (sum == target) {
returnSize[0] = i;//num[i] is not position. it is element of array
returnSize[1] = j;//num[j] is not position .it is element of array
return returnSize;//otherwise it will traverse array compeltely and they -1 again
}
also only if you code one line for if,else,while,for,... (conditional statements) ,you can avoid using braces ,otherwise only one line of your code will executed ,if that condition become true ,so you have to add a block for this else:
else
{
returnSize[0] = -1;
returnSize[1] = -1;
}//coding more than one line so your else should be in a block
and also here sum=sum+num[i]+num[j]; is wrong you should change this to sum=num[i]+num[j]; because you only want to check sum of two current number ,or better way don't use sum at all only check equality of target with num[i]+num[j]
here is complete code:
int* twoSum(int* nums, int numsSize, int target);
int main() {
int* array;
int arraySize;
scanf("%d", &arraySize);
array = malloc(sizeof(int) * arraySize);//allocate memory for array
for (int i = 0; i < arraySize; i++) {
scanf("%d", &array[i]);
}
int target;
scanf("%d", &target);
int* positions = twoSum(array, arraySize, target);
printf("The positions are: %d %d", positions[0], positions[1]);//%p is for not for content of array
return 0;
}
int* twoSum(int* nums, int numsSize, int target) {
int* returnSize ;
returnSize = malloc(sizeof(int) * 2);
for (int i = 0; i < numsSize; i++) {
for (int j = 0; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
returnSize[0] = i;//num[i] is not position. it is element of array
returnSize[1] = j;//num[j] is not position .it is element of array
return returnSize;//otherwise it will traverse array compeltely and they -1 again
}
else
{
returnSize[0] = -1;
returnSize[1] = -1;
}//coding more than one line so your else should be in a block
}
}
return returnSize;
}
There is some mistakes in your code:
memory allocation
You declare pointers on int to store data to process and result, but you do not allocate memory: malloc is for Memory ALLOCation:
array = malloc(sizeof *array * arraySize);
and
int *returnSize = malloc(sizeof *returnSize * 2);
Sum calculation logic
sum value
In twoSum function, the sum variable is getting bigger and bigger: sum =sum+nums[i]+nums[j];
Instead, a simple if (target == nums[i] + nums[j]) will perform the test you wanted.
sum test
In your code, each time sum is not equal to target, you reset returnSize[0] to -1
You do not have to have an else clause: you can initialize the returnSize before the for loop.
missing {...}
Look at your first code: for any value of sum and target, returnSize[1] is set to -1 because you've forgotten to put accolades after the else (but, as written before, you do not even need an else)
gcc can warn you about such issue (-Wmisleading-indentation, or better -Wall)
for(int j=0;j<numsSize;j++){
sum =sum+nums[i]+nums[j];
if(sum==target){
returnSize[0]=nums[i];
returnSize[1]=nums[j];
}
else
returnSize[0]= -1;
returnSize[1]= -1;
}
Considering this, you can write a code that do what you wanted.
Be careful, you should test the scanf and malloc return values too...
#include <stdio.h>
#include <stdlib.h>
int *twoSum(int *nums, int numsSize, int target);
int main()
{
int *array;
int arraySize;
// TODO: test that scanf returned 1
scanf("%d", &arraySize);
// TODO: test that arraysize is at least 2
/* allocate array to store the numbers*/
array = malloc(sizeof *array * arraySize);
for (int i = 0; i < arraySize; i++) {
// TODO: test that scanf returned 1
scanf("%d", &array[i]);
}
int target;
// TODO: test that scanf returned 1
scanf("%d", &target);
int *positions = twoSum(array, arraySize, target);
printf("The positions are: %d(%d) %d(%d)\n", positions[0], array[positions[0]], positions[1], array[positions[1]]);
/* memory has been allocated? free it */
free(positions)
free(array)
return 0;
}
int *twoSum(int *nums, int numsSize, int target)
{
int *returnSize = malloc(sizeof *returnSize * 2);
returnSize[0] = returnSize[1] = -1;
for (int i = 0; i < numsSize; i++) {
for (int j = 0; j < numsSize; j++) {
if (target ==nums[i] + nums[j] ) {
returnSize[0] = i;
returnSize[1] = j;
return returnSize;
}
}
}
return returnSize;
}
Here your code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int* twoSum(int* nums, int numsSize, int target);
void print_pos(int * arr, int i) {
printf("test %d\n", i);
if (arr != NULL) {
printf("position 1 = %d, position 2 = %d\n", arr[0], arr[1]);
} else
printf("Not found\n");
}
int main(){
int array[5] = {5, 6, 2 ,1 ,3} ;
int target1 = 11, target2 = 9, target3 = 15;
int * positions1=twoSum(array, 5, target1);
int * positions2=twoSum(array, 5, target2);
int * positions3=twoSum(array, 5, target3);
print_pos(positions1, 1);
print_pos(positions2, 2);
print_pos(positions3, 3);
return 0;
}
int* twoSum(int* nums, int numsSize, int target){
int *return_arr = malloc(sizeof(int) * 2);
bool found = false;
for(int i=0;i<numsSize;i++){
for(int j=0;j<numsSize;j++){
if((nums[i]+nums[j])==target){
return_arr[0]= i;
return_arr[1]= j;
found = true;
}
}
}
if (found)
return return_arr;
else {
free(return_arr);
return NULL;
}
}
I try to split an int array. This array contains positive and negative numbers and I want the function to return 2 arrays one with the positive numbers and one with the negative numbers.
I already tried the following code but it doesn't work as expected.
int main(void)
{
int array[] = {1, -1, 2, 3, 4, -5, 6};
int cnt = sizeof(array)/sizeof(array[0]);
int *neg, *pos;
int **low = &neg;
int **high = &pos;
neg = (int*) malloc(sizeof(int) * 2);
pos = (int*) malloc(sizeof(int) * 5);
sort(array, cnt, low, high);
for(int i = 0; i < 5; i++)
{
printf("%3d\n", pos[i]);
}
//same for negative array
return 0;
}
int sort(int *arr, int cnt, int **low, int **high)
{
for(int i = 0; i < cnt; i++)
{
if(arr[i] > 0)
{
*high[0] = arr[i];
**high++;
}
else
{
*low[0] = arr[i];
**low++;
}
}
}
If someone could show me what I am doing wrong would help a lot.
As mentioned in the comments, the double indirection with int** is unnecessary. A more suitable interface to the function is shown below.
It takes as input the array and count, and pointers to large enough output arrays. As output, the arrays are filled with the positive (negative) values, and the count for each is written to *npos (*nneg).
Treatment of zeroes is left to you. Just edit the if conditions.
Also note how I use *npos += 1 instead of (*npos)++ to avoid mistakes with operator precedence.
void separate(int *arr, int cnt, int *neg, int *pos, int *nneg, int *npos)
{
*nneg = 0;
*npos = 0;
for(int i = 0; i < cnt; i++)
{
if (arr[i] > 0)
{
pos[*npos] = arr[i];
*npos += 1;
}
else if (arr[i] < 0)
{
neg[*nneg] = arr[i];
*nneg += 1;
}
}
}
While in your example you know how many positive and negative values there are, in general you should allocate arrays that are definitely large enough, i.e. cnt elements.
I wish to sort a second array as per the first array. e.g.
first = {1,8,7,2,4}
second = {9,7,2,10,3}
I want first to be unchanged and second to be sorted in the same relative order as the first. i.e. the lowest value is at index 0, the second lowest value is at index 3, third lowest value is at index 4 etc etc
second = {2,10,9,3,7}
I have already tried some code for the following
#include <stdio.h>
typedef struct
{
int num;
int pos;
}ArrType;
ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
ArrType arrB[5] = {{9,0},{7,1},{2,2},{10,3},{3,4}};;
int cmparr(const void *a, const void *b)
{
ArrType *tmpa, *tmpb;
tmpa = (ArrType*) a;
tmpb = (ArrType*) b;
return(arrA[tmpa->pos].num - arrA[tmpb->pos].num);
}
int main(void)
{
int i;
qsort(arrB,5, sizeof(ArrType), cmparr);
for (i=0; i<5; i++)
{
printf ("%d ",arrB[i].num);
}
return (0);
}
The actual output is
9 10 3 2 7
I am open to a different data structure, but arrB should only be sorted one time.
I have seen some solutions for this in C++, Javascipt and other languages. But there is not a solution in C.
Edit - These arrays would be quite large in the final program. I am looking for a single sorting operation. i.e. single call to qsort
You need to create the meta-data that matches the desired ordering (i.e an array of indexes). Then apply that meta-data to the second array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int first[] = {1,8,7,2,4};
int second[] = {9,7,2,10,3};
int compare(const void * a, const void * b);
int binary_search(int array[], int min, int max, int target);
void print_array(int * array, int c);
int main()
{
int idx;
int c = sizeof(first)/sizeof(int);
int * sorted = NULL;
int * indexes = NULL;
int * result = NULL;
if (NULL == (sorted = malloc(sizeof(first)))) {
return -1;
}
memcpy(sorted, first, sizeof(first));
if (NULL == (indexes = malloc(sizeof(first)))) {
free(sorted);
return -1;
}
memset(indexes, -1, sizeof(first));
if (NULL == (result = malloc(sizeof(second)))) {
free(sorted);
free(indexes);
return -1;
}
memset(result, -1, sizeof(second));
// 1st: Sort the reference array
qsort (sorted, c, sizeof(int), compare);
// 2nd: Record the position of each sorted element in the original array (this is your meta-data)
for (idx=0; idx<c; idx++) {
indexes[idx] = binary_search(sorted, 0, c, first[idx]);
}
// 3rd sort the target array
memcpy(sorted, second, sizeof(second));
qsort (sorted, c, sizeof(int), compare);
// 4th apply the stored positions to the sorted target array
for (idx = 0; idx < c; idx++) {
result[idx] = sorted[indexes[idx]];
}
print_array(result, c);
free(result);
free(indexes);
free(sorted);
return 0;
}
int compare(const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int binary_search(int array[], int min, int max, int target)
{
int mid;
while (min <= max)
{
mid = min + (max - min)/2;
if (target > array[mid])
min = mid + 1;
else if (target < array[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
void print_array(int * array, int c)
{
for(int i = 0; i < c; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
Demo
Here is my approach, it uses qsort twice and arrC contains the result.
#include <stdio.h>
typedef struct
{
int num;
int pos;
}ArrType;
ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
int arrB[5] = {9,7,2,10,3};;
int arrC[5];
int cmpInt(const void *a, const void *b)
{
return(*a - *b);
}
int cmp(const void *a, const void *b)
{
ArrType *tmpa, *tmpb;
tmpa = (ArrType*) a;
tmpb = (ArrType*) b;
return(tmpa->num - tmpb->num);
}
int main(void)
{
int i;
qsort(arrA,5, sizeof(ArrType), cmp);
qsort(arrB,5, sizeof(ArrType), cmpInt);
for (i=0; i<5; i++)
{
arrC[arrA[i].pos] = arrB[i];
}
return (0);
}
Since C doesn't have a lambda compare (which could be used to sort an array of indexes according to first[]), the code below sorts an array of pointers ap[] to the elements of first[] using qsort(). Using pointers eliminates the need to pass an array name as a parameter for the compare function, which in turn allows the compare function to work with qsort(). The expression (ap[i]-first) converts a pointer into an index. Next second[] is sorted, also using qsort(). Then ap[] is used as a set of ranks to reorder second[] in place and in O(n) time.
To explain reorder by rank versus reorder by index:
dst[rank[i]] = src[i]; /* reorder by rank */
dst[i] = src[index[i]]; /* reorder by index */
Example code:
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
/* compare for ptr to integer */
int cmppi(const void *p0, const void *p1){
return (*(int *)p0 - *(int *)p1);
}
/* compare for ptr to ptr to integer */
int cmpppi(const void *p0, const void *p1){
return (**(int **)p0 - **(int **)p1);
}
int main()
{
int first[] = {1, 8, 7, 2, 4};
int second[] = {9, 7, 2,10, 3};
int **ap; /* array of pointers */
int *tmpp;
int tmpi;
size_t i, j;
/* allocate and generate array of pointers to first[] */
ap = (int **)malloc(sizeof(first)/sizeof(first[0])*sizeof(int *));
for(i = 0; i < sizeof(first)/sizeof(first[0]); i++)
ap[i] = &first[i];
/* sort ap */
qsort(ap, sizeof(first)/sizeof(first[0]), sizeof(int *), cmpppi);
/* sort second */
qsort(second, sizeof(second)/sizeof(second[0]), sizeof(int), cmppi);
/* reorder ap and second in place using ap as rank (O(n) time) */
for (i = 0; i < sizeof(second) / sizeof(second[0]); i++){
while(i != (j = ap[i] - first)){
tmpp = ap[i]; /* swap(ap[i], ap[j]) */
ap[i] = ap[j];
ap[j] = tmpp;
tmpi = second[i]; /* swap(second[i], second[j] */
second[i] = second[j];
second[j] = tmpi;
}
}
/* display second[] */
for (i = 0; i < sizeof(second) / sizeof(second[0]); i++)
printf("%3d", second[i]);
printf("\n");
free(ap);
return 0;
}
I am trying to count the number of swaps that occur in my quicksort in C. However, I am getting values that are incorrect and not sure where I went wrong. I am using a structures as my arrays to be sorted.
struct anArray{
int numbers[maxSize];
int swaps;
};
/* Partition function */
int partition(struct anArray *array, int start, int end){
if(start == end){
return start;
}
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for(;;){
do{
low++;
} while(array->numbers[low] < pivot);
do{
high--;
} while(array->numbers[high] > pivot);
/* Detector for when the cells meet */
if(low >= high){
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
This is my partition function used to "separate" the arrays.
void quickSort(struct anArray *array, int start, int end){
if(end - start <= 0){ return; }
else{
int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
}
This is my quicksorting function. It's a recursive function.
My swap function increments counter by 1 every time it's called.
In my main, I set
myArray->swaps = counter;
But the number of times the swaps occurs isn't right. For example, if I sort an array that goes from 1 to 9, the number of swaps should be 0 but I get 9. I've tried incrementing counter when it's in the partition function only but it gives me the same result.
Is there something wrong with my partition function?
Thank you very much
Edit 1:
Here's my swap function.
void swap(struct anArray *array, int first, int second){
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
counter++;
}
I've tried using
void swap(struct anArray *array, int first, int second, int swapCount)
and then have swapCount be array->swaps when calling the swap function, and incrementing it by 1 but it gives me the same answer.
Here's a part of my main.
int main(){
struct anArray *ascending = (struct anArray*)malloc(10 * sizeof(struct anArray));
int ascend[maxSize] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
initArray(ascending, ascend);
quickSort(ascending, 0, maxSize - 1);
ascending->swaps = counter;
printf("Test: Unique random values\nSorted: [ ");
for(int i = 0; i < maxSize; i++){
printf("%i ", ascending->numbers[i]);
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);
The other parts of my main are just other arrays to be sorted. The initArray is used to set the values of array->numbers and also reset array->swaps to 0.
Your quicksort code seems pretty good. I didn't examine it rigorously, but it passed a simple test, so I didn't investigate further. (Edit: Based on your feedback, I created a third version in my second update that shows that the sort has an issue for larger data inputs).
The main bug was the malloc at the top of main. We do not want an array of the struct anArray:
struct anArray *ascending = malloc(10 * sizeof(struct anArray));
That is, we do not want (e.g.) 10 structs, we want a single struct and to fill in 10 ints that go into the numbers field that is in that single struct.
The initArray function was not posted, so I had to guess/deduce what it might be. Based on the above bug, I'm not sure that numbers would have been initialized correctly.
From the code fragments posted, I was able to piece together a whole program. I've created two versions:
One with the bugs annotated [but not fixed] that compiles cleanly.
And, a second that is fully cleaned up, working, and generalized for arbitrary array sizes [please pardon the gratuitous style cleanup]
Here is [something close to] your original code with the bugs annotated:
#include <stdio.h>
#include <stdlib.h>
// NOTE/BUG: this was not defined and _fixed_ defines should be all caps
#define maxSize 10
struct anArray {
int numbers[maxSize];
int swaps;
};
int counter;
void
initArray(struct anArray *array,const int *src)
{
for (int idx = 0; idx < maxSize; ++idx)
array->numbers[idx] = src[idx];
array->swaps = 0;
}
void
swap(struct anArray *array, int first, int second)
{
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
counter++;
}
/* Partition function */
int
partition(struct anArray *array, int start, int end)
{
if (start == end) {
return start;
}
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for (;;) {
do {
low++;
} while (array->numbers[low] < pivot);
do {
high--;
} while (array->numbers[high] > pivot);
/* Detector for when the cells meet */
if (low >= high) {
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
void
quickSort(struct anArray *array, int start, int end)
{
if (end - start <= 0) {
return;
}
else {
// NOTE/BUG: pivot is _not_ used
int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
}
int
main(void)
{
// NOTE/BUG: we do _not_ want an array of the struct, but an array of int
// that is allocated for "number" _inside_ the struct
struct anArray *ascending = malloc(10 * sizeof(struct anArray));
int ascend[maxSize] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// NOTE/BUG: this was not defined
initArray(ascending, ascend);
quickSort(ascending, 0, maxSize - 1);
ascending->swaps = counter;
printf("Test: Unique random values\nSorted: [ ");
for (int i = 0; i < maxSize; i++) {
printf("%i ", ascending->numbers[i]);
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);
return 0;
}
Here is a cleaned up and working version. I've generalized it so it can take an arbitrarily long array. I've also done a bit of style and code cleanup:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *numbers;
int size;
int swaps;
} Array;
Array *
initArray(const int *src,int size)
{
Array *array = malloc(sizeof(Array));
array->numbers = malloc(size * sizeof(int));
array->size = size;
// store in reverse order so the sort will actually do something
for (int idx = 0; idx < size; ++idx)
array->numbers[size - 1 - idx] = src[idx];
array->swaps = 0;
return array;
}
void
freeArray(Array *array)
{
free(array->numbers);
free(array);
}
void
swap(Array *array, int first, int second)
{
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
array->swaps += 1;
}
/* Partition function */
int
partition(Array *array, int start, int end)
{
if (start == end)
return start;
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for (;;) {
do {
low++;
} while (array->numbers[low] < pivot);
do {
high--;
} while (array->numbers[high] > pivot);
/* Detector for when the cells meet */
if (low >= high) {
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
void
quickSort(Array *array, int start, int end)
{
if (end - start <= 0)
return;
//int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
int
main(void)
{
// NOTE/BUG: we do _not_ want an array of the struct, but an array of int
// that is allocated for "number" _inside_ the struct
int original[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int size = sizeof(original) / sizeof(original[0]);
Array *ascending = initArray(original, size);
quickSort(ascending, 0, ascending->size - 1);
printf("Test: Unique random values\nSorted: [ ");
for (int i = 0; i < ascending->size; i++) {
int expected = original[i];
int actual = ascending->numbers[i];
printf("%d%s ", actual, (actual == expected) ? "" : "???");
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);
freeArray(ascending);
return 0;
}
UPDATE:
What does the line int size = sizeof(original) / sizeof(original[0]); do exactly?
Does it give me an integer for size which I set to be the size of how many numbers I can hold in an array?
Yes, that is common/idiomatic trick to get the count of the number of elements of a fixed size array:
int array[] = { 1, 2, 3 };
size_t count = sizeof(array) / sizeof(array[0]);
Here, sizeof(array) is 3 times the size [in bytes] of the individual elements [which are int, which is 4 bytes], so we have 3 * 4 or 12.
sizeof(array[0]) is the size of the single, first element of the array, which is [again] an int, so this is 4.
So, when we divide the two, we have 12 / 4 or 3, which is the number of elements.
If so, wouldn't the amount of numbers I can hold be really small if sizeof(original[0]) happens to be very large?
No, because of the division. It doesn't care how large the element size [in bytes] is, because the ratio always produces the number of elements.
The sizeof(arr) / sizeof(arr[0]) trick is useful to get the count when we do: int arr[] = { ... };
If we do:
#define ARRCOUNT 3
int arr[ARRCOUNT] = { 1, 2, 3 };
We already know the count (i.e. it is ARRCOUNT).
The [slight] advantage to the sizeof/sizeof trick is that if we had incorrectly defined ARRCOUNT as 4 by mistake, it would still compile, link, and run, but would produce incorrect results [because there were only 3 elements].
This is a common enough trick that we can define a generic macro [that we can reuse by putting it a .h file]:
#define ARRAY_COUNT(arr_) (sizeof(arr_) / sizeof(arr_))
UPDATE #2:
I've tried your code (even tried copying and pasting it) but my swaps is still showing 9 despite my array to be sorted is just going from { 1 to 10}. Not sure why this keeps occurring.
I believe [now] you have a bug in the sort itself.
I've produced another version that has much more extensive test data generation and comparison.
At a minimum, because of the way the tests are structured, the first element of the sorted array should always have a value of 1.
The test that fails is the one that does a random shuffle of the original array before sending it in to be sorted.
You can add other tests as needed. The array needn't be so large to show the problem. For example, the following single test is enough to produce the error:
bigtest(100,237,1);
Anyway, here is the enhanced diagnostic code:
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 60
typedef struct {
int *numbers;
int size;
int swaps;
} Array;
Array *
initArray(const int *src,int size,int randshuf)
{
int idx;
Array *array = malloc(sizeof(Array));
array->numbers = malloc(size * sizeof(int));
array->size = size;
array->swaps = 0;
// store in reverse order so the sort will actually do something
switch (randshuf) {
case 0: // reverse the numbers
for (idx = 0; idx < size; ++idx)
array->numbers[size - 1 - idx] = src[idx];
break;
default: // do _crude_ random shuffle
for (idx = 0; idx < size; ++idx)
array->numbers[idx] = 0;
for (idx = 0; idx < size; ++idx) {
while (1) {
int ridx = rand() % size;
if (array->numbers[ridx] == 0) {
array->numbers[ridx] = src[idx];
break;
}
}
}
break;
}
return array;
}
void
freeArray(Array *array)
{
free(array->numbers);
free(array);
}
void
swap(Array *array, int first, int second)
{
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
array->swaps += 1;
}
/* Partition function */
int
partition(Array *array, int start, int end)
{
if (start == end)
return start;
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for (;;) {
do {
low++;
} while (array->numbers[low] < pivot);
do {
high--;
} while (array->numbers[high] > pivot);
/* Detector for when the cells meet */
if (low >= high) {
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
void
quickSort(Array *array, int start, int end)
{
if (end - start <= 0)
return;
//int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
void
print_orig(const int *orig,int count)
{
int len = 0;
printf("Test: Original numbers (%d):\n",count);
for (int idx = 0; idx < count; ++idx) {
len += printf(" %10d ", orig[idx]);
if (len >= MAXLEN) {
printf("\n");
len = 0;
}
}
if (len > 0)
printf("\n");
}
int
print_array(Array *array,const int *orig,const char *reason)
{
int len = 0;
int cmp;
int err = -1;
printf("Test: Array Values (%s):\n",reason);
for (int idx = 0; idx < array->size; ++idx) {
int actual = array->numbers[idx];
if (orig != NULL) {
int expected = orig[idx];
cmp = (actual == expected);
}
else
cmp = 1;
len += printf(" %10d%c", actual, cmp ? ' ' : '?');
if (len >= MAXLEN) {
printf("\n");
len = 0;
}
if (cmp)
continue;
if (err < 0)
err = idx;
}
if (orig != NULL)
printf("\nSwaps: %i\nComps: \n\n", array->swaps);
else {
if (len > 0)
printf("\n");
}
return err;
}
void
bigtest(int count,int randgap,int randshuf)
// count -- number of elements (negative means random)
// randgap -- gap between element values (negative means random)
// randshuf -- 0=simple reverse, 1=random shuffle
{
int *orig;
Array *array;
printf("\n");
for (int idx = 1; idx <= 80; ++idx)
printf("-");
printf("\n");
printf("COUNT: %d, RANDGAP: %d, RANDSHUF: %d\n",count,randgap,randshuf);
// get number of elements
if (count < 0)
count = (rand() % count) + 1;
// get element gap (e.g. 1 --> {1, 2, 3}, 2 --> { 1, 3, 5 }
if (randgap < 0)
randgap = (rand() % randgap) + 1;
printf("COUNT: %d, RANDGAP: %d, RANDSHUF: %d\n",count,randgap,randshuf);
// get original array
orig = malloc(sizeof(int) * count);
// fill in original array
do {
int val = 1;
// simple gap
if (randgap >= 0) {
if (randgap == 0)
randgap = 1;
for (int idx = 0; idx < count; ++idx, val += randgap)
orig[idx] = val;
break;
}
// random gap
int gap;
for (int idx = 0; idx < count; ++idx, val += gap) {
orig[idx] = val;
gap = (rand() % randgap) + 1;
}
} while (0);
print_orig(orig,count);
array = initArray(orig,count,randshuf);
print_array(array,NULL,"Shuffled");
quickSort(array, 0, array->size - 1);
print_array(array,orig,"Sorted");
freeArray(array);
free(orig);
}
int
main(void)
{
bigtest(10,0,0);
bigtest(-100,23,0);
bigtest(-1000,-2337,0);
bigtest(-1000,-2337,1);
return 0;
}