Find recursively the third biggest element of array in c - c

This one was asked in one of my computer science exam months has passed but I couldn't find any answers.Sometimes I wonder if its possible or not here is the prototype.
The objective is to return the index of third largest element in an integer array.I have learned how to find the largest and second largest but this seems hard.
int third_max(int arr[],int size);
I am looking a recursive function that will find it by maybe only one functions help that is max(a,b) which returns the max of a,b.
Edit : There is no duplicate elements

My implementation of third_max(). (It uses an assert to catch a starting array shorter than three elements.) First it sorts the first three elements in the array in place; if the array is only three elements long, it returns the first. If the array is more than three elements, it compares the first and forth elements, keeping the larger as the fourth element. Finally, it calls it self recursively dropping off the first array element and decrimenting the array size:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define ARRAY_SIZE (10)
int third_max(int array[], size_t size) {
assert(size > 2);
if (array[0] > array[1]) {
int temp = array[1];
array[1] = array[0];
array[0] = temp;
}
if (array[1] > array[2]) {
int temp = array[2];
array[2] = array[1];
array[1] = temp;
}
if (array[0] > array[1]) {
int temp = array[1];
array[1] = array[0];
array[0] = temp;
}
if (size == 3) {
return array[0];
}
if (array[0] > array[3]) {
array[3] = array[0];
}
return third_max(array + 1, size - 1);
}
int compare(const void *a, const void *b) {
const int *aa = a;
const int *bb = b;
return (*aa > *bb) - (*aa < *bb);
}
int main() {
int array[ARRAY_SIZE], control[ARRAY_SIZE];
srandomdev();
for (int i = 0; i < ARRAY_SIZE; i++) {
int x = -1;
while (x == -1) {
x = (random() & 127) - 63;
for (int j = 0; j < i; j++) {
if (array[j] == x) { // avoid duplicates
x = -1;
break;
}
}
}
control[i] = array[i] = x;
}
printf("[");
for (int i = 0; i < ARRAY_SIZE; i++) {
printf("%d, ", array[i]);
}
printf("] -> ");
printf("%d ", third_max(array, ARRAY_SIZE));
qsort(control, ARRAY_SIZE, sizeof(int), &compare);
printf("(%d)\n", control[ARRAY_SIZE - 3]);
return 1;
}
The rest of the code tests the third_max() function by creating an array of unique positive integers. It compares the results of the recursive function to that of a matching control array that is sorted and the third to last element extracted for comparison.
My third_max() doesn't call any other functions other than itself (i.e. no helper functions.) It is destructive on the array passed in.

Without any additional constraints, a naive but effective solution would simply be to create a sorted copy of the array, take the third element, then find that element in the original array and return its index. The theoretical complexity is O(n log n) in time and O(n) in space. An O(n) time solution is possible.

Related

Determine the three maximum and two minimum values of the array

Task:
Given a natural number N (set arbitrarily as a preprocessor constant) and one-dimensional array A0, A1, …, AN-1 of integers (generate positive and negative elements randomly, using the <stdlib.h> library function rand()). Perform the following actions: Determine the three maximum and two minimum values of this array.
Code with search for two minimum values:
#include <stdio.h>
#include <stdlib.h>
#define N 9
int main() {
int M[N], i, a[N], fbig, sbig, tbig, min, smin;
for (i = 0; i < N; i++) {
M[i] = rand() % 20 - 10;
printf("%i\t", M[i]);
}
printf("\n");
for (i = 0; i < N; i++) {
if (a[i] < min) {
smin = min;
min = a[i];
} else
if (a[i] < smin && a[i] != min)
smin = a[1];
}
printf("\nMinimum=%d \nSecond Minimum=%d", min, smin);
return 0;
}
I tried to compare array elements with each other but here is my result:
-7 -4 7 5 3 5 -4 2 -1
Minimum=0
Second Minimum=0
I would be very grateful if you could help me fix my code or maybe I'm doing everything wrong and you know how to do it right. Thank you for your time
I will revise my answer if op address what to do about duplicate values. My answer assume you want possible duplicate values in the minimum and maximum arrays, while other answers assume you want unique values.
The easiest solution would be to sort the input array. The minimum is the first 2 values and the maximum would be the last 3:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_N 3
#define MIN_N 2
#define N 9
void generate(size_t n, int a[n]) {
for(size_t i = 0; i < n; i++)
a[i] = rand() % 20 - 10;
}
void print(size_t n, int a[n]) {
for(size_t i = 0; i < n - 1; i++)
printf("%d, ", a[i]);
if(n) printf("%d\n", a[n-1]);
}
int cmp_asc(const void *a, const void *b) {
if(*(int *) a < *(int *) b) return -1;
if(*(int *) a > *(int *) b) return 1;
return 0;
}
int main() {
int t = time(0);
srand(t);
printf("%d\n", t); // essential for debugging
int a[N];
generate(N, a);
print(N, a);
qsort(a, N, sizeof *a, cmp_asc);
print(MIN_N, a);
print(MAX_N, a + (N - MAX_N));
}
If you cannot use sort then consider the following purpose built algorithm. It's much easier to use arrays (min and max) rather than individual values, and as a bonus this allows you to easily change how many minimum (MIN_N) and maximum (MAX_N) values you want. First we need to initialize the min and max arrays, and I use the initial values of the input array for that. I used a single loop for that. To maintain the invariant that the min array has the MIN_N smallest numbers we have seen so far (a[0] through a[i-1]) we have to replace() largest (extrema) of them if the new value a[i] is smaller. For example, if the array is min = { 1, 10 } and the value we are looking at is a[i] = 5 then we have to replace the 10 not the 1.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_N 3
#define MIN_N 2
#define N 9
void generate(size_t n, int a[n]) {
for(size_t i = 0; i < n; i++)
a[i] = rand() % 20 - 10;
}
void print(size_t n, int a[n]) {
for(size_t i = 0; i < n - 1; i++)
printf("%d, ", a[i]);
if(n) printf("%d\n", a[n-1]);
}
int cmp_asc(const void *a, const void *b) {
if(*(int *) a < *(int *) b) return -1;
if(*(int *) a > *(int *) b) return 1;
return 0;
}
int cmp_desc(const void *a, const void *b) {
return cmp_asc(b, a);
}
void replace(size_t n, int a[n], int v, int (*cmp)(const void *, const void *)) {
int *extrema = &a[0];
for(size_t i = 1; i < n; i++) {
if(cmp(extrema, &a[i]) < 0) {
extrema = &a[i];
}
}
if(cmp(extrema, &v) > 0)
*extrema = v;
}
void min_max(size_t n, int a[n], size_t min_n, int min[n], size_t max_n, int max[n]) {
for(size_t i = 1; i < n; i++) {
if(i < min_n)
min[i] = a[i];
else
replace(min_n, min, a[i], cmp_asc);
if(i < max_n)
max[i] = a[i];
else
replace(max_n, max, a[i], cmp_desc);
}
}
int main() {
int t = time(0);
srand(t);
printf("%d\n", t); // essential for debugging
int a[N];
generate(N, a);
print(N, a);
int min[MIN_N];
int max[MAX_N];
min_max(N, a, MIN_N, min, MAX_N, max);
print(MIN_N, min);
print(MAX_N, max);
}
and here is example output. The first value is a the seed in case you have to reproduce a run later. Followed by input, min and max values:
1674335494
-7, 0, -2, 7, -3, 4, 5, -8, -9
-9, -8
7, 5, 4
If MIN_N or MAX_N gets large, say, ~1,000+, then you want sort the min and max arrays and use binary search to figure out where to inserta[i]. Or use a priority queue like a heap instead of arrays.
There are multiple problems in your code:
min and smin are uninitialized, hence the comparisons in the loop have undefined behavior and the code does work at all. You could initialize min as a[0] but initializing smin is not so simple.
there is a typo in smin = a[1]; you probably meant smin = a[i];
Note that the assignment is somewhat ambiguous: are the maximum and minimum values supposed to be distinct values, as the wording implies, or should you determine the minimum and maximum elements of the sorted array?
For the latter, sorting the array, either fully or partially, is a simple solution.
For the former, sorting is also a solution but further testing will be needed to remove duplicates from the sorted set.
Here is a modified version to print the smallest and largest values:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 9
#define N_MIN 2
#define N_MAX 3
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
int a[N], i, j, e, dup;
int smallest[N_MIN], nsmall = 0;
int largest[N_MAX], nlarge = 0;
srand(time(NULL));
for (i = 0; i < N; i++) {
a[i] = rand() % 20 - 10;
printf("%i\t", a[i]);
}
printf("\n");
for (i = 0; i < N; i++) {
e = a[i];
dup = 0;
for (j = 0; j < nsmall; j++) {
if (e == smallest[j]) {
dup = 1;
break;
}
if (e < smallest[j]) {
swap(&e, &smallest[j]);
}
}
if (!dup && nsmall < N_MIN) {
smallest[nsmall++] = e;
}
e = a[i];
dup = 0;
for (j = 0; j < nlarge; j++) {
if (e == largest[j]) {
dup = 1;
break;
}
if (e > largest[j]) {
swap(&e, &largest[j]);
}
}
if (!dup && nlarge < N_MAX) {
largest[nlarge++] = e;
}
}
printf("smallest values: ");
for (i = 0; i < nsmall; i++) {
printf(" %d", smallest[i]);
}
printf("\n");
printf("largest values: ");
for (i = nlarge; i --> 0;) {
printf(" %d", largest[i]);
}
printf("\n");
return 0;
}
As already noted, the most direct way to do this would be to simply sort the array. (In fact, if all you need is an output of five integers then your array only need be five elements long.) But I will presume that that is not the point of this homework.
Your goal isn’t super efficiency or a pretty algorithm. It is simply to solve the tasks. Do them one at a time.
First question: How would you find the largest value?
Answer: Loop through the array, keeping track of the largest element found so far.
int largest = array[0]; // why start with this value?
for (int n = 0; n < size; n++)
if (array[n] > largest)
largest = array[n];
Second question: How would you find the smallest value?
Answer: Almost the same way, with only a simple change: Instead of testing if (array[n] > largest) we want to test if (array[n] < smallest), right?
int smallest = largest; // why start with this value?
for (int n = 0; n < size; n++)
if (...) // new condition goes here
smallest = array[n];
Third question: How would you find the second smallest value?
Answer: It should not surprise you that you just need to change the if condition in that loop again. An element would be the second smallest if:
it is the smallest value greater than the smallest.
Think about how you would change your condition:
int second_smallest = largest; // why start with this value?
for (int n = 0; n < size; n++)
if (... && ...) // what is the new test condition?
second_smallest = array[n];
Remember, this time you are testing two things, so your test condition needs that && in it.
Fourth question: can you write another loop to find the second-largest? How about the third-largest?
At this point you should be able to see the variation on a theme and be able to write a loop that will get you any Nth largest or smallest value, as long as you already have the (N-1)th to work against.
Further considerations:
Is it possible that the third-largest is the same as the second-smallest?
Or the smallest?
Is it possible for there to not be a third-largest?
Does it matter?
Put all these loops together in your main() and print out the results each time and you are all done!
...
int main(void)
{
int array[SIZE];
// fill array with random numbers here //
int largest = array[0];
for (...)
if (...)
...
int smallest = largest;
for (...)
if (...)
...
int second_smallest = largest;
for (...)
if (...)
...
int second_largest = smallest;
for (...)
if (...)
...
int third_largest = smallest;
for (...)
if (...)
...
printf( "The original array = " );
// print original array here, then: //
printf( "largest = %d\n", largest );
printf( "2nd largest = %d\n", second_largest );
printf( "3nd largest = %d\n", third_largest );
printf( "2nd smallest = %d\n", second_smallest );
printf( "smallest = %d\n", smallest );
return 0;
}
Example outputs:
{ 1 2 3 4 }
smallest = 1
2nd smallest = 2
3rd largest = 2
2nd largest = 3
largest = 4
{ 5 5 5 5 5 }
smallest = 5
2nd smallest = 5
3rd smallest = 5
largest = 5
{ 1 2 }
smallest = 1
2nd smallest = 2
3rd smallest = 2
largest = 2
Bonus: be careful with variable names. There has been no need to use short abbreviations since before the early nineties. Prefer clarity over brevity.

Complexity to find if there is a missing element in an array

I am trying to write a function (in C) that checks if an array has all the elements (between 0 and its "size-1")
For example, if the array's size is 3, it should have {0, 1, 2 } in any order.
The question is: what is the most efficient complexity to do this without an extra array?
The complexity of my attempt, showed below, is (average of nlogn + n).
edit: sorry for the miss understanding, any whole number can be an input, which means checking size wont work --> {0, 0, 3}
int check_missing_element(int *a, int n)
{
int i = 0;
quicksort(a, 0, n - 1);
for (i = 0; i < n; i++)
{
if (a[i] != i)
return 0;
}
return 1;
}
Walk the array using the value [0...n-1] of the element as the next element to visit.
As leaving each element, set its value to n. Any visited element with an n has already been visited and so is a failure - unless we have indexed ourselves. Any element with a value outside [0...n-1] is a failure.
After 'n' visits we are done. O(n).
Sort not needed. This does consume the array.
Here is an implementation of the cycle-chasing algorithm sketched in chux’ answer, along with a test program.
/* Return 1 iff each integer in 0...n-1 appears exactly once in a[0]...a[n-1].
Return 0 otherwise.
*/
int check_missing_element(int *a, int n)
{
// Reject elements that are out of bounds.
for (int i = 0; i < n; ++i)
if (a[i] < 0 || n <= a[i])
return 0;
// Define a value to mark already seen values with.
static const int AlreadySeen = -1;
// Work through the array.
for (int i = 0; i < n; ++i)
// If we already examined this element, ignore it.
if (a[i] != AlreadySeen)
{
/* Follow the cycle defined by x -> a[x]. If we encounter an
already seen element before returning to i, report rejection.
Otherwise, mark each encountered element seen.
*/
for (int j = a[i]; j != i;)
{
int next = a[j];
if (next == AlreadySeen)
return 0;
a[j] = AlreadySeen;
j = next;
}
}
// Every element has been seen once and only once. Report acceptance.
return 1;
}
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Define a comparator for sorting int values in ascending order.
static int Comparator(const void *a, const void *b)
{
int A = * (const int *) a;
int B = * (const int *) b;
return
A < B ? -1 :
A == B ? 0 :
+1;
}
// Provide a reference routine for testing check_missing_elements.
static int check_missing_elementReference(int *a, int n)
{
/* Sort the elements. Iff the array contains each value exactly once,
this results in an array containing 0, 1, 2, 3,... n-1.
*/
qsort(a, n, sizeof *a, Comparator);
// Test the sorted array.
for (int i = 0; i < n; ++i)
if (a[i] != i)
return 0;
return 1;
}
#define ArrayLimit 7
#define NumberOf(a) (sizeof (a) / sizeof *(a))
/* Define a structure used to iterator through test values.
The indices in the Index array will each run from -x to n, inclusive,
where x is the number of special values (defined below) and n is the array
size. The indices will be incremented lexicographically (odometer style).
For the indices from -x to -1, the associated value will be one of the
special values. For the indices from 0 to n, the associated value will
equal the index. Note that n is outside the bounds of array values that
pass the test. It is included in testing so that rejections based on it
are tested.
*/
typedef struct
{
int Index [ArrayLimit];
int Values[ArrayLimit];
} Iterator;
// Define special values to include in testing.
static const int SpecialValues[] = { INT_MIN, -1, INT_MAX };
/* Define the number of special values as an int, not a size_t, because we use
its negation and so need a signed type.
*/
#define NumberOfSpecialValues ((int) NumberOf(SpecialValues))
// Initialize an iterator.
static void InitializeIterator(Iterator *Iterator, int n)
{
for (int i = 0; i < n; ++i)
{
Iterator->Index [i] = -NumberOfSpecialValues;
Iterator->Values[i] = SpecialValues[0];
}
}
/* Increment an iterator. Return 0 if we are done (all fields rolled over,
bringing the iterator back to the initial state) and 1 otherwise.
*/
static int Increment(Iterator *Iterator, int n)
{
// Start at the rightmost field.
int j =n-1;
while (0 <= j)
{
// If this field has room to increase, increment it.
if (Iterator->Index[j] < n)
{
++Iterator->Index[j];
/* Set the associated value to either a special value or the
index value, as described above.
*/
Iterator->Values[j] =
Iterator->Index[j] < 0
? SpecialValues[Iterator->Index[j] + NumberOfSpecialValues]
: Iterator->Index[j];
// There is no carry into the next field, so we are done.
return 1;
}
/* This field rolls over and resets to its initial value. Then we
carry into the next field.
*/
Iterator->Index [j] = -NumberOfSpecialValues;
Iterator->Values[j] = SpecialValues[0];
--j;
}
// All fields rolled over, so we are done.
return 0;
}
// Print an array.
static void PrintArray(int *a, int n)
{
printf("[");
if (0 < n)
printf("%d", a[0]);
for (int i = 1; i < n; ++i)
printf(", %d", a[i]);
printf("]");
}
int main(void)
{
// Test each array size up to the limit.
for (int n = 1; n <= ArrayLimit; ++n)
{
// Iterator through all array values.
Iterator i;
for (InitializeIterator(&i, n); Increment(&i, n);)
{
/* Since the routines destroy the array, copy the array. Then
execute the routine and record the return value.
*/
int Buffer[ArrayLimit];
// Reference routine first.
memcpy(Buffer, i.Values, n * sizeof *Buffer);
int expected = check_missing_elementReference(Buffer, n);
// Subject routine.
memcpy(Buffer, i.Values, n * sizeof *Buffer);
int observed = check_missing_element (Buffer, n);
// Test for a bug.
if (expected != observed)
{
printf("Failure:\n");
printf("\tArray = "); PrintArray(i.Values, n); printf("\n");
printf("\tExpected %d but observed %d.\n", expected, observed);
exit(EXIT_FAILURE);
}
}
printf("Array length %d: Passed.\n", n);
}
}

How to fix "Program received signal SIGSEGV, Segmentation fault." while trying to access an array

I'm doing quick sorting with different methods of selecting pivots, I don't see any problems in my code, the functions work while testing separated, but when I put them together, they don't work most of the time.
I've tried moving the files to another path, and changing the way I access the array.
void quick_sort(uint32_t arr[], int first, int last, int pivot_opt)
{
int i, j;
uint32_t pivot = pivot_select(arr, last, pivot_opt);
i = first;
j = last;
do
{
comparations_count++;
while (arr[i] < pivot) i++; // Counting elements smaller than pivot
comparations_count++;
while (arr[j] > pivot) j--; // Counting elements greater than pivot
comparations_count++;
if (i <= j)
{
exchanges_count++;
swap(&arr[i++], &arr[j--]); // Placing smaller elements in the left, and greater elements in the right without touching the pivot
}
comparations_count++;
} while (i <= j);
comparations_count++;
if (first < j)
quick_sort(arr, first, j, pivot_opt); // Sorting smaller elements of array
comparations_count++;
if (i < last)
quick_sort(arr, i, last, pivot_opt); // Sorting greater elements of array
}
uint32_t pivot_select(uint32_t arr[], int last, int pivot_opt)
{
uint32_t pivot = 0;
int random_index = 0;
switch (pivot_opt)
{
case 0:
pivot = arr[last]; // Choosing the pivot as the last element in the array
break;
case 1:
random_index = rand()%(last); // Choosing the pivot as a random element of array
pivot = arr[random_index];
break;
case 2:
pivot = median(arr, last); // Choosing the pivot as avg of three random indexes of the array
break;
default:
break;
}
return pivot;
}
uint32_t median(uint32_t arr[], int n)
{
if (n <= 3)
{
return arr[0]; // If the array have 3 or less elements, choose as pivot first element
}
else
{
int index[3] = {0}; // Index of 3 elements of original array
int last_index = 0; // Last chosen index, to verify if index was selected
int i = 0;
while(i < 3) // Selecting 3 random index
{
int current_index = (rand()%(n));
if (current_index == last_index)
i--;
else
{
index[i++] = current_index;
last_index = current_index;
}
}
uint32_t array[3] = {arr[index[0]], arr[index[1]], arr[index[2]]}; // Creating array with the elements on random indexes
insertion_sort(array, 3); // Sorting the array
return array[1]; // Returning the pivot as the middle element of array
}
}
I'm getting this error on median function
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555546 in median (arr=<error reading variable: Cannot access memory at address 0x7fffff7fefd8>, n=<error reading variable: Cannot access memory at address 0x7fffff7fefd4>) at /media/storage/Codes/Data Structure/Recursive_Sorting/main.c:107
107 {
I put all the libraries I'm using so I don't miss one.
Code for testing:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#define size 1000
uint32_t comparations_count;
uint32_t exchanges_count;
int main(int argc, char** argv)
{
uint32_t array[size];
fill(array, size);
permute_array(array, size);
comparations_count = 0;
exchanges_count = 0;
quick_sort(array, 0, size-1, 2);
return 0;
}
void fill(uint32_t arr[], uint32_t n)
{
for (size_t i = 0; i < n; i++) // Filling the array in ascending order
arr[i] = i;
}
void swap(uint32_t *a, uint32_t *b)
{
// Swapping two elements
uint32_t t = *a;
*a = *b;
*b = t;
}
void permute_array(int a[], size_t n)
{
// Adapted from:
// https://www.geeksforgeeks.org/shuffle-a-given-array-using-fisher-yates-shuffle-algorithm/
srand(time(NULL)); // Init random seed
for (size_t i = n - 1; i > 0; i--) // Permute array
{
size_t j = rand() % (i+1); // Pick a random index from 0 to i
swap(&a[i], &a[j]); // Swap arr[i] with the element at random index
}
}
void insertion_sort(uint32_t arr[], size_t n)
{
uint32_t current_index = 0;
uint32_t current_value = 0;
for (size_t i = 1; i < n; i++) {
current_index = i;
current_value = arr[i];
while (current_index > 0) {
if (current_value < arr[current_index - 1]) {
swap(&arr[current_index], &arr[current_index-1]);
current_index--;
}else { break; }
}
}
}
Let's start with this one:
while (arr[i] < pivot) i++;
What if all the elements are less than pivot, your i will be out of bounds, change the condition to while(arr[i] < pivot && i <= j) i++;
Consider this one:
while (arr[j] > pivot) j--;
What if all the elements are greater than pivot, your j will be out of bounds (a negative number), change the condition here too.
According to my opinion, the above-mentioned areas are causing problems.
Happy debugging!

Heapsort implementation in C - array error

I was trying to implement Heapsort algorithm in C but I'm not sure I'm done it right. I also have an error "variably modified 'A' at file scope". I was searching similar topic on stackoverflow and I found out that heapSize should be const but then I couldn't use it as a variable in my functions. What should I do?
#include <stdio.h>
#include <math.h>
int heapSize = 100;
int length;
int A[heapSize];
int Heapify(int i) {
int l = 2*i;
int r = 2*i + 1;
int largest;
int tmp;
if( l <= heapSize && A[l] > A[i]) largest = l;
else largest = i;
if (r <= heapSize && A[r] > A[largest]) largest = r;
if (largest != i) {
tmp = A[i];
A[i] = A[largest];
A[largest] = tmp;
}
}
int BuildHeap() {
heapSize = length;
int i;
for (i = floor(length/2); i <= 1; i--) {
Heapify(i);
}
}
int main(void) {
int i,tmp;
BuildHeap();
for (i = length; i <= 2; i--) {
tmp = A[heapSize];
A[heapSize] = A[1];
A[1] = A[heapSize];
heapSize = heapSize - 1;
Heapify(1);
}
}
EDIT:
I changed the first part of program to:
#include <stdio.h>
#define LENGTH 100
int heapSize = 10;
int A[LENGTH]
and, based on your suggestions, replace the "floor(length/2)" to "LENGTH/2". I solve my problems with compiling but I'm pretty sure this implementation is just bad. Well, anyway thank you very much for your help. I really appreciate it.
There's lots of issues with your code.
First, you declare a global int length variable, but you never assign it any value. So the length is always ZERO.
In BuildHeap() you do:
for (i = floor(length/2); i <= 1; i--) ...
which starts with floor(0/2) that is with i==0. That value is less than 1 so the loop makes the first iteration and decrements i with the i-- expression — and i becomes minus one. Then the loop proceeds until the i value wraps over zero to become positive (and greater than 1). For 32-bit integers it would take about 2.14 billion iterations...
The very first thing your main() does is invoking BuildHeap() which in turn invokes (multiple times) Heapify(). The latter compares array items to decide if they should get swapped – but they were not assigned any values! You never fill the A array with any data...
Did you notice that you compare and swap items which are outside your A array (actually, before it), since BuildHeap() decrements i below zero and passes negatve index values to Heapify()...?
Your Heapify routine performs at most one swap in the array. It doesn't seem sufficient. Suppose the heap is already 3 levels deep, and the current item appears the smallest one in the heap; it should go to the deepest level, but how do you achieve that? A single swap moves the item just one level downwards.
This is how you could do it.
First, decide the maximum size of data you will handle and prepare the array:
#define LENGTH 100
int A[LENGTH + 1];
(You need 'plus one' because A[0] will not be a part of the heap — why?)
Then prepare variables to store an actual size of data:
int dataSize;
int heapSize;
and a routine to fill the array. You can read the user input or load data from a file, or just fill the array by some algorithm.
void FillArrayAscending() {
dataSize = 16;
for(int i = 1; i <= dataSize; i ++)
A[i] = i;
}
void FillArrayDescending() {
dataSize = 25;
for(int i = 1; i <= dataSize; i ++)
A[i] = 50 - i;
}
void FillArrayCrossed() {
dataSize = 20;
for(int i = 1; i <= dataSize; i += 2)
A[i] = 10 + i;
for(int i = 2; i <= dataSize; i += 2)
A[i] = 30 - i;
}
Then you can 'heapify'. To do that you sift the item down the heap – you iterate swapping until the item reaches its place:
void SiftDown(int i) {
while(i < heapSize) {
int largest = i;
if(2*i <= heapSize && A[i] < A[2*i])
largest = 2*i;
if(2*i + 1 <= heapSize && A[largest] < A[2*i + 1])
largest = 2*i + 1;
if(largest == i)
break; // the item reached its place
A[0] = A[largest];
A[largest] = A[i];
A[i] = A[0];
i = largest; // new position to sift down...
}
}
i indicates the item to be sifted down, largest denotes a swap destination, A[0] can be used as a temporary storage (why?).
Now you can build a heap in the array:
void BuildHeap() {
heapSize = dataSize;
for(int i = heapSize/2; i >= 1; i --)
SiftDown(i);
}
and retrieve items from a heap in a descending order:
void ExtractHeap() {
while(heapSize > 1) {
A[0] = A[1]; // take the max item from a heap
A[1] = A[heapSize]; // replace it with the last one
A[heapSize] = A[0]; // add the max one to the sorted part
heapSize --;
SiftDown(1); // re-heapify
}
}
Now you can do the whole processing:
int main(int, char**)
{
FillArrayAscending(); // or Descending or...
BuildHeap();
ExtractHeap();
// and here you can print the array contents
// for indices 1 .. dataSize
// to verify it is actually sorted
}

Removing Duplicates from an Array using C [duplicate]

This question already has answers here:
Algorithm: efficient way to remove duplicate integers from an array
(34 answers)
Closed 8 years ago.
I want small clarification in array concept in C.
I have array:
int a[11]={1,2,3,4,5,11,11,11,11,16,16};
I want result like this:
{1,2,3,4,5,11,16}
Means I want remove duplicates.
How is it possible?
You can't readily resize arrays in C - at least, not arrays as you've declared that one. Clearly, if the data is in sorted order, it is straight-forward to copy the data to the front of the allocated array and treat it as if it was of the correct smaller size (and it is a linear O(n) algorithm). If the data is not sorted, it gets messier; the trivial algorithm is quadratic, so maybe a sort (O(N lg N)) followed by the linear algorithm is best for that.
You can use dynamically allocated memory to manage arrays. That may be beyond where you've reached in your studies, though.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static int intcmp(const void *pa, const void *pb)
{
int a = *(int *)pa;
int b = *(int *)pb;
if (a > b)
return +1;
else if (a < b)
return -1;
else
return 0;
}
static int compact(int *array, int size)
{
int i;
int last = 0;
assert(size >= 0);
if (size <= 0)
return size;
for (i = 1; i < size; i++)
{
if (array[i] != array[last])
array[++last] = array[i];
}
return(last + 1);
}
static void print(int *array, int size, const char *tag, const char *name)
{
int i;
printf("%s\n", tag);
for (i = 0; i < size; i++)
printf("%s[%d] = %d\n", name, i, array[i]);
}
int main(void)
{
int a[11] = {1,2,3,4,5,11,11,11,11,16,16};
int a_size = sizeof(a) / sizeof(a[0]);
print(a, a_size, "Before", "a");
a_size = compact(a, a_size);
print(a, a_size, "After", "a");
int b[11] = {11,1,11,3,16,2,5,11,4,11,16};
int b_size = sizeof(b) / sizeof(b[0]);
print(b, b_size, "Before", "b");
qsort(b, b_size, sizeof(b[0]), intcmp);
print(b, b_size, "Sorted", "b");
b_size = compact(b, b_size);
print(b, b_size, "After", "b");
return 0;
}
#define arraysize(x) (sizeof(x) / sizeof(x[0])) // put this before main
int main() {
bool duplicate = false;
int a[11] = {1,2,3,4,5,11,11,11,11,16,16}; // doesnt have to be sorted
int b[11];
int index = 0;
for(int i = 0; i < arraysize(a); i++) { // looping through the main array
for(int j = 0; j < index; j++) { // looping through the target array where we know we have data. if we haven't found anything yet, this wont loop
if(a[i] == b[j]) { // if the target array contains the object, no need to continue further.
duplicate = true;
break; // break from this loop
}
}
if(!duplicate) { // if our value wasn't found in 'b' we will add this non-dublicate at index
b[index] = a[i];
index++;
}
duplicate = false; // restart
}
// optional
int c[index]; // index will be the number of objects we have in b
for(int k = 0; k < index; k++) {
c[k] = b[k];
}
}
If you really have to you can create a new array where that is the correct size and copy this into it.
As you can see, C is a very basic (but powerful) language and if you can, use a vector to but your objects in instead (c++'s std::vector perhaps) which can easily increase with your needs.
But as long as you only use small numbers of integers you shouldn't loose to much. If you have big numbers of data, you can always allocate the array on the heap with "malloc()" and pick a smaller size (maybe half the size of the original source array) that you then can increase (using realloc()) as you add more objects to it. There is some downsides reallocating the memory all the time as well but it is a decision you have to make - fast but allocation more data then you need? or slower and having the exact number of elements you need allocated (which you really cant control since malloc() might allocate more data then you need in some cases).
//gcc -Wall q2.cc -o q2 && q2
//Write a program to remove duplicates from a sorted array.
/*
The basic idea of our algorithm is to compare 2 adjacent values and determine if they
are the same. If they are not the same and we weren't already looking previusly at adjacent pairs
that were the same, then we output the value at the current index. The algorithm does everything
in-place and doesn't allocate any new memory. It outputs the unique values into the input array.
*/
#include <stdio.h>
#include <assert.h>
int remove_dups(int *arr, int n)
{
int idx = 0, odx = -1;
bool dup = false;
while (idx < n)
{
if (arr[idx] != arr[idx+1])
{
if (dup)
dup = false;
else
{
arr[++odx] = arr[idx];
}
} else
dup = true;
idx++;
}
return (odx == -1) ? -1 : ++odx;
}
int main(int argc, char *argv[])
{
int a[] = {31,44,44,67,67,99,99,100,101};
int k = remove_dups(a,9);
assert(k == 3);
for (int i = 0;i<k;i++)
printf("%d ",a[i]);
printf("\n\n");
int b[] = {-5,-3,-2,-2,-2,-2,1,3,5,5,18,18};
k = remove_dups(b,12);
assert(k == 4);
for (int i = 0;i<k;i++)
printf("%d ",b[i]);
printf("\n\n");
int c[] = {1,2,3,4,5,6,7,8,9};
k = remove_dups(c,9);
assert(k == 9);
for (int i = 0;i<k;i++)
printf("%d ",c[i]);
return 0;
}
you should create a new array and you should check the array if contains the element you want to insert before insert new element to it.
The question is not clear. Though, if you are trying to remove duplicates, you can use nested 'for' loops and remove all those values which occur more than once.
C does not have a built in data type that supports what you want -- you would need to create your own.
int a[11]={1,2,3,4,5,11,11,11,11,16,16};
As this array is sorted array, you can achieve very easily by following code.
int LengthofArray = 11;
//First elemnt can not be a duplicate so exclude the same and start from i = 1 than 0.
for(int i = 1; i < LengthofArray; i++);
{
if(a[i] == a[i-1])
RemoveArrayElementatIndex(i);
}
//function is used to remove the elements in the same as index passed to remove.
RemoveArrayElementatIndex(int i)
{
int k = 0;
if(i <=0)
return;
k = i;
int j =1; // variable is used to next item(offset) in the array from k.
//Move the next items to the array
//if its last item then the length of the array is updated directly, eg. incase i = 10.
while((k+j) < LengthofArray)
{
if(a[k] == a[k+j])
{
//increment only j , as another duplicate in this array
j = j +1 ;
}
else
{
a[k] = a[k+j];
//increment only k , as offset remains same
k = k + 1;
}
}
//set the new length of the array .
LengthofArray = k;
}
You could utilise qsort from stdlib.h to ensure your array is sorted into ascending order to remove the need for a nested loop.
Note that qsort requires a pointer to a function (int_cmp in this instance), i've included it below.
This function, int_array_unique returns the duplicate free array 'in-place' i.e. it overwrites the original and returns the length of the duplicate free array via the pn pointer
/**
* Return unique version of int array (duplicates removed)
*/
int int_array_unique(int *array, size_t *pn)
{
size_t n = *pn;
/* return err code 1 if a zero length array is passed in */
if (n == 0) return 1;
int i;
/* count the no. of unique array values */
int c=0;
/* sort input array so any duplicate values will be positioned next to each
* other */
qsort(array, n, sizeof(int), int_cmp);
/* size of the unique array is unknown at this point, but the output array
* can be no larger than the input array. Note, the correct length of the
* data is returned via pn */
int *tmp_array = calloc(n, sizeof(int));
tmp_array[c] = array[0];
c++;
for (i=1; i<n; i++) {
/* true if consecutive values are not equal */
if ( array[i] != array[i-1]) {
tmp_array[c] = array[i];
c++;
}
}
memmove(array, tmp_array, n*sizeof(int));
free(tmp_array);
/* set return parameter to length of data (e.g. no. of valid integers not
* actual allocated array length) of the uniqe array */
*pn = c;
return 0;
}
/* qsort int comparison function */
int int_cmp(const void *a, const void *b)
{
const int *ia = (const int *)a; // casting pointer types
const int *ib = (const int *)b;
/* integer comparison: returns negative if b > a
and positive if a > b */
return *ia - *ib;
}
Store the array element with small condition into new array
**just run once 100% will work
!)store the first value into array
II)store the another element check with before stored value..
III)if it exists leave the element--and check next one and store
here the below code run this u will understand better
int main()
{
int a[10],b[10],i,n,j=0,pos=0;
printf("\n enter a n value ");
scanf("%d",&n);
printf("\n enter a array value");
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);//gets the arry value
}
for(i=0;i<n;i++)
{
if(check(a[i],pos,b)==0)//checks array each value its exits or not
{
b[j]=a[i];
j++;
pos++;//count the size of new storing element
}
}
printf("\n after updating array");
for(j=0;j<pos;j++)
{
printf("\n %d",b[j]);
} return 0;
}
int check(int x,int pos,int b[])
{ int m=0,i;
for(i=0;i<pos;i++)//checking the already only stored element
{
if(b[i]==x)
{
m++; //already exists increment the m value
}
}
return m;
}

Resources