I'm trying to write a program that sorts an array of size N via a selections sort and then conducts a binary search for a random number in that array and displays the index in which that number is present. I noticed that without my binary search function I begin to get a stack overflow when N is greater than 1e5 and when I try to run the binary search I run into the error "read access violation". I would greatly appreciate any help on this especially considering my N is supposed to be 1e6.
#define N 10
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//function prototypes
void selectionSort(int array[], size_t length);
void swap(int* elementPtr, int* element2Ptr);
void printPass(int array[], size_t length, unsigned int pass, size_t index);
size_t binarySearch(const int b[], int searchKey, size_t low, size_t high);
unsigned long long int counter = 0;
unsigned long long int counter2 = 0;
long long unsigned int counter3 = 0;
int main(void) {
int array[N];
srand(time(NULL));
for (size_t i = 0; i < N; i++) {
array[i] = rand() % 90 + 10; // give each element a value
}
/*
puts("Unsorted array:");
for (size_t i = 0; i < N; i++) { //print the array
printf("%d ", array[i]);
}
puts("{\n");
*/
selectionSort(array, N);
/*
puts("Sorted array:");
for (size_t i = 0; i < N; i++) { //print the array
printf("%d ", array[i]);
}
*/
printf("\nTotal amount of comparisons: %d\n", counter);
printf("Total amount of swaps: %d", counter2);
int value = rand() % N + 1;
int index = binarySearch(array, value, 0, N);
printf("\nThe amount of times the value was compared was: %d\n", counter3);
if (index != -1) {
printf("%d was first found on index %d\n", value, index);
}
else printf("%d was not found on the array\n", value);
}
void selectionSort(int array[], size_t length) {
//loop over length - 1 elements
for (size_t i = 0; i < length - 1; i++) {
size_t smallest = i; //first index of remaining array
//loop to find index of smallest element
for (size_t j = i + 1; j < length; j++) {
counter++;
if (array[j] < array[smallest]) {
smallest = j;
}
}
swap(array + i, array + smallest); //swap smallest element
//printPass(array, length, i + 1, smallest); //output pass
}
}
//function that swaps two elements in the array
void swap(int* elementPtr,int* element2Ptr)
{
counter2++;
int temp;
temp = *elementPtr;
*elementPtr = *element2Ptr;
*element2Ptr = temp;
}
//function that prints a pass of the algorithm
void printPass(int array[], size_t length, unsigned int pass, size_t index) {
printf("After pass %2d: ", pass);
//output elements till selected item
for (size_t i = 0; i < index; i++) {
printf("%d ", array[i]);
}
printf("%d ", array[index]); //indicate swap
//finish outputting array
for (size_t i = index + 1; i < length; i++) {
printf("%d ", array[i]);
}
printf("%s", "\n "); //for alignment
//indicate amount of array that is sorted
for (unsigned int i = 0; i < pass; i++) {
printf("%s", "-- ");
}
puts(""); //add newline
}
size_t binarySearch(const int b[], int searchKey, size_t low, size_t high) {
counter3++;
if (low > high) {
return -1;
}
size_t middle = (low + high) / 2;
if (searchKey == b[middle]) {
return middle;
}
else if (searchKey < b[middle]) {
return binarySearch(b, searchKey, low, middle - 1);
}
else {
return binarySearch(b, searchKey, middle + 1, high);
}
}
For N as big as 1e5 or 1e6, you can't afford allocating it on stack. The size of an int is 4 bytes and so you'll consume 4e5 bytes from stack just for your array.
You will need to dynamically allocate the array and instead of
int array[N];
you should have
int *array = malloc(sizeof(int) * N);
and after you are done with everything, don't forget to
free(array);
Now you should have enough space on stack for the recursive binary search.
UPDATE:
After I've run the code myself, indeed, the binarySearch function always yields segmentation fault. The problem is the type of the parameters, namely size_t. There are cases where high argument from the binarySearch function becomes -1. But because the size_t is an unsigned type, you have an integer underflow, thus high will become maxint. So your condition if (low > high) would never become true. You'll have to change the types of low and high to a signed integer to have the function working.
Still, I suggest going for the dynamic allocation, even though your stack might cope with that.
Even outside of the great answer that was posted, I am seeing other problems with this code. I have issues running it with N = 2, N =5, and N = 10.
I believe you have some problems with passing the variables into your binary search function. I think that you are passing incorrect values that are overflowing and causing all sorts of memory nightmares. This is causing your read access violations.
Do your small cases function appropriately? Despite the suggestions to minimize your footprint. I would double check simple cases are functioning.
Related
The program should eliminate any repeating digits and sort the remaining ones in ascending order. I know how to print unique digits but I donĀ“t know how to create a new vector from them that i can later sort.
#include <stdio.h>
void unique(double arr[], int n) {
int i, j, k;
int ctr = 0;
for (i = 0; i < n; i++) {
printf("element - %d : ",i);
scanf("%lf", &arr[i]);
}
for (i = 0; i < n; i++) {
ctr = 0;
for (j = 0, k = n; j < k + 1; j++) {
if (i != j) {
if (arr[i] == arr[j]) {
ctr++;
}
}
}
if (ctr == 0) {
printf("%f ",arr[i]);
}
}
}
int main() {
double arr[100];
int n;
printf("Input the number of elements to be stored in the array: ");
scanf("%d", &n);
unique(arr, n);
}
You can always break a larger problem down into smaller parts.
First create a function that checks if a value already exists in an array.
Then create a function that fills your array with values. Check if the value is in the array before adding it. If it is, you skip it.
Then create a function that sorts an array. Alternatively, qsort is a library function commonly used to sort arrays.
This is far from efficient, but should be fairly easy to understand:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUMS 256
int find(double *arr, size_t length, double val)
{
for (size_t i = 0; i < length; i++)
if (val == arr[i])
return 1;
return 0;
}
size_t fill_with_uniques(double *arr, size_t limit)
{
size_t n = 0;
size_t len = 0;
while (n < limit) {
double value;
printf("Enter value #%zu: ", n + 1);
if (1 != scanf("%lf", &value))
exit(EXIT_FAILURE);
/* if value is not already in the array, add it */
if (!find(arr, len, value))
arr[len++] = value;
n++;
}
return len;
}
int compare(const void *va, const void *vb)
{
double a = *(const double *) va;
double b = *(const double *) vb;
return (a > b) - (a < b);
}
int main(void)
{
double array[MAX_NUMS];
size_t count;
printf("Input the number of elements to be stored in the array: ");
if (1 != scanf("%zu", &count))
exit(EXIT_FAILURE);
if (count > MAX_NUMS)
count = MAX_NUMS;
size_t length = fill_with_uniques(array, count);
/* sort the array */
qsort(array, length, sizeof *array, compare);
/* print the array */
printf("[ ");
for (size_t i = 0; i < length; i++)
printf("%.1f ", array[i]);
printf("]\n");
}
Above we read values from stdin. Alternatively, fill_with_uniques could take two arrays, a source and a destination, and copy values from the former into the latter, only when they would be unique.
Remember to never ignore the return value of scanf, which is the number of successful conversions that occurred (in other words, variables assigned values). Otherwise, if the user enters something unexpected, your program may operate on indeterminate values.
So I'm very new to programming and the C language, and I would like to find the simplest, fastest, and most efficient way to count all the distinct elements of a 1D array. This was actually for a school assignment, but I've been stuck on this problem for days, since my program was apparently too slow for the online judge and it got a TLE. I've used regular arrays and dynamically allocated arrays using malloc, but neither worked.
Anyways, here's the latest code of it(using malloc):
#include <stdio.h>
#include <stdlib.h>
int distinct(int *arr, int N){
int j, k, count = 1;
for(j = 1; j < N; j++){
for(k = 0; k < j; k++){
if(arr[j] == arr[k]){
break;
}
}
if(j == k){
count++;
}
}
return count;
}
int main(){
int T, N, i = 0;
scanf("%d", &T);
do{
scanf("%d", &N);
int *arr;
arr = (int*)malloc(N * sizeof(int));
for(int j = 0; j < N; j++){
scanf("%d", &arr[j]);
}
int count = distinct(arr, N);
printf("Case #%d: %d\n", i + 1, count);
i++;
}while(i < T);
return 0;
}
The most efficient way depends on too many unknown factors. One way is to sort the array and then to count distinct elements in there, skipping the duplicates as you go. If you have sorted the array and gotten this:
1 1 1 1 2 2 2 2 3 3
^ ^ ^
+-skip--+-skip--+-- end
... you can easily see that there are 3 distinct values in there.
If you don't have a favourite sorting algorithm handy, you could use the built-in qsort function:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Example:
#include <stdio.h>
#include <stdlib.h>
int compar(const void *l, const void *r) {
const int* lhs = l;
const int* rhs = r;
if(*lhs < *rhs) return -1; // left side is less than right side: -1
if(*lhs > *rhs) return 1; // left side is greater than right side: 1
return 0; // they are equal: 0
}
int distinct(int arr[], int N){
// sort the numbers
qsort(arr, N, sizeof *arr, compar);
int count = 0;
for(int i=0; i < N; ++count) {
int curr = arr[i];
// skip all numbers equal to curr as shown in the graph above:
for(++i; i < N; ++i) {
if(arr[i] != curr) break;
}
}
return count;
}
int main() {
int T, N, i = 0;
if(scanf("%d", &T) != 1) return 1; // check for errors
while(T-- > 0) {
if(scanf("%d", &N) != 1) return 1;
int *arr = malloc(N * sizeof *arr);
if(arr == NULL) return 1; // check for errors
for(int j = 0; j < N; j++){
if(scanf("%d", &arr[j]) != 1) return 1;
}
int count = distinct(arr, N);
free(arr); // free after use
printf("Case #%d: %d\n", ++i, count);
}
}
My issue is that I am getting segmentation fault (core dumped) each time I try, I have yet to clean up my code, but I am stumped.
I must enter the values in with the compiler e.g "./filename 0 100" whereby 0 is min and 100 is max.
It must then fill the array of 10 elements with random numbers (0-100). I am so close, just can't fathom the main function.
Also, how can I print the array {0,1,2,3} in format "[0,1,2,3]" including the commas, without it looking like "[0,1,2,3, ]"
#include <stdlib.h>
#include <stdio.h>
int getRandom(int min, int max);
void fillArray(int data[], int size, int min, int max);
void printArray(int data[], int size);
int main(int argc, char *argv[]) {
int a;
int b;
if (argc>=3){
a = atoi(argv[1]);
b = atoi(argv[2]);
int arr[10];
printf("\t An array with random values from 0 to 100 \n");
fillArray(arr,10 ,a, b);
printArray(arr, 10);
} else {
printf("Incorrect number of arguments - please call with assignment min max\n");
}
return 0;
}
int getRandom(int min, int max) {
int result = 0;
int low = 0;
int high = 0;
if (min<max) {
low = min;
high = max+1;
} else {
low = max + 1;
high = min;
}
result = (rand() % (high-low)) + low;
return result;
}
void fillArray(int data[], int size, int min, int max){
int i;
for(i=min ; i < max+1; i++){
data[i] = getRandom(min,max);
}
}
void printArray(int data[], int size){
int i;
printf("[");
for(i=0; i<size; i++){
printf("%d,", data[i]);
}
printf("]");
}
I agree with #Steve Friedl that the main problem with your program lies in the fillArray function. There i should run from 0 to size.
As for your second question, testing whether you're printing the last number helps to suppress the unwanted comma:
void printArray(int data[], int size) {
printf("[");
for (int i = 0; i < size; i++) {
printf("%d", data[i]);
if (i < size - 1)
printf(",");
}
printf("]");
}
If you prefer a more compact solution (although with an optimizing compiler there's not really a difference), you could write it as:
void printArray(int data[], int size) {
printf("[");
for (int i = 0; i < size; i++) {
printf("%d%c", data[i], i < size-1 ? ',' : ']');
}
}
Also, in your main function, you should include a and b in your printing:
printf("\t An array with random values from %d to %d \n", a, b);
I believe this is blowing things up for you:
void fillArray(int data[], int size, int min, int max){
int i;
for(i=min ; i < max+1; i++){ // <-- HERE
data[i] = getRandom(min,max);
}
}
The calling function allocates 10 items in the arr array, and that's passed as the size parameter, but you're not using that parameter to limit filling up the array. If the max value is 100, then it's trying to fill one hundred slots instead of just ten.
for (i = 0; i < size; i++)
data[i] = getRandom(min,max);
should fix at least this issue.
EDIT: The comma thing, I prefer to add commas before the items unless this is the first. In this case it doesn't matter much, but it's more general, especially for variable-length lists where you don't know you're at the end until you get there. Augmenting the helpful response from #JohanC :
void printArray(int data[], int size) {
printf("[");
for (int i = 0; i < size; i++) {
if (i > 0) printf(",");
printf("%d", data[i]);
}
printf("]");
}
Firstly I am fairly familar with Java programming and have just started to learn C programming.
Below is a program that takes inputted integers and finds the min, max and sum.
To me (at least) that code written seems logical in properly performing the needed tasks and functions.
#include <stdio.h>
#include <limits.h>
int sum(int array[], unsigned int length) {
int sumTest;
for (int i = 0; i < length; i++) {
sumTest = sumTest + array[i];
}
return sumTest;
}
int max(int array[], unsigned int length) {
int maxTest = array[0];
for (int i = 0; i < length; i++) {
if (array[i] > maxTest) {
array[i] = maxTest;
}
}
return maxTest;
}
int min(int array[], unsigned int length) {
int minTest = array[0];
for (int i = 0; i < length; i++) {
if (array[i] < minTest) {
array[i] = minTest;
}
}
return minTest;
}
int main(void) {
unsigned int length = 0;
scanf("%u", &length);
int array[length];
int temp = -1;
for (int i = 0; i < length; i++) {
scanf("%d", &temp);
array[i] = temp;
}
printf("SUM: %d\n", sum(array, length));
printf("MAX: %d\n", max(array, length));
printf("MIN: %d\n", min(array, length));
return 0;
}
However when I type in the console some entries the results vary every time.
1
10
SUM: 286271434
MAX: 10
MIN: 10
Again
1
10
SUM: -72217974
MAX: 10
MIN: 10
My compiler highlights the "<" sign in the for loops in the three methods min,max and sum telling me I am comparing unsigned and signed integers. To fix this I have tried fixing the line to look like this.
for (unsigned int i = 0; i < length; i++) {
Unfortunately I still get the same results, which logically to me makes sense as I have read that unsigned integers can hold large positive numbers. I've read a bit about C being more about memory management, is it possible that I am not considering memory as a factor. I've truth fully been looking up the syntax from handbooks and forum posts none of which don't seem to consider memory as a factor and which seems no different from java.
Can someone help me understand why this happening and what a solution is.
Thank you.
You don't ever initialize sumTest to anything before using it to keep track of the sum so the value is indeterminate. Setting it to 0 should fix the issue like so:
int sum(int array[], unsigned int length) {
int sumTest = 0;
for (int i = 0; i < length; i++) {
sumTest = sumTest + array[i];
}
return sumTest;
}
Initialize sum_test=0;.
While finding the min/max instead of saving the temp value you modify the array. This should solve it:
min_test = array[i];
As the other answers have noted, sumTest needs to be initialized to 0 before use.
You might also want to test what happens with
unsigned int length = 0;
scanf("%u", &length);
int array[length];
when you enter a very large value for length.
You have not initialized the sumTest, so it takes any garbage value. To make it more meaningful initialize it to 0
i.e. int sumTest = 0;
The code does run. This is a little different version of quicksort I am working on. I am running into some major issues with it. First off It prints out the first element in the array as n: for example(if you set n = 3, even if you make the first element in the array 1 lets say, it will still print out 3 as the first element). Also when you print out the sorted version it doesn't actually change anything.
Example input with n = 3,
Set values = 8 , 7 , 6
Initial output will equal 3 , 7 , 6
Final output will equal 3 , 7 , 6
(The output SHOULD be 6 , 7 , 8)
I haven't been able to find any code online similar to my code, so this may be something new! Thanks.
//preprocessor directives and header files
#include <stdio.h>
#define MAX_ARRAY_SIZE 50
//function prototypes separated by data types
void print_array( int array[], int n ); // Print out the array values
void swap( int array[], int index1, int index2 ); // Swap two array elements.
void quicksort( int array[], int low, int high ); // Sorting algorithm
int populate_array( int array[] ); // Fill array with values from user.
int partition( int array[], int low, int high ); // Find the partition point (pivot)
//the main function
int main(void)
{
int array[MAX_ARRAY_SIZE];
//set n = to size of user created size of array
int n = populate_array(&array[MAX_ARRAY_SIZE]);
//print the original array to the screen
print_array(&array[MAX_ARRAY_SIZE], n );
//perform the algorithm
quicksort(array, 0, n-1);
printf("The array is now sorted:\n");
print_array(&array[MAX_ARRAY_SIZE], n);
return 0;
}
// *array and array[] are the same...
int populate_array(int array[])
{
int n = -1;
printf("Enter the value of n > ");
scanf("%d", &n);
if(n > MAX_ARRAY_SIZE)
{
printf("%d exceeds the maximum array size. Please try again.\n\n", n);
populate_array( &array[MAX_ARRAY_SIZE]);
}
else if(n < 0)
{
printf("%d is less than zero. Please try again.\n\n", n);
populate_array( &array[MAX_ARRAY_SIZE]);
}
else if(n == 0)
{
printf("%d Array of size 0? Please don't try this, and... Please try again.\n\n", n);
populate_array( &array[MAX_ARRAY_SIZE]);
}
else
{
for(int i = 0; i < n; i++)
scanf("%d", &array[i]);
}
printf("The initial array contains: \n");
return n;
}
void print_array(int array[], int n)
{
for(int i = 0; i < n; i++)
printf("%+5d\n", array[i]);
}
void quicksort(int array[], int low, int high)
{
if (low < high)
{
/* pivot is partitioning index, array[p] is now
at right place */
int pivot = partition(array, low, high);
// Separately sort elements before
// partition and after partition
quicksort(array, low, pivot - 1);
quicksort(array, pivot + 1, high);
}
}
int partition(int array[], int low, int high)
{
int pivot = array[high];
int i = low;
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (array[j] <= pivot)
{
swap(array, i, j);
i = i +1;
}
}
swap(array, i, high);
return i;
}
void swap(int array[], int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
Here is a heavily commented answer. I changed the code quite a bit.
This is now a fully functional quicksort array for user input.
The problem I was having before was with the &array[MAX_ARRAY_SIZE]. This needed to be changed to just "array" instead. The &array[MAX_ARRAY_SIZE] was trying to access a memory location past the actual size of the array.
Changing it to just "array" means that it is accessing the first element in the array.(Correct if wrong)
I also changed the populate array function to be a robust do-while loop. And instead of trying to re-call the function inside itself. The do-while loop will only allow you to change the value of 'n'.
/*
Author: Zachary Alberda
*/
//preprocessor directives and header files
#include <stdio.h>
#define MAX_ARRAY_SIZE 50
//function prototypes separated by data types
void print_array( int array[], int n ); // Print out the array values
void swap( int array[], int index1, int index2 ); // Swap two array elements.
void quicksort( int array[], int low, int high ); // Sorting algorithm
int populate_array( int array[] ); // Fill array with values from user.
int partition( int array[], int low, int high ); // Find the partition point (pivot)
//the main function
int main(void)
{
int array[MAX_ARRAY_SIZE]; //set n = to size of user created size of array
int n = populate_array(array); //print the original array to the screen
print_array(array, n ); //print array of size n
quicksort(array, 0, n-1); //perform the algorithm low is 0, high is size of array -1.
printf("The array is now sorted:\n");//Inform user that the array is sorted.
print_array(array, n);//print the sorted array
return 0; // exit without errors.
}
// *array and array[] are the same...
int populate_array(int array[])
{
int n = -1;//initialize variable n(local variable to function populate_array)
printf("Enter the value of n > ");//inform user of what to input
scanf("%d", &n);
/*
CHECK IF N IS VALID
This is a robust do while loop!
1) Performs the if-statements while 'n' is not valid in a do-while loop.
-The reason I do this is because it will cause errors
if the if-statements are individual without the do-while loop.
2)The program will not crash if you try different combinations
of inputs for 'n'. :)
3)Checks if user input is > MAX_ARRAY_SIZE
4)Checks if user input is < 0
5)Checks if user input is == 0
*/
do
{
if(n > MAX_ARRAY_SIZE)
{
printf("%d exceeds the maximum array size. Please try again.\n\n", n);
printf("Enter the value of n > ");
scanf("%d", &n);
}
else if(n < 0)
{
printf("%d is less than zero. Please try again.\n\n", n);
printf("Enter the value of n > ");
scanf("%d", &n);
}
else if(n == 0)
{
printf("%d Array of size 0? Please don't try this, and... Please try again.\n\n", n);
printf("Enter the value of n > ");
scanf("%d", &n);
}
}while(n <= 0 || n > MAX_ARRAY_SIZE);
//scan in array if user input is valid
for(int i = 0; i < n; i++)
scanf("%d", &array[i]);
printf("The initial array contains: \n");//Inform user of initial array
return n;
}
void print_array(int array[], int n)
{
//print array in pre/post order before and after the algorithm.
for(int i = 0; i < n; i++)
printf("%+5d\n", array[i]);
}
void quicksort(int array[], int low, int high)
{
if (low < high)
{
/* pivot is partitioning index, array[pivot] is now
at right place */
int pivot = partition(array, low, high);
// Separately sort elements before
// partition and after partition
quicksort(array, low, pivot - 1);
quicksort(array, pivot + 1, high);
}
}
int partition(int array[], int low, int high)
{
int pivot = array[high];
int i = low;
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (array[j] <= pivot)
{
swap(array, i, j);
i = i +1;
}
}
swap(array, i, high);
return i;
}
void swap(int array[], int index1, int index2)
{
//swap positions of array index 1 and 2
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}