How to compare nodes and not add duplicates in C? - c

I have three nodes as follows.
First node (sNodes) contains: a,b,c,d
Second node (rNodes) contains: c,d,e,f
Third node (nodes) contains: a,b,c,d
I want to add any nodes from second node that is not in the third node. I am having hard time how to do it in C as I am just a beginner. I tried using strcmp method in for loop but couldn't solve it that way. Any help would be really appreciated.
typedef struct {
char emails[(LENGTH*2)+1];
}Node;
Node nodes[GRAPH_SIZE + 1], sNodes[(GRAPH_SIZE + 1) / 2], rNodes[(GRAPH_SIZE + 1)/2];
void addNode(){
int j =0,k = 0, compare, total;
char item[] = {0};
for(j = 0; j <= GRAPH_SIZE/2; j++){
total = 0;
for(k = 0; k <= GRAPH_SIZE/2; k++){
if(strcmp(rNodes[j].emails, nodes[k].emails) != 0){
total = 1;
}else {
total = 0;
}
}
if(total == 1){
strcpy(nodes[i].emails, rNodes[j].emails);
}
}
}

The code snippet you provided is not completed or buggy,
(like unused sNodes, item, compare...and I can't find where is i)
and what you want to do is also unclear for me.
But let me suppose you want to do compare, if not match, do some copy.
Then you should break the for strcmp loop when you find unmatch node,
so you can copy target node, not just set flag.

Related

How can I correctly allocate memory for this MergeSort implementation in C (with the DS I am using)?

My goal here is to perform MergeSort on a dynamic array-like data structure I called a dictionary used to store strings and their relative weights. Sorry if the implementation is dumb, I'm a student and still learning.
Anyway, based on the segfaults I'm getting, I'm incorrectly allocating memory for my structs of type item to be copied over into the temporary lists I'm making. Not sure how to fix this. Code for mergesort and data structure setup is below, any help is appreciated.
/////// DICTIONARY METHODS ////////
typedef struct {
char *item;
int weight;
} item;
typedef struct {
item **wordlist;
//track size of dictionary
int size;
} dict;
//dict constructor
dict* Dict(int count){
//allocate space for dictionary
dict* D = malloc(sizeof(dict));
//allocate space for words
D->wordlist = malloc(sizeof(item*) * count);
//initial size
D->size = 0;
return D;
}
//word constructor
item* Item(char str[]){
//allocate memory for struct
item* W = malloc(sizeof(item));
//allocate memory for string
W->item = malloc(sizeof(char) * strlen(str));
W->weight = 0;
return W;
}
void merge(dict* D, int start, int middle, int stop){
//create ints to track lengths of left and right of array
int leftlen = middle - start + 1;
int rightlen = stop - middle;
//create new temporary dicts to store the two sides of the array
dict* L = Dict(leftlen);
dict* R = Dict(rightlen);
int i, j, k;
//copy elements start through middle into left dict- this gives a segfault
for (int i = 0; i < leftlen; i++){
L->wordlist[i] = malloc(sizeof(item*));
L->wordlist[i] = D->wordlist[start + i];
}
//copy elements middle through end into right dict- this gives a segfault
for (int j = 0; j < rightlen; j++){
R->wordlist[j] = malloc(sizeof(item*));
R->wordlist[j]= D->wordlist[middle + 1 + k];
}
i = 0;
j = 0;
k = leftlen;
while ((i < leftlen) && (j < rightlen)){
if (strcmp(L->wordlist[i]->item, R->wordlist[j]->item) <= 0) {
D->wordlist[k] = L->wordlist[i];
i++;
k++;
}
else{
D->wordlist[k] = R->wordlist[j];
j++;
k++;
}
}
while (i < leftlen){
D->wordlist[k] = L->wordlist[i];
i++;
k++;
}
while (j < rightlen){
D->wordlist[k] = L->wordlist[j];
j++;
k++;
}
}
void mergeSort(dict* D, int start, int stop){
if (start < stop) {
int middle = start + (stop - start) / 2;
mergeSort(D, start, middle);
mergeSort(D, middle + 1, stop);
merge(D, start, middle, stop);
}
I put print statements everywhere and narrowed it down to the mallocs in the section where I copy the dictionary to be sorted into 2 separate dictionaries. Also tried writing that malloc as malloc(sizeof(D->wordlist[start + i])). Is there something else I need to do to be able to copy the item struct into the wordlist of the new struct?
Again, I'm new to this, so cut me some slack :)
There are numerous errors in the code:
In merge() when copying elements to the R list, the wrong (and uninitialized) index variable k is being used instead of j. R->wordlist[j]= D->wordlist[middle + 1 + k]; should be R->wordlist[j]= D->wordlist[middle + 1 + j];.
In merge() before merging the L and R lists back to D, the index variable k for the D list is being initialized to the wrong value. k = leftLen; should be k = start;.
In merge() in the loop that should copy the remaining elements of the "right" list to D, the elements are being copied from the "left" list instead of the "right" list. D->wordlist[k] = L->wordlist[j]; should be D->wordlist[k] = R->wordlist[j];.
In Item(), the malloc() call is not reserving space for the null terminator at the end of the string. W->item = malloc(sizeof(char) * strlen(str)); should be W->item = malloc(sizeof(char) * (strlen(str) + 1)); (and since sizeof(char) is 1 by definition it can be simplified to W->item = malloc(strlen(str) + 1);).
Item() is not copying the string to the allocated memory. Add strcpy(W->item, str);.
There are memory leaks in merge():
L->wordlist[i] = malloc(sizeof(item*)); is not required and can be removed since L->wordlist[i] is changed on the very next line: L->wordlist[i] = D->wordlist[start + i];.
Similarly, R->wordlist[j] = malloc(sizeof(item*)); is not required and can be removed since R->wordlist[j] is changed on the very next line.
L and R memory is created but never destroyed. Add these lines to the end of merge() to free them:
free(L->wordlist);
free(L);
free(R->wordlist);
free(R);
None of the malloc() calls are checked for success.
Allocate it all at once, before the merge sort even starts.
#include <stdlib.h>
#include <string.h>
// Weighted Word --------------------------------------------------------------
//
typedef struct {
char *word;
int weight;
} weighted_word;
// Create a weighted word
//
weighted_word* CreateWeightedWord(const char *str, int weight){
weighted_word* W = malloc(sizeof(weighted_word));
if (W){
W->word = malloc(strlen(str) + 1); // string length + nul terminator
if (W->word)
strcpy( W->word, str);
W->weight = weight;
}
return W;
}
// Free a weighted word
//
weighted_word *FreeWeightedWord(weighted_word *W){
if (W){
if (W->word)
free(W->word);
free(W);
}
return NULL;
}
// Dictionary (of Weighted Words) ---------------------------------------------
//
typedef struct {
weighted_word **wordlist; // this is a pointer to an array of (weighted_word *)s
int size; // current number of elements in use
int capacity; // maximum number of elements available to use
} dict;
// Create a dictionary with a fixed capacity
//
dict* CreateDict(int capacity){
dict* D = malloc(sizeof(dict));
if (D){
D->wordlist = malloc(sizeof(weighted_word*) * capacity);
D->size = 0;
D->capacity = capacity;
}
return D;
}
// Free a dictionary (and all weighted words)
//
dict *FreeDict(dict *D){
if (D){
for (int n = 0; n < D->size; n++)
FreeWeightedWord(D->wordlist[n]);
free(D->wordlist);
free(D);
}
return NULL;
}
// Add a new weighted word to the end of our dictionary
//
void DictAddWord(dict *D, const char *str, int weight){
if (!D) return;
if (D->size == D->capacity) return;
D->wordlist[D->size] = CreateWeightedWord(str, weight);
if (D->wordlist[D->size])
D->size += 1;
}
// Merge Sort the Dictionary --------------------------------------------------
// Merge two partitions of sorted words
// words • the partitioned weighted word list
// start • beginning of left partition
// middle • end of left partition, beginning of right partition
// stop • end of right partition
// buffer • temporary work buffer, at least as big as (middle-start)
//
void MergeWeightedWords(weighted_word **words, int start, int middle, int stop, weighted_word **buffer){
int Lstart = start; int Rstart = middle; // Left partition
int Lstop = middle; int Rstop = stop; // Right partition
int Bindex = 0; // temporary work buffer output index
// while (left partition has elements) AND (right partition has elements)
while ((Lstart < Lstop) && (Rstart < Rstop)){
if (strcmp( words[Rstart]->word, words[Lstart]->word ) < 0)
buffer[Bindex++] = words[Rstart++];
else
buffer[Bindex++] = words[Lstart++];
}
// if (left partition has any remaining elements)
while (Lstart < Lstop)
buffer[Bindex++] = words[Lstart++];
// We don't actually need this. Think about it. Why not?
// // if (right partition has any remaining elements)
// while (Rstart < Rstop)
// buffer[Bindex++] = words[Rstart++];
// Copy merged data from temporary buffer back into source word list
for (int n = 0; n < Bindex; n++)
words[start++] = buffer[n];
}
// Merge Sort an array of weighted words
// words • the array of (weighted_word*)s to sort
// start • index of first element to sort
// stop • index ONE PAST the last element to sort
// buffer • the temporary merge buffer, at least as big as (stop-start+1)/2
//
void MergeSortWeightedWords(weighted_word **words, int start, int stop, weighted_word **buffer){
if (start < stop-1){ // -1 because a singleton array is by definition sorted
int middle = start + (stop - start) / 2;
MergeSortWeightedWords(words, start, middle, buffer);
MergeSortWeightedWords(words, middle, stop, buffer);
MergeWeightedWords(words, start, middle, stop, buffer);
}
}
// Merge Sort a Dictionary
//
void MergeSortDict(dict *D){
if (D){
// We only need to allocate a single temporary work buffer, just once, right here.
dict * Temp = CreateDict(D->size);
if (Temp){
MergeSortWeightedWords(D->wordlist, 0, D->size, Temp->wordlist);
}
FreeDict(Temp);
}
}
// Main program ---------------------------------------------------------------
#include <stdio.h>
int main(int argc, char **argv){
// Command-line arguments --> dictionary
dict *a_dict = CreateDict(argc-1);
for (int n = 1; n < argc; n++)
DictAddWord(a_dict, argv[n], 0);
// Sort the dictionary
MergeSortDict(a_dict);
// Print the weighted words
for (int n = 0; n < a_dict->size; n++)
printf( "%d %s\n", a_dict->wordlist[n]->weight, a_dict->wordlist[n]->word );
// Clean up
FreeDict(a_dict);
}
Notes for you:
Be consistent. You were inconsistent with capitalization and * placement and, oddly, vertical spacing. (You are waaay better than most beginners, though.) I personally hate the Egyptian brace style, but to each his own.
I personally think there are far too many levels of malloc()s in this code too, but I will leave it at this one comment. It works as is.
Strings must be nul-terminated — that is, each string takes strlen() characters plus one for a '\0' character. There is a convenient library function that can copy a string for you too, called strdup(), which AFAIK exists on every system.
Always check that malloc() and friends succeed.
Don’t forget to free everything you allocate. Functions help.
“Item” was a terribly non-descript name, and it overlapped with the meaning of two different things in your code. I renamed them to separate things.
Your dictionary object should be expected to keep track of how many elements it can support. The above code simply refuses to add words after the capacity is filled, but you could easily make it realloc() a larger capacity if the need arises. The point is to prevent invalid array accesses by adding too many elements to a fixed-size array.
Printing the array could probably go in a function.
Notice how I set start as inclusive and stop as exclusive. This is a very C (and C++) way of looking at things, and it is a good one. It will help you with all kinds of algorithms.
Notice also how I split the Merge Sort up into two functions: one that takes a dictionary as argument, and a lower-level one that takes an array of the weighted words as argument that does all the work.
The higher-level merge sort a dictionary allocates all the temporary buffer the merge algorithm needs, just once.
The lower-level merge sort an array of (weighted_word*)s expects that temporary buffer to exist and doesn’t care (or know anything) about the dictionary object.
The merge algorithm likewise doesn't know much. It is simply given all the information it needs.
Right now the merge condition simply compares the weighted-word’s string value. But it doesn’t have to be so simple. For example, you could sort equal elements by weight. Create a function:
int CompareWeightedWords(const weighted_word *a, const weighted_word *b){
int rel = strcmp( a->word, b->word );
if (rel < 0) return -1;
if (rel > 0) return 1;
return a->weight < b->weight ? -1 : a->weight > b->weight;
}
And put it to use in the merge function:
if (CompareWeightedWords( words[Rstart], words[Lstart] ) < 0)
buffer[Bindex++] = words[Rstart++];
else
buffer[Bindex++] = words[Lstart++];
I don’t think I forgot anything.

BFS traversal, same node being accessed twice

I am trying to figure out how to write BFS algorithm in C
and I got this
typedef struct graph {
int numnodes;
int **edges;
} graph;
void bfs(graph *g, int start) {
int visited[g->numnodes], queue[g->numnodes], front =- 1, rear =- 1;
for (int i = 0; i < g->numnodes; i++) {
visited[i] = 0;
}
front++;
queue[++rear] = start;
visited[start] = 1;
while (front <= rear) {
start = queue[front++];
printf("%d\t", start);
for (int i = 0; i < g->numnodes; i++) {
if (g->edges[start][i] == 1 && !visited[i]) {
queue[++rear] = i;
}
}
}
}
for graph looking like graph.
When I print out BFS, it seems to give me
0 1 2 2 3 4
I'm not entirely sure what's wrong here, some help would be appreciated.
I am not sure if BFS is the right term for what you are doing. Your graph is not a tree and with a node having multiple parent nodes it is hard to tell on what level a node really is.
But to make your code work as expected, you just need to fix your missing use of visited array:
if (g->edges[start][i] == 1 && !visited[i]) {
queue[++rear] = i;
visited[i] = 1;
}
Create an actual graph and go through that (e.g. struct for each node, nodes linked via pointers). Right now what you have is an array that you go through item by item if I understand correctly.
You can use an array to store one level of the graph.
0 (first level)
2 1 (second level)
...

Is there a way that I can go up an ADT list? (bubblesorting an ADT list)

(1 mo into learning c) I've been learning about making/using ADT lists and learned the basic functions(used for making ADT lists) like 'count', 'concatenate', 'insert' and etc. And i had an (online course)assignment that required me to bubblesort an ADT list.
So I kinda implemented what I knew about bubblesorting an array to the ADT list. Normally bubblesorting an array looks like this:
void bubbleSort(int arr[], int n) { //int n = numb of elements in the array
int i, j;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++)
if (arr[j] > arr[j+1])
swap(&arr[j], &arr[j+1]); //assuming 'swap(a,b);' swaps the two elements
}
}
So simply i 'just' implemented the modified 'swap' function and that was what i did like the below code. (I couldn't really think of a better method, tried anything what i could do)
typedef struct list { int data; struct list *next; } list;
...//some portion of the code fills/links the nodes
void bubblesort(list* p) {
list* pn = p->next;
for (i = 0; i < SIZE - 1; i++) {
for (j = 0; j < SIZE - j - 1; j++) {
if (p->data > pn->data) // Exception ERR here
datSwap(p, pn); // just swaps (only)the data portion of the two nodes(in ADT lists)
p = pn;
pn = pn->next;
if (pn == NULL)
break;
}
}
}
I'm pretty sure this code isn't pretty and it certainly doesn't work(Exception thrown: read access violation. 'pn' was nullptr.).
When I looked into the problem I thought that in normal situations when using arrays(the 1st code) 'j' used in arrays like 'arr[j+1]' would reset to the starting point(arr[0]) once the for loop was done, but ADT lists not having such 'positions(?)' ended up not resetting the position to the beginning(or to the head) which caused the 'np' to be NULL. So in my theory either the 'p' needed to be reset to the head by reversing up the list(which to my knowledge I don't know how to) or the bubblesort() function needs to be redesigned.
So, my question is...
Can I change the 'pointer of the ADT list'(Am i phrasing this right?) which is at the tail to the head? Image for explanation(idk whether people can understand what i'm saying or not so i included an image)
I know how to progress into a list like the following code which prints a list using 'p = p->data' like below but i want to know if i can do it the opposite way or not
typedef struct list { int data; struct list *next; } list;
...//some portion of the code fills/links the nodes
void printList(list* p) {
int i = 0;
while (p != NULL) {
printf("%d", p->data);
p = p->next;
if (p == NULL)
break;
else
printf(" : "); i++; if (i % 10 == 0 && i > 0) { printf("\n"); }
}
}
if not, how can i change/improve the 'bubblesort' function to sort the lists?
Thank you and if I said something wrong please correct me.
Try to reformulate the inner loop to iterate over p list from the first to "before last" element.
for (list *j = p; j->next; j = j->next)
if (j->data > j->next->data)
datSwap(j, j->next);

C Using insertion sort to sort array of pointers to structs

Im trying to sort, using Insertion Sort, variable-length array of pointers to struct objects.
The sorting criteria is based on the structs distance_to_neighbor attribute.
The problem is it seems that sorted output is semi-sorted.
Here is my data structure for a tree node:
typedef struct tree_
{
struct tree *left;
struct tree *right;
float * info;
float distance_to_neighbor;
} tree;
Here is my Insertion Sort implementation, relevant code snippet (based on https://www.techiedelight.com/insertion-sort-iterative-recursive/):
// perform insertion sort on array of references to structs
void insertion_sort(tree ** arr, int n)
{
// Start from second element (element at index 0
// is already sorted)
tree * pre_value = NULL;
for (int i = 1; i < n; i++)
{
tree * value = *(arr + i);
int j = i;
// Find the index j within the sorted subset arr[0..i-1]
// where element arr[i] belongs
pre_value = *(arr + j - 1);
while (j > 0 && pre_value->distance_to_neighbor > value.distance_to_neighbor)
{
**(arr + j) = **(arr + j - 1);
j--;
}
// Note that subarray arr[j..i-1] is shifted to
// the right by one position i.e. arr[j+1..i]
**(arr + j) = value;
}
}
Code snippet used for debugging before & after sort:
printf ("debug {");
float * info;
float distance = 0;
for (int c = 0; c < k_dimensions; c++)
{
info = (float *) current->info;
if (NULL != info)
{
printf ("%f,", info[c]);
}
else
{
break;
}
}//end for
printf ("} ");
distance = (float) current->distance_to_neighbor;
printf ("distance_to_neighbor=%f\n", distance);
Here are the values before sorting (should be sorted based on distance_to_neighbor) :
debug {-50.000000,-50.000000,-50.000000,} distance_to_neighbor=53.000000
debug {-3.000000,-3.000000,-3.000000,} distance_to_neighbor=6.000000
debug {-2.000000,-2.000000,-2.000000,} distance_to_neighbor=5.000000
debug {-1.000000,-1.000000,-1.000000,} distance_to_neighbor=4.000000
debug {0.000000,0.000000,0.000000,} distance_to_neighbor=3.000000
debug {1.000000,1.000000,1.000000,} distance_to_neighbor=2.000000
debug {2.000000,2.000000,2.000000,} distance_to_neighbor=1.000000
debug {3.000000,3.000000,3.000000,} distance_to_neighbor=0.000000
debug {4.000000,4.000000,4.000000,} distance_to_neighbor=1.000000
debug {5.000000,5.000000,5.000000,} distance_to_neighbor=2.000000
debug {6.000000,6.000000,6.000000,} distance_to_neighbor=3.000000
debug {7.000000,7.000000,7.000000,} distance_to_neighbor=4.000000
debug {8.000000,8.000000,8.000000,} distance_to_neighbor=5.000000
debug {100.000000,100.000000,100.000000,} distance_to_neighbor=97.000000
After sorting (looks sorted descending order then suddenly ascending order!. It should only be ascending order):
{8.000000,8.000000,8.000000,} distance_to_neighbor=5.000000
{7.000000,7.000000,7.000000,} distance_to_neighbor=4.000000
{6.000000,6.000000,6.000000,} distance_to_neighbor=3.000000
{5.000000,5.000000,5.000000,} distance_to_neighbor=2.000000
{4.000000,4.000000,4.000000,} distance_to_neighbor=1.000000
{3.000000,3.000000,3.000000,} distance_to_neighbor=0.000000
{2.000000,2.000000,2.000000,} distance_to_neighbor=1.000000
{1.000000,1.000000,1.000000,} distance_to_neighbor=2.000000
{0.000000,0.000000,0.000000,} distance_to_neighbor=3.000000
{-1.000000,-1.000000,-1.000000,} distance_to_neighbor=4.000000
{-2.000000,-2.000000,-2.000000,} distance_to_neighbor=5.000000
{-3.000000,-3.000000,-3.000000,} distance_to_neighbor=6.000000
{-50.000000,-50.000000,-50.000000,} distance_to_neighbor=53.000000
{100.000000,100.000000,100.000000,} distance_to_neighbor=97.000000
I must keep my function signature the same as void insertion_sort(tree ** arr, int n). How can I fix this sorting bug?
Thanks
You seem to assume that pre-value changes as you change j, but it needs to be re-calculated with each change to j.

randomize linked list in C

Suppose I have a reserved space in memory in a C program, for a linked list containing 1000 items. Each item contains nothing but a reference for next item in the list (last points to the first one). But now they are all set to null, it's just reserved space.
Next I have a rand() function which gives me a random number from 1 to 1000. My question is, is there any simple way how to randomize this list using this function in following way: When I start at first element, I will traverse the whole list, that is, there wont be circles in the list smaller than the whole list.
From your description, you have an array of 1000 nodes all zeroed. For sake of argument, that array is named node_array, and the link field is called next. You also have a pointer called head that can point to one of the nodes.
You can allocate an array of 1000 integers:
enum { NUM_ITEMS = 1000 };
int mapper[NUM_ITEMS];
You can initialize the list so each number appears once:
for (int i = 0; i < NUM_ITEMS; i++)
mapper[i] = i;
You can shuffle the list. (I should really check in Knuth (The Art of Computer Programming) or Bentley (Programming Pearls or More Programming Pearls), but I think the correct algorithms for random shuffling require a different random number generator — one that generates a random number in the range [n..m) — rather than one that just generates a number in the range 0..999).
for (int i = 0; i < NUM_ITEMS; i++)
{
int j = rand();
int t = mapper[j];
mapper[j] = mapper[i];
mapper[i] = t;
}
You can now thread through the array of nodes, linking them in the sequence in the mapper array. Because there were no duplicates in the array, there are no cycles in the list.
head = &node_array[mapper[0]];
for (i = 1; i < NUM_ITEMS; i++)
{
head->next = head;
head = &node_array[mapper[i]];
}
Et voilà...
Solution that does not require extra space. Although note that rand() is called random number of times for each node assignment:
struct Node
{
Node* next;
};
int main()
{
Node nodes[1000];
Node* pNext = NULL;
Node* pHead = NULL;
Node* pTail = NULL;
int i = 0;
// reset .next to NULL
memset(nodes, 0, sizeof(nodes));
srand ( time(NULL) );
pHead = &nodes[ rand() % (1000)];
pTail = pHead;
// need only 999 runs as one node is already assigned
for (i = 0; i < 999; ++i)
{
pTail->next = pTail;
while ((pNext = &nodes[ rand() % (1000)]) && pNext->next);
pTail->next = pNext;
pTail = pNext;
}
// pTail->next = pHead; // uncomment if you need circular list
}

Resources