#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define LIMIT 30000
void CreateArray(int *p, int N) {
int i;
p = (int *)malloc(N * sizeof(int));
srand((long)210);
for (i = 0; i < N; i++)
*(p + i) = rand() % LIMIT;
for (i = 0; i < N; i++)
printf("%d ", p[i]);
}
void Search(int *p, int N, int key) {
int comparisons = 0, success_search = 0;
int i;
clock_t start, end;
double elapsed;
start = clock();
for (i = 0; i < N; i++) {
if (key == p[i]) {
comparisons++;
success_search++;
printf("\nFound!");
break;
} else {
comparisons++;
printf("\nNot found!");
}
}
end = clock();
elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("\nTotal comparisons: %d \n", comparisons);
printf("Time elapsed: %f \n", elapsed);
printf("Successful comparisons: %d \n\n", success_search);
}
int main() {
int N, i, p, key;
key = 1;
CreateArray(&p, N = 7);
Search(&p, N, key);
}
I'm trying to create a pseudo-random array and then try to search for a specific number in it and keep track of the total comparisons made and the total time needed to complete the search. I have manually inserted a number that is not in the array and it keeps saying that the number was found after 3 comparisons. Also the time elapsed always appears to be zero. I can't figure out what's wrong.
Make the following changes.
1) You need to allocate array and pass it to different functions. So "n" should be a pointer.
int *n = NULL;
2) You want CreateArray() to allocate memory and pass the pointer.
void CreateArray (int **p, int N)
3) You have to pass pointer to Search(). So call from main() becomes
Search(p, N, key);
I think it should work fine as expected now.
For time elapsed, you refer to Weather Vane's comment in your question.
There are multiple problems in your code:
CreateArray should return the pointer to the allocated space. Passing it a pointer to a local int in main() makes no sense.
you should test for malloc potential failure.
Search should get the pointer to the allocated array, not the address of a local int.
Search should print the Not found message just once at the end of the scan phase.
If you want to count the number of successful comparisons, you should not break from the loop when you find the first one, but then the total number of comparisons is N.
for better timing accuracy, you should avoid using printf inside the timed fragment.
you should free the memory before exiting the program.
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LIMIT 30000
void CreateArray(int N) {
int i;
int *p = (int *)malloc(N * sizeof(int));
if (p != NULL) {
srand((long)210);
for (i = 0; i < N; i++)
*(p + i) = rand() % LIMIT;
for (i = 0; i < N; i++)
printf("%d ", p[i]);
}
return p;
}
void Search(int *p, int N, int key) {
int comparisons = 0, success_search = 0;
int i;
clock_t start, end;
double elapsed;
start = clock();
for (i = 0; i < N; i++) {
comparisons++;
if (key == p[i])
success_search++;
}
end = clock();
elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
if (success_search)
printf("Found!\n");
else
printf("Not found!\n");
printf("Total comparisons: %d\n", comparisons);
printf("Successful comparisons: %d\n\n", success_search);
printf("Time elapsed: %f\n", elapsed);
}
int main() {
int N, i, key;
int *p;
key = 1;
N = 7;
p = CreateArray(N);
if (p == NULL) {
fprintf(stderr, "cannot allocate memory for %d elements\n", N);
return 1;
}
Search(p, N, key);
free(p);
return 0;
}
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.
Hello I've recently started testing out QuickSort. I've written a program that makes array with the size of user's input and fills it with random numbers, then it uses quicksort to sort it. Now here is my problem. On linux machine with just 4gb of RAM I could make array with a size up to 10^8 before computer would become unusable. On my mac with 8gb of RAM I can only make an array with a size up to 10^6. If I try making an array with size of 10^7 and greater I get segmentation fault. Is it some hard restriction from operating system, can it be changed?
Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int FindPivot(int i, int j);
void PrintTable(int* table, int size);
void NextThing(int* table, int size);
void QuickSort(int* table, int i, int j);
void RandomizeTable (int* table, int size) {
int i;
for (i = 0; i < size; i++) {
table[i] = -10000 + rand() % (10000+1-(-10000));
//printf("%d\t", table[i]);
}
printf("\n");
NextThing(table, size);
}
void NextThing(int* table, int size) {
printf("Sorting the table...\n");
clock_t x = clock();
QuickSort(table, 0, size - 1);
clock_t y= clock();
printf("Time it took : %fs\n", ((double)(y - x))/CLOCKS_PER_SEC);
//Second sorting of the table, just to see how long does it take for quicksort to sort an already sorted table
printf("Sorting the table...\n");
clock_t x2 = clock();
QuickSort(table, 0, size - 1);
clock_t y2= clock();
printf("Time it took : %fs\n", ((double)(y2 - x2))/CLOCKS_PER_SEC);
exit(0);
}
void Swap(int* table, int i, int j) {
int temp;
temp = table[i];
table[i] = table[j];
table[j] = temp;
}
int Partition(int* table, int i, int j) {
int p, q, key;
p = FindPivot(i, j);
key = table[p];
Swap(table, i, p);
for (p = i, q = i + 1; q <= j; q++)
if (table[q] < key) {
p++;
Swap(table, p, q);
}
Swap(table, i, p);
return p;
}
void QuickSort(int* table, int i, int j) {
int p;
if (i < j) {
p = Partition(table, i, j);
QuickSort(table, i, p - 1);
QuickSort(table, p + 1, j);
}
}//QuickSort
void PrintTable(int* table, int size) {
int i;
for (i = 0; i < size; i++)
printf("%d", table[i]);
printf("\n");
}
int FindPivot(int i, int j) {
int pivot;
/*pivot = i + rand() % (j + 1 - i); */ //Method I randomizing pivot
pivot = (i + j) / 2; //Method II arithmetic avarage
return pivot;
}
int main () {
time_t t;
srand((unsigned) time(&t));
int n;
printf("Array size:");
scanf("%d", &n);
int tab[n]; //Here is where error occurs if array size is > 10^6
RandomizeTable(tab, n);
}
I am almost sure it's problem with making an array of such size. I've tried debugging the code with a printf. It printed text if it was before making an array (in main()) and wouldn't print it if I put it afterwards.
Assuming you're using C99,it may be implementation specific (but probably not), where the maximum size of any object is limited by SIZE_MAX, from this post, which means the minimum (in theory) could be less than 10^6 (1,000,000) bytes.
If this is the issue, you can check with something like
size_t max_size = (size_t)-1;
From here.
Otherwise, the other post is your best bet - if you can't implement it on the stack, using malloc can allocate it in the heap.
int *tab = malloc(n*sizeof(int));
This will allocate the (n * sizeof(int in bytes)) bytes in the heap, and should work.
Note that if you allocate memory this way, it'll need to be manually deleted, so you should call free on it when you're done.
free(tab)
*EDITED*
I fixed some issues but i'm still calling it wrong. Somehow when i don't declare with int the GetRand function more than once i get more error messages.
What i want as a final result is to print the array i created and also print the maximum and average of the values of it (only counting every number > -1).
I'm calling the maxavg() function wrong and i'm getting an error message "Error] expected identifier or '(' before '{' token" at the beginning of maxavg which i haven't been able to fix.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
int GetRand(int min, int max);
int maxavg();
int main ()
{
int a[21][21], i , j, average, maximum;
for (i = 0; i < 21; i++)
{
for ( j = 0; j < 21; j++)
{
a[i][j] = GetRand(0, 100);
printf("%3d" , a[i][j]);
}
a[2][15] = -1;
a[10][6] = -1;
a[13][5] = -1;
a[15][17] = -1;
a[17][17] = -1;
a[19][6] = -1;
printf("\n");
}
average = maxavg();
maximum = maxavg();
printf("average = %d \n maximum = %d", average, maximum);
return 0;
}
// random seed
int GetRand(int min, int max);
int get ()
{
int i, r;
for (i = 0; i < 21; i++)
{
r = GetRand(0, 100);
printf("Your number is %d \n", r);
}
return(0);
}
int GetRand(int min, int max)
{
static int Init = 0;
int rc;
if (Init == 0)
{
srand(time(NULL));
Init = 1;
}
rc = (rand() % (max - min +1) +min);
return (rc);
}
// max and average
int maxavg();
{
int max=INT_MIN, sum=0, count=0, avg, n, m, current;
current = a[i][j];
avg = sum/count;
for(n = 0; n < 21; n++){
for(m =0; m < 21; m++){
if(current > -1){
sum = sum + current;
count = count + 1;
if(current > max){
max = current;
}
}
}
}
return(0);
}
This program will only print the elements of the array a in the for-loop in main. Apart from GetRand, no other function is called, so get and maxavg are never executed, despite being defined. So yes, you should first of all call it from main if you want to see what it does.
There is also a big problem with the logic of your maxavg function though.
Where is the array you're presuming to iterate over? You haven't passed any parameter to maxavg (nor declared and set a local variable). It looks like you're expecting current to contain these array element values, but the reality is you've never set the value of this variable to anything. You should be using the i and j variables as indexes into the array you should add, as in arr[i][j].
A few other notes:
You really should be setting a[2][15], a[10][6] and so on after the loop has finished, not in every single iteration.
You've declared GetRand twice.
maxavg returns an int, yet there is no return statement in your function ("control reaches end of non-void function").
I wrote some C code to analyze the number of comparisons and runtime of building a heap and running heapsort. However, I'm not sure if the output of my code makes sense. Heapsort should perform at O(n log n), but the number of comparisons I'm seeing doesn't seem to be very close to that. For example, for an input of size n = 100, I'm seeing ~200 comparisons to build the heap and ~800 comparisons in heap sort. Am I just analyzing the data wrong, or is there something wrong with the way I'm collecting comparisons in my code?
I can provide a link to github if it would make a difference for anyone.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
void bottom_up_heap_sort(int*, int);
void heap_sort(int*, int);
void sift_up(int*, int);
void sift_down(int*, int);
void build_max_heap(int*, int);
void bottom_up_build_max_heap(int*, int);
void randomize_in_place(int*, int);
int* generate_array(int);
void swap(int*, int*);
int cmp(int, int);
void print_array(int*, int);
int heapsize;
unsigned long comparison_counter;
clock_t begin, end;
double time_spent;
int main() {
int k, N;
int* A;
int* B;
int i;
printf("Testing Sift_Down Heap Sort\n");
for(k = 2; k <= 5; k++) {
comparison_counter = 0;
N = (int)pow((double)10, k);
begin = clock();
A = generate_array(N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time Spent Generating Array: %f\n", time_spent);
// print the first unsorted array
//printf("Unsorted Array:\n");
//print_array(A, N);
begin = clock();
// call heap_sort on the first unsorted array
heap_sort(A, N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
// show that the array is now sorted
//printf("Sorted array: \n");
//print_array(A, N);
printf("Done with k = %d\n", k);
printf("Comparisons for Heap Sort: %lu\n", comparison_counter);
printf("Time Spent on Heap Sort: %f\n", time_spent);
printf("\n");
}
printf("----------------------------------\n");
printf("Testing Sift_Up Heap Sort\n");
for(k = 2; k <= 5; k++) {
comparison_counter = 0;
N = (int)pow((double)10, k);
begin = clock();
B = generate_array(N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time Spent Generating Array: %f\n", time_spent);
// print the unsorted array
//printf("Unsorted Array:\n");
//print_array(B, N);
begin = clock();
// call heap_sort on the unsorted array
bottom_up_heap_sort(B, N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
// show that the array is now sorted
//printf("Sorted array: \n");
//print_array(B, N);
printf("Done with k = %d\n", k);
printf("Comparisons for Heap Sort: %lu\n", comparison_counter);
printf("Time Spent on Heap Sort: %f\n", time_spent);
printf("\n");
}
printf("----------------------------------\n");
return 0;
}
void bottom_up_heap_sort(int* arr, int len) {
int i;
// build a max heap from the bottom up using sift up
bottom_up_build_max_heap(arr, len);
printf("Comparisons for heap construction: %lu\n", comparison_counter);
comparison_counter = 0;
for(i = len-1; i >= 0; i--) {
// swap the last leaf and the root
swap(&arr[i], &arr[0]);
// remove the already sorted values
len--;
// repair the heap
bottom_up_build_max_heap(arr, len);
}
}
void heap_sort(int* arr, int len) {
int i;
// build a max heap from the array
build_max_heap(arr, len);
printf("Comparisons for heap construction: %lu\n", comparison_counter);
comparison_counter = 0;
for(i = len-1; i >= 1; i--) {
swap(&arr[0], &arr[i]); // move arr[0] to its sorted place
// remove the already sorted values
heapsize--;
sift_down(arr, 0); // repair the heap
}
}
void sift_down(int* arr, int i) {
int c = 2*i+1;
int largest;
if(c >= heapsize) return;
// locate largest child of i
if((c+1 < heapsize) && cmp(arr[c+1], arr[c]) > 0) {
c++;
}
// if child is larger than i, swap them
if(cmp(arr[c], arr[i]) > 0) {
swap(&arr[c], &arr[i]);
sift_down(arr, c);
}
}
void sift_up(int* arr, int i) {
if(i == 0) return; // at the root
// if the current node is larger than its parent, swap them
if(cmp(arr[i], arr[(i-1)/2]) > 0) {
swap(&arr[i], &arr[(i-1)/2]);
// sift up to repair the heap
sift_up(arr, (i-1)/2);
}
}
void bottom_up_build_max_heap(int* arr, int len) {
int i;
for(i = 0; i < len; i++) {
sift_up(arr, i);
}
}
void build_max_heap(int* arr, int len) {
heapsize = len;
int i;
for(i = len/2; i >= 0; i--) {
// invariant: arr[k], i < k <= n are roots of proper heaps
sift_down(arr, i);
}
}
void randomize_in_place(int* arr, int n) {
int j, k;
double val;
time_t t;
// init the random number generator
srand((unsigned)time(&t));
// randomization code from class notes
for(j = 0; j < n-1; j++) {
val = ((double)random()) / 0x7FFFFFFF;
k = j + val*(n-j);
swap(&arr[k], &arr[j]);
}
}
// this function is responsible for creating and populating an array
// of size k, and randomizing the locations of its elements
int* generate_array(int k) {
int* arr = (int*) malloc(sizeof(int)*k-1);
int i, j, x, N;
double val;
time_t t;
// init the random number generator
srand((unsigned)time(&t));
// fill the array with values from 1..N
for(i = 0; i <= k-1; i++) {
arr[i] = i+1;
}
N = (int)pow((double)10, 5);
// randomize the elements of the array for 10^5 iterations
for(i = 0; i < N; i++) {
randomize_in_place(arr, k);
}
return arr;
}
// swap two elements
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int cmp(int a, int b) {
comparison_counter++;
if(a > b) return 1;
else if(a < b) return -1;
else return 0;
}
// print out an array by iterating through
void print_array(int* arr, int size) {
int i;
for(i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
O(n log n) (or in general O(f(x))) does not give you any idea about the expected value at a single point.
That's because big-O notation ignores constant factors. In other words, all of n * log(n), 0.000001 * n * log(n) and 1000000 * n * log(n) are in O(n log n). So the result for a particular value of n is completely undetermined.
What you can deduce from big-O notation is the effect of modify the control variable. If a function involves O(n) operations, then it is expected that doubling n will double the number of operations. If a function involves O(n2) operations, then it is expected that doubling n will quadruple the number of operations. And so on.
The actual number for such small values of n doesn't really matter, as the constant factors are omitted in the complexity. What matters is the growth of your algorithm, measuring for increasingly larger values of n, and plotting them should give roughly the same graph as your theoretical complexity.
I tried your code for a couple of n, and the increase in complexity was approximately O(n logn )
i'm tryin' to print the time taken for a merge sort on an array of random numbers generated by the computer, whose size should be taken from the user during runtime, but it's givin' a segmentation fault. can anyone help correct my mistake?
part(int arr[],int min,int max)
{
int mid;
if(min<max)
{
mid=(min+max)/2;
part(arr,min,mid);
part(arr,mid+1,max);
merge(arr,min,mid,max);
}
}
merge(int arr[],int min,int mid,int max)
{
int tmp[30];
int i,j,k,m;
j=min;
m=mid+1;
for(i=min; j<=mid && m<=max ; i++)
{
if(arr[j]<=arr[m])
{
tmp[i]=arr[j];
j++;
}
else
{
tmp[i]=arr[m];
m++;
}
}
if(j>mid)
{
for(k=m; k<=max; k++)
{
tmp[i]=arr[k];
i++;
}
}
else
{
for(k=j; k<=mid; k++)
{
tmp[i]=arr[k];
i++;
}
}
for(k=min; k<=max; k++)
arr[k]=tmp[k];
}
main(){
int x, *b, i;
double t5;
printf("array size = \t");
scanf("%d", &x);
b = (int)malloc(x*sizeof(int));
srand(time(NULL));
for(i = 0; i<x; i++) b[i] = rand();
time_t t1 = 0;
time_t t2 = 0;
t1 = time(NULL);
part(b, 0, (x-1));
t2 = time(NULL);
printf("time taken for merge sort = %f sec\n", (t1 - t2));
}
There are several issues with the code here:
All relevant prototypes to system functions are missing, Fix this by including the necessary headers.
The prototype for merge() is missing, as needed by part(). Add it.
Functions not returning anything shall be typed as void. Declare them alike.
There is no need to cast the result of malloc(). And if it is done it should be done to the correct type: int * here not int!
time_t is an integer in most of the cases, so if it is don't use the conversion specifier for double when trying to print time_t, but the correct integer conversion specifier that is d for 32bit wide time_t or ld for 64bit wide time_t. However to print difference of time_ts use difftime(), which actually results in a double.
Last not least the temporary buffer in merge() doesn't scale. Make it max+1 elements wide.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void merge(int arr[], int min, int mid, int max);
void part(int arr[], int min, int max);
void part(int arr[], int min, int max)
{
int mid;
if (min < max)
{
mid = (min + max) / 2;
part(arr, min, mid);
part(arr, mid + 1, max);
merge(arr, min, mid, max);
}
}
void merge(int arr[], int min, int mid, int max)
{
int tmp[max + 1];
int i, j, k, m;
j = min;
m = mid + 1;
for (i = min; j <= mid && m <= max; i++)
{
if (arr[j] <= arr[m])
{
tmp[i] = arr[j];
j++;
}
else
{
tmp[i] = arr[m];
m++;
}
}
if (j > mid)
{
for (k = m; k <= max; k++)
{
tmp[i] = arr[k];
i++;
}
}
else
{
for (k = j; k <= mid; k++)
{
tmp[i] = arr[k];
i++;
}
}
for (k = min; k <= max; k++)
arr[k] = tmp[k];
}
int main(void)
{
int x, *b, i;
printf("array size = \t");
scanf("%d", &x);
b = malloc(x * sizeof(int));
srand(time(NULL ));
for (i = 0; i < x; i++)
b[i] = rand();
time_t t1 = 0;
time_t t2 = 0;
t1 = time(NULL);
part(b, 0, x - 1);
t2 = time(NULL);
printf("time taken for merge sort = %f sec\n", difftime(t2, t1));
}
time uses a type called time_t. To use it to find an elapsed time in seconds you must do something like this:
time_t time1, time2;
double seconds;
time(&time1);
...
time(&time2);
seconds = difftime(time2, time1);
Also, remove the cast from malloc. malloc returns a void pointer which is implicitly cast to an int pointer for you:
b = malloc(x * sizeof(*b));