Every reference I look at to learn about heaps says that the sift_down approach to building heaps is the ideal way, but does this mean that it is still possible to build a heap using sift_up? If so, why is sift_down preferred? I'm trying to get a better understanding of these types of things for an algorithms course I am taking. I'd like to try to implement a build_heap function that uses sift_up, but so far I haven't had any luck, though I have managed to get it to work using sift_down.
Any ideas, suggestions, or references that anyone could share? Here's a few functions I'm struggling with at the moment:
#include <stdio.h>
void bottom_up_heapsort(int*, int);
void heapsort(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 swap(int*, int*);
int heapsize;
int main() {
int A[] = { 7, 12, 1, -2, 0, 15, 4, 11, 9 };
int B[] = { 7, 12, 1, -2, 0, 15, 4, 11, 9 };
int i;
int size = 9;
printf("Unsorted array: \n");
for(i = 0; i < size; i++) {
printf(" %d ", A[i]);
}
heapsort(A, size);
printf("\n");
printf("Sorted array: \n");
for(i = 0; i < size; i++) {
printf(" %d ", A[i]);
}
printf("\n");
printf("----------------------------------\n");
printf("Unsorted array for bottom up: \n");
for(i = 0; i < size; i++) {
printf(" %d ", B[i]);
}
bottom_up_heapsort(B, size);
printf("\n");
printf("Sorted array: \n");
for(i = 0; i < size; i++) {
printf(" %d ", B[i]);
}
printf("\n");
return 0;
}
void bottom_up_heapsort(int* arr, int len) {
int i;
bottom_up_build_max_heap(arr, len);
for(i = len-1; i >= 1; i--) {
sift_up(arr, len);
heapsize--;
swap(&arr[i], &arr[0]);
}
}
void heapsort(int* arr, int len) {
int i;
build_max_heap(arr, len);
for(i = len-1; i >= 1; i--) {
swap(&arr[0], &arr[i]); // move arr[0] to its sorted place
heapsize = heapsize - 1;
sift_down(arr, 0); // repair the heap
}
}
void sift_down(int* arr, int i) {
int l = 2*i, r = 2*i+1;
int largest;
if(l < heapsize && arr[l] > arr[i]) {
largest = l;
}
else {
largest = i;
}
if(r < heapsize && arr[r] > arr[largest]) {
largest = r;
}
if(largest != i) {
swap(&arr[i], &arr[largest]);
sift_down(arr, largest);
}
}
void sift_up(int* arr, int i) {
if(i == 1) return; // at the root
if(arr[i] > arr[i/2]) {
swap(&arr[i], &arr[i/2]);
sift_up(arr, i/2);
}
}
void bottom_up_build_max_heap(int* arr, int len) {
heapsize = 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 swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
You should be able to do
for (int i = 1; i <= n; i++) sift_up(heap, i);
which is equivalent to inserting the elements one by one. The worst-case running time is Theta(n log n), since in the worst case each new element must be sifted all the way to the root. This running time is worse than that of the sift_down heapify, namely, Theta(n). The difference is that sift_down can move the majority of elements only a couple levels down, while sift_up can move the majority of elements log n levels up.
Related
This C code is for deleting all occurrences of an integer in an array. However, when I executed it, there is a problem with displaying the final array, the code doesn't display the rest of the array once it finds the first occurrence.
unsigned int T[10], n, i, j, exist, integerDeleteOccurences;
printf("Array length : ");
scanf("%u", &n);
for(i=0; i<n; i++)
{
printf("T[%u] : ", i);
scanf("%u", &T[i]);
}
for(i=0; i<n; i++)
{
printf("%u | ", T[i]);
}
printf("The number you want to delete its occurences : ");
scanf("%u", &integerDeleteOccurences);
exist = 0;
for (i=0; i<n; i++)
{
if (T[i] == integerDeleteOccurences)
{
j = i;
for (j=i; j<n-1; j++);
{
T[j] = T[j+1];
}
exist = 1;
i--;
n--;
}
}
if (exist == 1)
{
for (i=0; i<n; i++)
{
printf("%u | ", T[i]);
}
}
else if (exist == 0)
{
printf("This number doesn't exist in the array ! \n");
}
It is far to complicated.
size_t removeFromArray(int *arr, size_t size, int val)
{
int *tail = arr;
size_t newSize = size;
if(arr)
{
while(size--)
{
if(*tail == val) { tail++; newSize--;}
else
*arr++ = *tail++;
}
}
return newSize;
}
When working with statically allocated arrays (i.e. you know the maximum possible size), you should handle them by keeping track of their current size.
Here's a function that delete all occurrencies of an element, given an array and its size, and returns the number of deletions:
int deleteAllOccurrencies(int* arr, int size, int el)
{
int occurrencies = 0;
for (int i = 0; i < size; i++)
{
if (arr[i] == el)
{
occurrencies++;
// shift following elements
for (int j = i; j < size; j++)
{
arr[j] = arr[j + 1];
}
}
}
return occurrencies;
}
Edit with alternative solution (suggested by chqrlie)
The above function loops through an array of integers and for each occurrency found, removes the element from the array and shifts the following values by one position. However, that is not much efficient, since the time complexity of that approach is O(n²).
A better solution would be to loop through the array by using two indexes:
i, which is used to check each value in the starting array, and is increased at the end of each loop;
j, which is used to update only the array elements that are different from the one want to delete, and is increased only when that value is different.
This way we are able to get a much more efficient check, reaching a time complexity of O(n):
int deleteAllOccurrencies(int* arr, int size, int el)
{
int occurrencies = 0;
for (int i = 0, j = 0; i < size; i++)
{
if (arr[i] == el)
{
occurrencies++;
}
else
{
arr[j++] = arr[i];
}
}
return occurrencies;
}
Example Usage
#include <stdio.h>
#define MAX_SIZE 10
int deleteAllOccurrencies(int* arr, int size, int el);
void printArray(int* arr, int size);
int main(int argc, char** argv)
{
int array[MAX_SIZE] = { 1, 2, 3, 4, 2, 6, 7, 8, 2, 10 };
int size = MAX_SIZE, res;
printf("Array: ");
printArray(array, size);
res = deleteAllOccurrencies(array, size, 2);
size = MAX_SIZE - res;
printf("\nResult: %d occurrencies found!\n", res);
printf("Resulting array: ");
printArray(array, size);
return 0;
}
int deleteAllOccurrencies(int* arr, int size, int el)
{
int occurrencies = 0;
for (int i = 0, j = 0; i < size; i++)
{
if (arr[i] == el)
{
occurrencies++;
}
else
{
arr[j++] = arr[i];
}
}
return occurrencies;
}
void printArray(int* arr, int size)
{
printf("[ ");
for (int i = 0; i < size; i++)
{
printf("%d", arr[i]);
if (i < size - 1)
printf(", ");
}
printf("]\n");
}
I was requested to write an effecient function with running time n which sort array by the remainder of 3 the program puts the elements which the remainder from dividing in 3 is 0 afterwards the elements that the remainder is 1 and afterwards 2
for example the array {7, 16, 3, 28, 12, 31, 14, 12}
will be sortes that way {12, 3, 12, 28, 16, 31, 7, 14}
so I tries to write an efficient function but it have not cover all cases and does not works for all arrays
int arr[] = { 7,16,3,28,12,31,14,12 };
int rem0 = 0, rem1 = 1, rem2 = 2;
for (int i = 0; i < 8; i++) {
if (arr[i] % 3 == 0)
rem0++;
if (arr[i] % 3 == 1)
rem1++;
if (arr[i] % 3 == 2)
rem2++;
}
int k = rem0, p = 0, m = 0 = 0;
for (int i = 0; i < 8; i++) {
while (rem0-k){
swap(&arr[i], &arr[rem0 - k]);
k--;
}
if (arr[i] % 3 == 1 && rem0+m<7) {
swap(&arr[i], &arr[rem0 + m]);
m++;
}
if (arr[i] % 3 == 1 && rem0 + rem1 + p<7) {
swap(&arr[i], &arr[rem0+rem1 + p]);
p++;
}
}
for (int l = 0;l <8;l++) {
printf("%d\n", arr[l]);
}
}
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
swap switch elements,
Can anyone tells me how can I fix that?
thanks:)
Since you want your function to run in O(n) time, you cannot sort the array completely. All you need to do is put all the elements in 3 buckets.
The following algorithm runs in 2 phases.
//First we count the number of elements in each bucket
int count[3] ={0, 0, 0};
for (int i = 0; i < NUM_ELEMENTS; i++) {
count[arr[i]%3]++;
}
Now that we have the number of elements, we can calculate the offsets of each bucket and create and output array
int output[NUM_ELEMENTS]; // In place bucketing can also be done using swaps
count[2] = count[0] + count[1];
count[1] = count[0];
count[0] = 0;
for (int i = 0; i < NUM_ELEMENTS; i++) {
output[count[arr[i]%3]] = arr[i];
count[arr[i]%3]++;
}
// Finally print the array
for (int i = 0; i < NUM_ELEMENTS; i++) {
printf("%d", output[i]);
}
Demo on Ideone
Here is the solution which you are looking for which uses the same array:
#include <stdio.h>
#define REMINDER 3
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int arr_size = sizeof(arr)/sizeof(arr[0]);
int idx=0;
for (int r=0; r<REMINDER; r++) {
for (int i=0; i<arr_size; i++) {
if (arr[i]%REMINDER==r) {
swap(&arr[idx++], &arr[i]);
}
}
}
for (int i=0; i<arr_size; i++) {
printf("%d ", arr[i]);
}
return 0;
}
Here is a another solution which is just simpler by using other place to store the result:
#include <stdio.h>
#define REMINDER 3
#define ARR_SIZE 10
int main()
{
int arr[ARR_SIZE] = {1,2,3,4,5,6,7,8,9,0};
int arr_sorted[ARR_SIZE];
int idx=0;
for (int r=0; r<REMINDER; r++) {
for (int i=0; i<ARR_SIZE; i++) {
if (arr[i]%REMINDER==r) {
arr_sorted[idx++]=arr[i];
}
}
}
for (int i=0; i<ARR_SIZE; i++) {
printf("%d ", arr_sorted[i]);
}
return 0;
}
Here's a 1-pass in-place Dutch national flag algorithm implementation (thanks to #Virgile who pointed out the algorithm)
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
// Dutch National Flag (see xlinux.nist.gov/dads/HTML/DutchNationalFlag.html)
void sort3dnf(int *a, size_t n) {
int *bot = a;
int *mid = a;
int *top = a + n - 1;
while (mid <= top) {
switch (*mid % 3) {
default: swap(bot++, mid++); break;
case 1: mid++; break;
case 2: swap(mid, top--); break;
}
}
}
See ideone.com/6QXXCN
hey thanks for the advice
sadly we had requested to write the code
without any added array
I will be very glad if you could help me to
solve the issue
thanks :)
hey thanks for the advice sadly we had requested to write the code without any added array I will be very glad if you could help me to solve the issue thanks :)
Here is the answer without adding any extra array:
#include <stdio.h>
#define REMINDER 3
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int arr_size = sizeof(arr)/sizeof(arr[0]);
int idx=0;
for (int r=0; r<REMINDER; r++) {
for (int i=0; i<arr_size; i++) {
if (arr[i]%REMINDER==r) {
swap(&arr[idx++], &arr[i]);
}
}
}
for (int i=0; i<arr_size; i++) {
printf("%d ", arr[i]);
}
return 0;
}
Hi there somehow my bubble sort that is suppose to work does not seem to work.Im not sure where the error is being caused.It is suppose to give me a sorted output list.It is giving me segmentation error and have been trying this for about 1 hr.Heres the code:
#include <stdio.h>
#include <stdlib.h>
#define N 10
void sort(int [], int);
void show(char *, int [], int);
int main(void)
{
int i, j, a[N];
srand(0);
for (j = 1; j <= 5; j++) {
// initialise array (pseudo-randomly)
for (i = 0; i < N; i++) {
a[i] = rand()%100;
}
// display, sort, then re-display
printf("Test #%d\n",j);
show("Sorting", a, N);
sort(a, N);
show("Sorted ", a, N);
}
return 0;
}
// sort array using bubble sort
void sort(int a[], int n)
{
int i, j, nswaps;
for (i = 0; i < n; i--) {
nswaps = 0;
for (j = n-1; j > i; j--) {
if (a[j] < a[j-1]) {
int tmp;
tmp = a[j];
a[j] = a[j-1];
a[j-1] = tmp;
nswaps++;
}
}
if (nswaps == 1) break;
}
}
// display array, preceded by label
void show(char *label, int a[], int n)
{
int i;
printf("%s:", label);
for (i = 0; i < n; i++) {
printf(" %02d", a[i]);
}
printf("\n");
}
Your are not technically sorting here.Instead of this for (i = 0; i < n; i--), try for (i = 0; i < n; i++).This is because you are starting with i=0 so in a FOR loop you need to increment i.
What my program does is that it takes an array of numbers that were read in from a file and sorts them with the selection sort and bubble sort methods. When it's sorted via the bubble sort method, the array lists one number twice in a row. It's also always the second number that gets copied. I checked to see if for whatever reason the number was actually getting passed to the new array twice, but it isn't. I also tried a different input file, same thing happens in the same place.This also cuts off the last number in the list. I don't see anything obvious in my code that's causing that to happen.
The list that the program calls is as follows:
10
50
78
83
92
100
0
4
72
3
19
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int findMin(int arr[], int start, int size);
void printArr(int arr[], int size);
void selectionSort(int arr[], int size);
void bubbleSort(int arr[], int size);
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Syntax Error: ./<exec> <infile>\n");
exit(1);
}
FILE *ifp = NULL;
ifp = fopen(argv[1], "r");
if(ifp == NULL)
{
printf("Could not open %s for reading\n", argv[1]);
exit(1);
}
int counter;
int j = 0;
fscanf(ifp, "%d", &counter);
int array[counter];
int arrB[counter];
for(j = 0; j < counter; ++j)
{
fscanf(ifp, "%d", &array[j]);
}
for(j = 0; j < counter; j++)
{
arrB[j] = array[j];
}
int size = sizeof(array) / sizeof(int);
printf("Before: ");
printArr(array, size);
selectionSort(array, size);
bubbleSort(arrB, size);
fclose(ifp);
return 0;
}
int findMin(int arr[], int start, int size)
{
int i = 0;
int minLoc = start;
int minVal = arr[minLoc];
for ( i = start + 1; i < size; ++i)
{
if (arr[i] < minVal)
{
minVal = arr[i];
minLoc = i;
}
}
return minLoc;
}
void printArr(int arr[], int size)
{
int i = 0;
for(i = 0; i < size; ++i)
printf("%3d ", arr[i]);
printf("\n");
}
void selectionSort(int arr[], int size)
{
int i = 0;
int minLoc = 0;
int tmp = 0;
for(i = 0; i < size; ++i)
{
minLoc = findMin(arr, i, size);
tmp = arr[i];
arr[i] = arr[minLoc];
arr[minLoc] = tmp;
}
printf("** Selection Sort **\n After: ");
printArr(arr, size);
}
void bubbleSort(int arr[], int size)
{
int i = 0;
int j = 0;
int tmp = 0;
for(j = 0; j < size; j++)
{
for(i = 0; i < size; ++i)
{
if(arr[i] > arr[i+1])
{
tmp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = tmp;
}
}
}
printf("** Bubble Sort **\n After: ");
printArr(arr, size);
}
bubbleSort() accesses outside array bounds. Thus undefined behavior (UB).
for(j = 0; j < size; j++) {
for(i = 0; i < size; ++i) {
if(arr[i] > arr[i+1]) { // Here code access outside bounds when i = size - 1
... Code swaps arr[i], arr[i+1];
}
}
}
Instead
for(j = 0; j < size; j++) {
for(i = 1; i < size; ++i) {
if(arr[i-1] > arr[i]) {
... Code swaps arr[i-1], arr[i];
}
}
}
I want to write a program that reads 10 int values from the user and swaps the largest and smallest numbers on the first and second values, then the rest of the numbers should be in the order.
Please check the code and help me what the wrong is.
For instance:
1
9
4
5
6
7
8
2
4
5
New order should be 9 1 4 5 6 7 8 2 4 5
#include <stdio.h>
int main() {
int a[10],i,min,max=0,pos=0;
printf("Please enter 10 int values :\n");
do{
scanf("%d", &a[pos++]);
} while (pos<10);
for (i=0; i<10;i++) {
printf("%i\n",a[i]);
if (max<a[i])
{
max=a[i];
}
if (min>a[i])
{
min=a[i];
}
for (i=0;i<10;i++) {
if (a[i]==max)
a[i]=max;
if (a[i] == min) a[i] = min;
}
printf("The new order is : %d %d %d ", max, min, ...);
return 0;
}
EDIT:
It is the new form
#include <stdio.h>
int main() {
int a[10],i,pos,temp,min = 0,max = 0;
printf("Please enter 10 int values :\n");
do {
scanf("%d", &a[pos++]);
} while (pos < 10);
for ( =1; i<10;i++) {
if (a[i]>a[max])
{
max=i;
}
if (a[i]<a[min])
{
min=i;
}
}
temp=a[max];
a[max]=a[min];
a[min]=temp;
printf("%d %d",a[max],a[min]);
for (i=0;i<10;i++){
if ((i != min) && (i != max)) {
printf("%d ", a[i]);
}
}
printf("\n");
return 0;
}
As others have noted, your code does not properly identify the maximum and minimum values in the array because you are writing min and max back into the array instead of the other way around.
Since you want to swap these values, what you actually want are the indices of the min and max values of the array, and swap those.
It is best to break this code into functions instead of having everything in main. Here is a solution that will do what you want:
#include <stdio.h>
int indexofmax(int *data, int len)
{
int max = 0;
int i;
for(i = 0; i < len; i++)
{
if(data[i]>data[max]) max = i;
}
return max;
}
int indexofmin(int *data, int len)
{
int min = 0;
int i;
for(i = 0; i < len; i++)
{
if(data[i]<data[min]) min = i;
}
return min;
}
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
// user enters in 10 ints...
int max = indexofmax(a, 10);
int min = indexofmin(a, 10);
int i;
swap(&a[min], &a[max]);
for(i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
return 0;
}
This initialization min=0,max=0 is not right.
Instead have min = INT_MAX and max = INT_MIN.
By setting min=0, you would never get the lowest number in the array if it is greater than 0.
Similarly by setting max=0, you would never get the greatest number in the array if it is lower than 0.
You are gaining nothing by this code:
for(i=0;i<10;i++)
{ if(a[i]==max) a[i]=max;
if(a[i]==min) a[i]=min; }
It is evident that this loop
for(i=0;i<10;i++)
{ if(a[i]==max) a[i]=max;
if(a[i]==min) a[i]=min; }
does not make sense.
Moreover variable min is not initialized while variable max is initialized incorrectly.
int a[10],i,min,max=0,pos=0;
For example the array can contain all negative elements. In this case you will get incorrect value of the maximum equal to 0.
And I do not see where the elements are moved to the right to place the maximum and the minimum to the first two positions of the array.
If I have understood correctly then what you need is something like the following. To move the elements you could use standard function memmove declared in header <string.h>. However it seems you are learning loops.
#include <stdio.h>
#define N 10
int main( void )
{
int a[N] = { 4, 5, 9, 6, 7, 1, 8, 2, 4, 5 };
for (size_t i = 0; i < N; i++) printf("%d ", a[i]);
printf("\n");
size_t min = 0;
size_t max = 0;
for (size_t i = 1; i < N; i++)
{
if (a[max] < a[i])
{
max = i;
}
else if (a[i] < a[min])
{
min = i;
}
}
if (max != min)
{
int min_value = a[min];
int max_value = a[max];
size_t j = N;
for (size_t i = N; i != 0; --i)
{
if (i - 1 != min && i - 1 != max)
{
if (i != j)
{
a[j - 1] = a[i - 1];
}
--j;
}
}
a[--j] = min_value;
a[--j] = max_value;
}
for (size_t i = 0; i < N; i++) printf("%d ", a[i]);
printf("\n");
}
The program output is
4 5 9 6 7 1 8 2 4 5
9 1 4 5 6 7 8 2 4 5
You're not actually altering the array.
In the second loop, you say "if the current element is the max, set it to the max". In other words, set it to its current value. Similarly for the min.
What you want is to swap those assignments.
if(a[i]==max) a[i]=min;
if(a[i]==min) a[i]=max;
Also, your initial values for min and max are no good. min is unitialized, so its initial value is undefined. You should initialize min to a very large value, and similarly max should be initialized to a very small (i.e. large negative) value.
A better way to do this would be to keep track of the index of the largest and smallest values. These you can initialize to 0. Then you can check a[i] > a[max] and a[i] < a[min]. Then you print the values at indexes min and max, then loop through the list and print the others.
int i, temp, min=0, max=0;
for (i=1; i<10; i++) {
if (a[i] > a[max]) max = i;
if (a[i] < a[min]) min = i;
}
printf("%d %d ", a[max], a[min]);
for (i=0; i<10; i++) {
if ((i != min) && (i != max)) {
printf("%d ", a[i]);
}
}
printf("\n");
Just keep it nice and simple, like this:
#include <stdio.h>
#include <stdlib.h>
#define MAXNUM 10
int find_biggest(int A[], size_t n);
int find_smallest(int A[], size_t n);
void print_array(int A[], size_t n);
void int_swap(int *a, int *b);
int
main(void) {
int array[MAXNUM], i, smallest, biggest;
printf("Please enter 10 int values:\n");
for (i = 0; i < MAXNUM; i++) {
if (scanf("%d", &array[i]) != 1) {
printf("invalid input\n");
exit(EXIT_FAILURE);
}
}
printf("Before: ");
print_array(array, MAXNUM);
smallest = find_smallest(array, MAXNUM);
biggest = find_biggest(array, MAXNUM);
int_swap(&array[smallest], &array[biggest]);
printf("After: ");
print_array(array, MAXNUM);
return 0;
}
int
find_biggest(int A[], size_t n) {
int biggest, i, idx_loc;
biggest = A[0];
idx_loc = 0;
for (i = 1; i < n; i++) {
if (A[i] > biggest) {
biggest = A[i];
idx_loc = i;
}
}
return idx_loc;
}
int
find_smallest(int A[], size_t n) {
int smallest, i, idx_loc;
smallest = A[0];
idx_loc = 0;
for (i = 1; i < n; i++) {
if (A[i] < smallest) {
smallest = A[i];
idx_loc = i;
}
}
return idx_loc;
}
void
print_array(int A[], size_t n) {
int i;
for (i = 0; i < n; i++) {
printf("%d ", A[i]);
}
printf("\n");
}
void
int_swap(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}