I'm learning about graph data structure in C and I have represented a graph with the adjacency matrix. So far I created the adjacency matrix which means(in my understanding at least) that I have specified 'between which vertices there will be edges' altough I have not yet created any actual nodes. Now after I have done that I want to actually populate my graph with nodes which contain a data type of my own(say each node in a structure which contains some elements). I have googled a lot but all I found was examples on how to create the adjacency matrix but the explanations would stop there without showing how you actually insert new elements in the graph.
I have written the code to populate the adjacency matrix. I have provided the code below:
#include<stdio.h>
#define V 5
void init(int arr[][V])
{
int i,j;
for(i = 0; i < V; i++)
for(j = 0; j < V; j++)
arr[i][j] = 0;
}
void addEdge(int arr[][V],int src, int dest)
{
arr[src][dest] = 1;
}
void printAdjMatrix(int arr[][V])
{
int i, j;
for(i = 0; i < V; i++)
{
for(j = 0; j < V; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int adjMatrix[V][V];
init(adjMatrix);
addEdge(adjMatrix,0,1);
addEdge(adjMatrix,0,2);
addEdge(adjMatrix,0,3);
addEdge(adjMatrix,1,3);
addEdge(adjMatrix,1,4);
addEdge(adjMatrix,2,3);
addEdge(adjMatrix,3,4);
printAdjMatrix(adjMatrix);
return 0;
}
Now my question is: to populate my graph with new nodes do I have to create another array of size noofnodes x noofnodes and populate it? Is that the correct way to do it or is there any other way? I want to know how the normal and considered correct way to do this is.
Thank you for reading.
I think the easiest way to achieve is this is the following:
map every node (e.g. represented by string) to an integer
store this mapping in a class representing the Graph object
instead of storing an array of ints, store an std::vector<std::vector<int>>
Now when you add something, the process becomes very straightforward:
add the new node to the mapping, its corresponding integer is the size of the adjecency matrix std::vector<std::vector<int>>
add a new std::vector<int> to the adjecency matrix, filled with zeros
updating the adjecency matrix is easy:
public void setAdjMat(const std::string& n0, const std::string& n1, int c){
int i0 = nodeMap[n0];
int i1 = nodeMap[n1];
adjecencyMatrix[i0][i1] = c;
}
The advantages:
adding requires very little effort, and does not need to restructure the entire adjecency matrix
removal can be implemented in two ways; removal from nodeMap and/or removal from adjecencyMatrix
Related
So, I am trying to make a function that transpose some matrix and save it in another matrix.
In the main function I create a matrix called AB (is a 3D matrix) that is size AB[100][100][2] (in this test) and the terms of the type AB[i][j][0] represents the matrix A and AB[i][j][1] represents the matrix B.
The error is occurring in the big test (AB[100][100][2]) when I run the first loop in the function, that look like that:
void transpose(int size, int matrix[][MAX][2], int index, int index_save){
int auxiliar_matrix[MAX][MAX];
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
auxiliar_matrix[i][j] = matrix[j][i][index];
}
save(matrix, index_save, auxiliar_matrix, size) /*this just save the matrix, isnt wrong*/
}
The function just do not work for the big case and the error is in the first 3 lines. Any idea?
How can I use repetitions to check if there aren't any repeated numbers on a n x n matrix?
Using two for's two times wouldn't let me check anything that does not share at least a line or a column
Example: (in the most simplified way possible):
int matrix[n][n];
/*matrix is filled*/
int current, isEqual;
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
current = matrix[i][j];
if (current == matrix[i][j+1])
{
isEqual=1;
}
else
{
isEqual=0;
}
}
}
for (int j=0; j<n; j++)
{
for (int i=0; i<n; i++)
{
current = matrix[i][j];
if (current == matrix[i+1][j])
{
isEqual=1;
}
else
{
isEqual=0;
}
}
}
I can't check numbers that don't share lines or columns.
First, think in a NxM matrix as if it were an array with length [N*M]. The only difference is how you access the elements (two fors instead of one, for example).
Then, a simple algorithm would be to iterate every element (first index), and for each one, iterate every other element (second index) to check if it's the same. It's easier to do with an array; in a matrix it's the same, maybe a bit more verbose and complex. But the algorithm is the same.
As a second phase, after you have implemented the basic algorithm, you can improve its performance starting the second index in the element after the first index. This way, you avoid checking the already seen elements multiple times. This algorithm improvement is slightly harder to do in a matrix, if you iterate it with 2 fors, as it's a bit harder to know what's the "next index" (you have a "compound" index, {i,j}).
One simple way to do this is to insert each number into a data structure that makes it easy to check for duplicates. This is sort of fun to do in C, and although the following is certainly not super efficient or production ready, it's (IMO) a nice little toy:
/* Check if any integer on the input stream is a dup */
#include <stdio.h>
#include <stdlib.h>
struct node { int data; struct node *child[2]; };
static struct node *
new_node(int data)
{
struct node *e = calloc(1, sizeof *e);
if( e == NULL ){
perror("calloc");
exit(EXIT_FAILURE);
}
e->data = data;
return e;
}
/*
* Insert a value into the tree. Return 1 if already present.
* Note that this tree needs to be rebalanced. In a real
* project, we would use existing libraries. For this toy
* it is not worth the work needed to properly rebalance the
* tree.
*/
int
insert(struct node **table, int data)
{
struct node *t = *table;
if( !t ){
*table = new_node(data);
return 0;
}
if( data == t->data ){
return 1;
}
return insert(&t->child[data < t->data], data);
}
int
main(void)
{
int rv, v;
struct node *table = NULL;
while( (rv = scanf("%d", &v)) == 1 ){
if( insert(&table, v) ){
fprintf(stderr, "%d is duplicated\n", v);
return EXIT_FAILURE;
}
}
if( rv != EOF ){
fprintf(stderr, "Invalid input\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The basic approach is to loop through the nxn matrix and keeping a list of the numbers in it along with a count of the number of times each number is found in the nxn matrix.
The following is example source code for a 50 x 50 matrix. To extend this to an n x n matrix is fairly straightforward and I leave that as an exercise for you. You may need to do something such as using malloc() to create an arbitrary sized matrix. There are posts on that sort of thing.
I also do not specify how the data is put into the matrix in the first place. That is also up to you.
This is to just show a brute force approach for determining if there are duplicates in the matrix.
I've also taken the liberty of assuming the matrix elements are int but changing the type to something else should be straightforward. If the matrix elements are something other than a simple data value type such as int, long, etc. then the function findAndCount() will need changing for the equality comparison.
Here are the data structures I'm using.
typedef struct {
int nLength; // number of list elements in use
struct {
int iNumber; // number from an element of the nxn matrix
int iCount; // number of times this element was found in the matrix
} list[50 * 50];
} elementList;
elementList matrixList = {
0,
{0, 0}
};
int matrixThing[50][50];
next we need to loop through the matrix and with each element in the matrix to check if it is in the list. If it's not then add it. It does exist then increment the count.
for (unsigned short i = 0; i < 50; i++) {
for (unsigned short j = 0; j < 50; j++) {
findAndCount (matrixThing[i][j], &matrixList);
}
}
And then we need to define our function we use to check matrix values against the list.
void findAndCount (int matrixElement, elementList *matrixList)
{
for (int i = 0; i < matrixList->nLength; i++) {
if (matrixElement == matrixList->list[i].iNumber) {
matrixList->list[i].iCount++;
return;
}
}
// value not found in the list so we add it and set the initial count
// to one.
// we can then determine if there are any duplicates by checking the
// resulting list once we have processed all matrix elements to see
// if any count is greater than one.
// the initial check will be to see if the value of nLength is equal
// to the number of array elements in the matrix, n time n.
// so a 50 x 50 matrix should result in an nLength of 2500 if each
// element is unique.
matrixList->list[matrixList->nLength].iNumber = matrixElement;
matrixList->list[matrixList->nLength].iCount = 1;
matrixList->nLength++;
return;
}
Search algorithms
The above function, findAndCheck(), is a brute force search algorithm that searches through an unsorted list element by element until either the thing being searched for is found or the end of the list is reached.
If the list is sorted then you can use a binary search algorithm which is much quicker than a linear search. However you then run into the overhead needed to keep the list sorted using a sorting algorithm in order to use a binary search.
If you change the data structure used to store the list of found values to a data structure that maintains values in an ordered sequence, you can also cut down on the overhead of searching though there will also be an overhead of inserting new values into the data structure.
One such data structure is a tree and there are several types and algorithms to build a tree by inserting new items as well as searching a tree. See search tree which describes several different kinds of trees and searches.
So there is a kind of balancing between the effort to do searching versus the effort to add items to the data structure.
Here is an example that checks for duplicate values, the way want to do it.
Looping is slow, and we should use a hash set or a tree instead of using loops.
I assume you are not using C++, because the C++ standard library has build-in algorithms and data structures to do it efficiently.
#include <stdio.h>
/* Search the 'array' with the specified 'size' for the value 'key'
starting from 'offset' and return 1 if the value is found, otherwise 0 */
int find(int key, int* array, int size, int offset) {
for (int x = offset; x < size; ++x)
if (key == array[x])
return 1;
return 0;
}
/* Print duplicate values in a matrix */
int main(int argc, char *argv[]) {
int matrix[3][3] = { 1, 2, 3, 4, 3, 6, 2, 8, 2 };
int size = sizeof(matrix) / sizeof(matrix[0][0]);
int *ptr = (int*)matrix;
for (int x = 0; x < size; ++x) {
/* If we already checked the number, then don't check it again */
if (find(ptr[x], ptr, x, 0))
continue;
/* Check if the number repeats and show it in the console if it does */
if (find(ptr[x], ptr, size, x + 1))
printf("%d\n", ptr[x]);
}
return 0;
}
When you become better at C, you should find or implement a "hash set" or a "red-black tree", and use that instead.
I have the task to paste results of an exam into a static list sorted by highest to lowest.
I initialize a list with the results of the examination and declare a "empty static list".
With the function insertSortArray(...) I want to paste the result into the static list.
I am wondering why the sequence of "noten" is changed after the second printf of "noten".
Can this somebody explain to me?
Thats one point.
The other point ist that I am struggling with algorithm to sort the values.
I know I could copy the values and then program a bubble sort, but is there a way to sort it from the one list to the other?
#include <stdio.h>
void insertSortArray(float *array, float *list, int length)
{
for (int i = 0; i < length; i++)
{
list[i] = array[i];
}
}
int main()
{
float noten[] = { 4.0,
1.3,
1.0,
5.0,
2.3};
float statList[] = { 0 };
int length = sizeof(noten) / sizeof(float);
for (int i = 0; i < length; i++)
{
printf("%f\n", noten[i]);
}
printf("\n%f\n", noten[1]);
printf("\n");
insertSortArray(noten, statList, length);
printf("\n");
for (int i = 0; i < length; i++)
{
printf("%f\t", noten[i]);
printf("%f\n", statList[i]);
}
printf("\n%f\n", noten[1]);
return 0;
}
float statList[] = { 0 }; declares an array with just one element that is initialized to zero. That is too small to copy your static array to.
Use:
float statList[5] = { 0 };
This declares an array of 5 elements of which the first is explicitly initialized to zero (and because not enough initializers are provided to initialize the whole array, all remaining elements are set to zero).
I'm trying to sort a list with Merge Sort algoritm, while keeping it's original indices. I was told that the straight-forward solution was to use an array of indexes (obviously it would be initialized to 0 1 2 3...), and change it inside the merge-sort, as I change the corresponding values in the original array.
The thing is, I can't find a way to make it work, because merge sort doesn't use the indexes of the original array, but rather the indexes of the small arrays that the original array splits into. I guess I'm missing something here... the solution I thought about so far was to treat the indexes array just as the original one, I mean split it into smaller arrays, declare a "helperIndexArray" for the new indexes, call merge with those variables etc... But it seems really unefficient. Isn't there a better way?
I'd appreciate any tips, thanks!
void internalMsort(int array[], int size, int helperArray[], int index[]) {
int left = size / 2, right = size - left;
if (size < 2)
return;
internalMsort(array, left, helperArray);
internalMsort(array + left, right, helperArray);
merge(array, left, array + left, right, helperArray, index);
memCpy(array, helperArray, size);
}
void merge(int a[], int na, int b[], int nb, int c[], index[]) {
int ia, ib, ic;
for(ia = ib = ic = 0; (ia < na) && (ib < nb); ic++)
{
if(a[ia] < b[ib]) {
c[ic] = a[ia];
ia++;
// here I was trying to swap index[ic] with index[ia] but it didn't work
}
else {
c[ic] = b[ib];
ib++;
}
}
for(;ia < na; ia++, ic++){ c[ic] = a[ia]; }
for(;ib < nb; ib++, ic++) { c[ic] = b[ib]; }
}
Define a new type called tuple:
typedef struct
{
int value;
size_t index;
} tuple;
Create an array of tuples, fill it with values, and set the indexes in order, from 0 to size-1.
Then sort the array using the member value, and ignore the member index.
The resulting array will be sorted and its elements will contain the original index in the member index.
It is quite easy (and not specific to mergesort). Just create an array of
struct element_and_index_st {
int element;
size_t original_index; // could be an `int` or an `unsigned`
};
and sort that array, providing a compare function which only compares the element field.
(unless your array is huge, you practically can have the original_index be some int or some unsigned on current desktops or laptops, where ints have 32 bits at least)
But you don't tell why you need the original indexes and how will you give them back to your caller?
Perhaps you just want some stable sort ?
First sort the indices according to the array (compare array[index[ia]] <= array[index[ic]] to sort index[]. Use the helper array as the second array for the indices. Since both the array and the indices are integers, you can use the helper array to sort the array after the indices are sorted:
for(i = 0; i < size; i++)
helperArray = array[index[i]];
for(i = 0; i < size; i++)
array[i] = helperArray[i];
I left out main but basically this should sort 8 elements but when I compile it, it says:
prelab3.c: In function ‘sort’:
prelab3.c:77: error: invalid operands to binary > (have ‘DynamicArray’ and ‘DynamicArray’)
and I'm not sure why exactly, can you not compare things in a struct using pointers?
Code below:
typedef struct Array_
{
int data;
}DynamicArray;
void sort(DynamicArray *v, unsigned int size)
{
int i, j;
int min;
DynamicArray temp;
for (i=0; i<size-1; i++)
{
min = i;
for(j=i+1; j<size; j++)
{
if(*(v+i) > *(v+j))
{
min = j;
}
}
if(min != i)
{
temp = *v;
*v = *(v+min);
*(v+min) = temp;
}
}
}
Comparing structs is meaningless but you could compare the integers inside them. Try this:
(v+i)->data > (v+j)->data
As #David said, you can't compare structs. Your algorithm have some mistakes too:
The j loop is intended to find the minimum item in the range [i,size), so your comparison must be against the minimum so far found:
(v+min)->data > (v+j)->data
I recommend you to use the array notation, in my opinion is clearer:
v[min].data > v[j].data
The last part (after the min != i comparison) is intended to exchange the values between the min and i positions, so your code should look something like:
temp = v[i];
v[i] = v[min];
v[min] = temp;
Finally, keep in mind that struct assignment not always work, for more complex structs than yours, you might need to use field by field assignment, or memcpy().