Converting a array into a max heap - c

I wrote some code to build a max heap in C but I'm getting a very unlikely output. The output goes well with certain inputs but is incorrect with other inputs. How can a fix this?
include<stdio.h>
#include<stdlib.h>
void heapify(int arr[], int n, int i)
{
int temp;
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
// If left child is larger than root
if (l < n && arr[l] > arr[largest])
largest = l;
// If right child is larger than largest so far
if (r < n && arr[r] > arr[largest])
largest = r;
// If largest is not root
if (largest != i) {
{
temp=arr[i];
arr[i]=arr[largest];
arr[largest]=temp;
}
// Recursively heapify the affected sub-tree
heapify(arr, n, largest);
}
}
// Function to build a Max-Heap from the given array
void buildHeap(int arr[], int n)
{
// Index of last non-leaf node
int i;
// Perform reverse level order traversal
// from last non-leaf node and heapify
// each node
for ( i = n/2-1; i >= 0; i--) {
heapify(arr, n, i);
}
}
// A utility function to print the array
// representation of Heap
void printHeap(int arr[], int n)
{
int i;
for (i = 0; i < n; ++i)
printf("%d ",arr[i]);
printf("\n");
}
int main()
{
int arr[]={1,3,5,4,6,13,110,9,8,15,17};
int n=sizeof(arr)/sizeof(arr[0]);
printf("the array is");
printHeap(arr,n);
buildHeap(arr,n);
printf("the heap is");
printHeap(arr,n);
return 0;
}
For an input of 11 67 45 89 34 the output comes out to be 89 67 45 11 34. If we replace 34 with some other number that is smaller than 11, the output makes sense. When I work it on pen and paper I can easily make out that the input of 34 is not touched upon except during the first function call for heapify where i is 1 and left and right is 3 and 4 respectively. How can I fix this?

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.

Min-Max Heap, how to get level of node from given index in O(1)?

The function int IsOnMinLevel(Heap H, int i), returns if the node of index i is on a min level (even level), in constant time
functions provided:
typedef struct heap
{
int *array;
int count;
int capacity;
} *Heap;
Heap CreateHeap(int capacity)
{
Heap h=(Heap) malloc(sizeof(struct heap));
h->count=0;
h->capacity=capacity;
h->array=(int *)malloc(sizeof(int)*h->capacity);
if(! h->array) return NULL;
return h;
}
int Parent(Heap h, int i)
{
if(i<=0 || i>=h->count)
return -1;
return ((i-1)/2);
}
int LeftChild(Heap h, int i)
{
int left = 2*i+1;
if(left>=h->count) return -1;
return left;
}
int RightChild(Heap h, int i)
{
int right = 2*i+2;
if(right>=h->count)
return -1;
return right;
}
void ResizeHeap(Heap *h)
{
int i;
int *array_old = (*h)->array;
(*h)->array=(int *)malloc(sizeof(int)*(*h)->capacity*2);
for(i=0; i<(*h)->capacity; i++)
(*h)->array[i]=array_old[i];
(*h)->capacity *=2;
free(array_old);
}
How do I get level from index? And is there a relation between level and index in a complete binary tree?
Here is the level of the first few nodes:
index: 0 1 2 3 4 5 6 7 8 ...
level: 0 1 1 2 2 2 2 3 3 ...
The pattern is pretty simple: a new level starts at index 2^k-1. So if a node has an index between 2^k-1 included and 2^(k+1)-1 excluded, then it is at level k.
You can derive a formula from this: for a node with index i, find k such that 2^k-1 <= i < 2^(k+1)-1.
Add 1: 2^k <= i+1 < 2^(k+1).
Take the log2: k <= log2(i+1) < k+1.
Since k and k+1 are consecutive integers, this is equivalent to floor(log2(i+1)) = k.
It turns out the function floor(log2(i)) when i is an integer can be very efficiently written, for example like this (taken from here):
int uint64_log2(uint64_t n)
{
#define S(k) if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; }
int i = -(n == 0); S(32); S(16); S(8); S(4); S(2); S(1); return i;
#undef S
}
With this, your function becomes:
int IsOnMinLevel(Heap H, int i)
{
return uint64_log2(i+1) % 2 == 0;
}
The answer Given by #user3386109:
Assuming the heap uses 0-based indexing, and that the root is on level 1, then given index i, the level is floor(log2(i+1)) + 1
The function is simply:
int IsOnMinLevel(Heap H, int i)
{
return ((int)(floor(log2(i+1))) % 2) == 0; //cast to int since log2 gives double
}

No Output - The program doesn't give any output

I am learning data structures. I tried to write a function rotate(arr[], d, n) that rotates arr[] of size n by d elements.
By rotate I mean shifting the elements in an array.
The program doesn't give any error, rather it hangs a bit but it doesn't run.
Here's the code: -
#include <stdio.h>
int rotate(int arr[], int d, int n, int dir)
{
int temp, i;
while (d)
{
if (dir)
{
// for left shift
// First element will always get replaced in a rotation.
temp = arr[0];
for (i = 0; i < n - 1; i++)
// for left shifting the second element next to its original position.
arr[i] = arr[i + 1];
// Putting the temp value in the last position.
arr[n - 1] = temp;
}
else
{
// for right shift
// Last element will always get replaced in a rotation.
temp = arr[n - 1];
for (i = n - 1; i > 0; i--)
// for right shifting the second last element to the last position.
arr[i] = arr[i - 1];
// Putting the temp value in the first position
arr[0] = temp;
}
d--;
}
// Print the shifted array
for (i = 0; i < n; i++)
{
printf("%d, ", arr[i]);
}
}
The program only runs when I don't take inputs from the user.
int main()
{
int n;
int arr[n];
int dir;
int d;
printf("Enter the size of the array: \n");
scanf("%d", &n);
printf("Enter the elements of the array: \n");
for (int i = 1; i <= n; i++)
{
printf("Enter element %d", i);
scanf("%d", &arr[i]);
}
printf("Enter the position: \n");
scanf("%d", &d);
printf("Enter the direction: \n");
// 0: Right Direction and 1: Left Direction
scanf("%d", &dir);
// Before shifting the array
for (int i = 1; i <= n; i++)
{
printf("%d, ", arr[i]);
}
// After shifting the array
rotate(arr, d, n, dir);
return 0;
}
You might want to do int arr[n] after scanf("%d", &n); because n is not initialized when you do int arr[n]. Also array indexing in C starts from 0 so for (int i = 1; i <= n; i++) will be for (int i = 0; i < n; i++).
This is not a proper answer, so do not accept it as the correct answer. It is just a possible implementation for educational purposes.
Here is a way to rotate the array so that each element is moved only once (except that the first element of a "group" is moved via a temporary variable).
The rotation amount is specified as an integer with positive values rotating right and negative values rotating left. It converts this amount into a number in the range 0 to n-1 which is the index of the element that will be copied to element 0. It then divides the array into one or more interleaved groups of the same size such that successive elements in each group are separated by the rotation amount in a circular fashion, and rotates the elements within each group. (The number of groups is the greatest common divisor of n and the rotation amount, and the number of elements in each group is the total number of elements divided by the number of groups.)
#include <limits.h>
#include <stddef.h>
static size_t rotate_modulus(int d, size_t n);
static size_t gcd_size(size_t a, size_t b);
/* Rotate arr[] of length n right by d, or left by -d. */
void rotate(int arr[], int d, size_t n)
{
size_t md = rotate_modulus(d, n); /* Get offset in range 0 to n-1. */
if (md)
{
/* Rotation needed. */
/* Divide into interleaved groups and rotate each group. */
size_t num_groups = gcd_size(n, md);
size_t group_size = n / num_groups;
size_t group;
for (group = 0; group < num_groups; group++)
{
size_t a = group; /* Index of first element in group. */
size_t i;
/* Rotate elements in group. */
int temp = arr[a]; /* Get first element. */
for (i = 0; i < group_size - 1; i++)
{
/* Get index of next element in group. */
size_t b = (a + md);
if (a >= n - md)
{
b -= n; /* Index wraps around. */
}
arr[a] = arr[b]; /* Move an element. */
a = b; /* Advance to next index. */
}
arr[a] = temp; /* Move first element to last element. */
}
}
}
/*
* Get modulus for rotation of n elements.
*
* d is the amount to rotate right; negative d rotates left by -d.
*
* For zero n, the return value is 0.
*
* For non-zero n, the return value is n - s, where s is d plus an
* integer multiple of n such that s is in the range 1 to n, and the
* return value is in the range 0 to n - 1.
*/
static size_t rotate_modulus(int d, size_t n)
{
size_t md;
if (n < 2)
{
/* No rotation needed if n < 2. */
md = 0;
}
else if (d >= 0)
{
/* Non-negative d will rotate right. */
md = d % n;
if (md)
{
md = n - md;
}
}
else
{
/* Negative d will rotate left. */
/* -d would overflow if d == INT_MIN && INT_MIN == -INT_MAX - 1. */
int fix_overflow = (d < -INT_MAX);
md = -(d + fix_overflow) % n;
if (fix_overflow)
{
if (++md == n)
{
md = 0;
}
}
}
return md;
}
/*
* If both a and b are non-zero, return the greatest common divisor of a and b.
* Otherwise, return 0.
*/
static size_t gcd_size(size_t a, size_t b)
{
if (b == 0)
{
a = 0;
}
else
{
do
{
size_t t = b;
b = a % b;
a = t;
}
while (b);
}
return a;
}

transforming max-heap into min-heap with heapfy

I'm trying to heapfy a max-heap i've got into a min-heap. For some reason i'm not getting the result i expect.
i've built my max-heap and the array contents of it are showing as expected:
60 50 30 20 40 10
When trying heapfy the above array and transform it into a min-heap, the desired result is:
10 20 30 60 50 40
However, the result i'm getting is:
10 20 60 50 40 30
here are my functions:
struct _heap
{
int max; //array max
int pos; //current position
int* priority; //array gets initialized after.
};
typedef struct _heap heap_t;
void heapify_min(heap_t* h, int father)
{
int smallest = father;
int left = 2 * father + 1;
int right = 2 * father + 2;
if (left < h->pos && h->priority[left] < h->priority[smallest) {
smallest = left;
}
if (dir < h->pos && h->priority[right] < h->priority[smallest])
smallest = right;
if (smallest != father) {
swap(father,smallest,h->priority);
heapify_min(h,left);
}
}
void swap(int a, int b, int *v)
{
int f = v[a];
v[a] = v[b];
v[b] = f;
}
void build_heap(heap_t* h)
{
int n = h->pos;
int i2 = (n/2) -1;
int i;
for (i = i2;i>=0;i--) {
heapify_min(h,i);
}
}
Any insights would be really helpful.
Check your code against my (below is working code for min_heap).
There are 3 problems :
In heapify_min function when you calling function recursively you should use variable smallest not left.
operators of comparing values in MIN HEAP should be > (greater) instead of < (smaller)
Function build_heap is correct but that should be just very first rearrange of array. And after that first rearrange of array (first creation of max heap) you should swap first and last element in array. After that initial swap you continue with heapify function but every further creation of max heap, swapping values in sub-trees (during recursive calling) and swaping first element with last element is done in cycle until there is only one node left.
Here is code :
void heapify(int arr[], int n, int i)
{
int smallest = i;
int l = 2 * i + 1;
int r = 2 * i + 2;
// If left child is larger than root
if (l < n && arr[l] > arr[smallest])
smallest = l;
// If right child is larger than largest so far
if (r < n && arr[r] > arr[smallest])
smallest = r;
// If largest is not root
if (smallest != i) {
//swap
int backUp = arr[i];
arr[i] = arr[smallest];
arr[smallest] = backUp;
// Recursively call on heapify function
heapify(arr, n, smallest);
}
}
void heapSort(int arr[], int n)
{
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract an element from heap
for (int i = n - 1; i > 0; i--) {
// Swap root node with last node in array (WARNING: last node don't have to be
necessarily smallest one)
int backUp = arr[0];
arr[0] = arr[i];
arr[i] = backUp;
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
/* A utility function to print array of size n */
void printArray(int arr[], int n)
{
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}

C program that uses depth-first search to count the number of distinct graphs represented by an adjacency matrix

The code below uses depth-first search over all elements of an adjacency matrix to count how many graphs are represented in the adjacency matrix.
For some reason this code works only for some test cases but not for others, and I'd like to fix this.
#include <stdio.h>
#include <stdlib.h>
//depth-first search
void dfs(int start, int n, int * visited, int ** family){
int current;
visited[start] = 1;
for(current=0;current<n;++current)
if(visited[current] == 0 && family[start][current] == 1) dfs(current, n, visited, family);
}
//set all visited[i] array integers to zero
void zero(int n, int * visited){
int i;
for(i=0;i<n;++i){
visited[i] = 0;
}
}
int main(){
int ** family;
int * visited;
int ** all_visited;
int n, k;
int i, j, x, y;
int counter = 0;
int familycount = 0;
// n == number of elements
// k == number of lines to be read
scanf("%i %i", &n, &k);
//memory allocation
family = (int**) malloc(sizeof(int*) * n);
for(i=0;i<n;++i){
family[i] = (int*) malloc(sizeof(int) * n);
}
all_visited = (int**) malloc(sizeof(int*) * n);
for(i=0;i<n;++i){
all_visited[i] = (int*) malloc(sizeof(int) * n);
}
visited = (int*) malloc(sizeof(int) * n);
zero(n, visited);
//receive input pairs and build adjacency matrix for the graph
for(i=0;i<k;++i){
scanf("%i %i", &x, &y);
--x;
--y;
family[x][y] = 1;
}
//Perform depth-first search for each element in adjacency matrix.
//If dfs() returns a visited[] array that has never been seen before,
// add +1 to familycount.
for(i=0;i<n;++i){
dfs(i,n,visited,family);
for(j=0;j<n;++j){
all_visited[i][j] = visited[j];
}
for(x=0;x<i;++x){
for(y=0;y<n;++y){
if(all_visited[x][y] == 1 && visited[y] == 1) break;
}
if(y == n) ++counter;
}
if(counter == i ) ++familycount;
zero(n, visited);
counter = 0;
}
printf("%i\n",familycount);
return 0;
}
For instance, if we take the following test case:
9 8
1 2
2 3
3 6
4 3
6 5
7 8
1 4
6 2
First line ( "9 8" ) means we have nine possible elements ( integers ranging from 1 to 9 ) and that eight lines of input will follow below.
Possible means that I may or may not input 9 vertexes but never more than 9. If I don't input a vertex, it's ignored.
All following lines mean "X is related to Y", "X belongs to the same family as Y", or more formally, "X and Y belong to the same graph".
As you can see below, this test case has two families or two graphs, so program output should be "2".
This code is a lot more expensive than the problem you're trying to solve.
This problem is knows as graph connectivity in graph theory and you can solve it via a simple DFS for each node; we'll then use the visited array as a storage of the current DFS exploration.
For any vertex v:
visited[v] = 0 <--> v has not been explorated yet
visited[v] < 0 <--> v has an ongoing exploration but it isn't finished yet
visited[v] > 0 <--> v has finished its exploration
Starting from v, we'll mark every reachable vertex from it with the same ongoing value for counter, and once the DFS returns, we'll simply swap sign of the visited[v] value, meaning its exploration is now over.
To get the number of unconnected graphs, you only need to count how many different values are in the visited array.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
void dfs(int start, int n, int *visited, int **family, int counter) {
if (visited[start] > 0)
return;
else if (visited[start] == 0)
visited[start] = -counter;
for (int i = 0; i < n; i++) {
if (family[start][i] == 1 && visited[i]==0) {
dfs(i, n, visited, family, counter);
}
}
visited[start] = -visited[start];
return;
}
//set all visited[i] array integers to zero
void zero(int n, int * visited) {
int i;
for (i = 0; i<n; ++i) {
visited[i] = 0;
}
}
int main() {
int ** family;
int * visited;
int n, k;
int i, x, y;
int counter = 1;
int familycount = 0;
int last = -1;
// n == number of elements
// k == number of lines to be read
printf("Insert vertex# and edge#\n");
scanf("%i %i", &n, &k);
//memory allocation
family = (int**)malloc(sizeof(int*) * n);
for (i = 0; i<n; ++i) {
family[i] = (int*)malloc(sizeof(int) * n);
}
visited = (int*)malloc(sizeof(int) * n);
zero(n, visited);
//receive input pairs and build adjacency matrix for the graph
printf("Now insert all the edges, once at time\nFor edge (a,b), insert a b and press Enter\n");
for (i = 0; i<k; ++i) {
scanf("%i %i", &x, &y);
--x;
--y;
family[x][y] = 1;
}
zero(n, visited);
//Perform depth-first search for each element in adjacency matrix.
//If dfs() returns a visited[] array that has never been seen before,
// add +1 to familycount.
for (i = 0; i<n; ++i) {
dfs(i,n,visited,family,counter);
counter++;
}
for (i = 0; i < n; i++) {
if (visited[i] != last) {
familycount++;
last = visited[i];
}
}
printf("Graph #: %i\n", familycount);
return 0;
}
Instead of giving 9 8 as first input, you'll need to enter 8 8, meaning 8 vertexes and 8 edges, respectively.
What I don't see in your code, nor in the code of a proposed solutuon, is the counting of the unconnected components. I won't give the algoithm in code, just verbally.
Take a random node to start with and apply dfs to mark its nodes. You now have 1 component.
While there are still unmarked nodes, take the node and apply dfs. Add 1 to the number of components.
If there are no unmarked nodes anymore, you have the number of unconnected components of the graph.

Resources