Here is the code for a bucket sort program.
typedef struct node_struct {
double d;
struct node_struct *next;
} node;
I'm using insertion sort to sort the values
void insert(double value, int index, node *B[]) {
node *t;
if (B[index] == NULL) {
t = (node *)malloc(sizeof(node));
t->d = value;
t->next = NULL;
B[index] = t;
} else {
node *p0, *p1;
p0 = B[index];
p1 = p0 -> next;
while(p1 != NULL) {
if (p1 -> d > value) {
break;
}
p1 = p1->next;
p0 = p0->next;
}
t = (node *)malloc(sizeof(node));
t->d = value;
t->next = p1;
p0->next = t;
}
void Bucket_Sort(double A[], int n) {
int j, index;
double B[n];
node *B1;
B1 = (node *)malloc(sizeof(node));
for (int i = 0; i < n; i++) {
B[i] = 0;
}
B1->d = A[0];
B1->next = NULL;
for (int i = 1; i <= n; i++) {
index = (int) floor(n * A[i]);
insert(A[i], index, B1); // This part of the program is where I'm going wrong
}
for (int = 0; i < n; i++) {
printf("%f \n", B[i]);
}
}
When I try calling the insert function, an error occurs saying "expecting struct node ** but the argument is of type struct node *"
But if I call insert function as follows:
insert(A[i],index,&B1);
Then no error is given while compiling but when I run the program it leads to a segmentation fault. Can someone help me with the confusion?
Your insert function is indicating b is an array of pointers to node objects.
But you're not passing in an array of pointers, you're calling it with &b1, which is a pointer to a single node (not an array). And when you uses arrays like that generally you need to pass a count of elements, whereas with pointers to linked list elements you usually use null to indicate the end of the list.
If I were you I would just pass pointers around to deal with everything, and get rid of the [] since you're really not passing things properly for an array. E.g. Rather than passing in an index, just pass a pointer to the object of interest. In more tricky cases you can use ** pointer to pointer but that requires a very solid understand of what you're doing.
Google linked-list example to get ideas how to deal with that properly with pointers. You'll get the idea.
Otherwise be consistent in the way you pass an interpret arrays and pass a count in, and use the count variable in your loops. I'd advise not to try to mix the [] form and * or ** paradigms until you get really comfortable with each separately.
typedef struct node_struct {
double d;
struct node_struct *next;
} node;
void insert(double value, int index, node *b[]) {
node *t;
if (b[index] == NULL) {
t = (node *)malloc(sizeof(node));
t->d = value;
t->next = NULL;
b[index] = t;
} else {
node *p0, *p1;
p0 = b[index];
p1 = p0 -> next;
while (p1 != NULL) {
if (p1 -> d > value) {
break;
}
p1 = p1->next;
p0 = p0->next;
}
t = (node *)calloc(sizeof(node), 1);
t->d = value;
t->next = p1;
p0->next = t;
}
void Bucket_Sort(double a[], int n) {
int j, index;
double b[n];
node *b1 = (node *)calloc(sizeof(node), 1);
a1->d = a[0];
b1->next = NULL;
for (int i = 1; i <= n; i++) {
index = (int) floor(n * a[i]);
insert(a[i], index, b1);
}
for (int = 0; i < n; i++) {
printf("%f \n", b[i]);
}
}
I formatted the program in your question, and went further below. This is more how I see code written in professional code bases and when I do peer code reviews, etc...
Some notes:
• If you use calloc() instead of malloc, and your buffer is automatically zeroed. People usually use bzero(), or memset() to zero arrays rather than a for() loop.
• You can declare an assign a variable such as B1 at the same time and save space/clutter;
• You can declare the variable type inside a for-loop and it will be scoped to just that for-loop. Makes it clear and saves vertical space.
• Don't get too idiosyncratic with your formatting. The programming community is just frustrated by it. There are coding standards at just about any respectable C coding place, and very strict so the code looks clean, readable, easy to understand and maintain, and consistent. If everyone applies their own twist a large coding base becomes an ugly maintenance nightmare.
• Don't add spaces before and after pointers -> no one does it and it's harder to read by experienced programmers. Leave spaces after commas, for the same reason you do when writing - separates items visually better - easier to debug, etc...
• Capitals are used for constants. Camel-case (first letter lower-case and subsequent words first letter capital for example thisIsMyVariable), for variables, or underscores this_is_my_variable, in C. Naming arrays with capital letters is tacky and you almost never see it in professional code.
Related
So first of all i have 2 linked lists one inside the other (like a matrix) and i made a function to delete an entire node. It seems to be freeing but when i print the value t it outputs weird characters.
Here are the structs used inside the list
typedef struct
{
char codigo[LEN_CODIGO + 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
int ocupacao;
} Voo;
typedef struct r
{
char *codReserva;
int nPassangeiros;
struct r *next;
} *ListaReservas;
typedef struct node
{
Voo voo;
ListaReservas nodeReservas; /*this is the head to a list inside this list*/
struct node *next;
} *Node;
in the following function i pretend to delete one node and all the nodes of nodeReservas in it, like deleting an entire column of a matrix.
Node eliminaNode(Node head, char codigo[])
{
Node n, prev;
ListaReservas r, temp;
for (n = head, prev = NULL; n != NULL; prev = n, n = n->next)
{
if (strcmp(n->voo.codigo, codigo) == 0) /*If it's the correct node*/
{
if (n == head)
head = n->next;
else
prev->next = n->next;
/*deletes nodeReservas*/
r = n->nodeReservas;
temp = r;
while(temp != NULL)
{
temp = temp->next;
free(r->codReserva);
free(r);
r= temp;
}
/*deletes the whole node*/
free(n);
}
}
return head;
}
I then use this code to tell me which reservations still exist in a node
for (r=n->nodeReservas; r != NULL; r= r->next)
printf("%s %d\n", r->codReserva, r->nPassangeiros);
For example after adding 3 reservations to lets say Node X and deleting the Node with the reservations with eliminaNode(headofList, X). After recreating the node with that same name 'X' and printing its reservations, instead of getting a empty line i get this:
-725147632
�+���U -725147632
#+���U -725147632
So what is the free() freeing? Is this happening because Lista reservas is a pointer?
free() returns the allocated block to the heap where it may be re-used for subsequent allocation requests. It does not (how could it?) modify the pointer to that block and if you retain such a pointer and re-use it after de-allocation, nothing good will happen.
What you should do is set the pointer to NULL (or a valid pointer such as that of the new next node) immediately after freeing the block so that you retain no reference to the now invalid block:
free(r->codReserva);
r->codReserva = NULL ;
free(r);
r= temp;
}
/*deletes the whole node*/
free(n);
n = NULL ;
Doing that should be a habit in C code. You could make things simpler by creating a function say:
void dealloc( void** ref )
{
free( *ref ) ;
*ref = NULL ;
}
Then instead of calling free( n ) you would call dealloc( &n ) for example.
There are other serious issues with this code. For example the code involving temp is somewhat over-complicated (and any code with a variable temp should raise alarm bells - you have given it scope over the entire function, and used it for more than one purpose - that is not good practice). Consider:
r = n->nodeReservas;
while( r != NULL)
{
ListaReservas new_next= r->next;
free(r->codReserva);
r->codReserva = NULL ;
free(r);
r = new_next;
}
There new_next is very localised (literally "temporary") and named appropriately so it is clear what it is. The next problem is that having assigned the value r you do nothing with it! It is presumably n->nodeReservas that you intended to update not r? Perhaps:
ListaReservas r = n->nodeReservas;
while( r != NULL)
{
ListaReservas new_next= r->next;
free(r->codReserva);
r->codReserva = NULL ;
free(r);
n->nodeReservas = new_next;
}
Note in each case the declaration of temporary variables at point of first use, to give the narrowest scope. Note that r is also temporary. However here it is not truly necessary - it is just a shorthand for n->nodeReservas - personally I'd eradicate it - if only to avoid exactly teh bug described above. Having multiple references to a single allocation is a recipe for bugs. Instead:
while( n->nodeReservas != NULL)
{
ListaReservas new_next = n->nodeReservas->next;
free(n->nodeReservas->codReserva);
n->nodeReservas->codReserva = NULL ;
free(n->nodeReservas);
n->nodeReservas = new_next;
}
I cannot say for sure there are not other bugs - that is just the part that had an obvious "code smell".
I'm working on implementing a binary search tree data structure in C, but I got stuck at the part where you point to the left or right child. I understand that if the value you're inserting is smaller than the root, it goes to the left and to the right if it's larger. I'm just struggling with the double pointers part as shown in the code below. Let's take bs_tree_insert_left for example, I want pos->left_child to point to the left_child in order to place the value given there, but I'm not sure how I would write this.
For context regarding the main function, the numbers in arr[] will be randomly shuffled but I removed that part of the code to keep the post short and compact.
struct node
{
int value;
struct node *left_child;
struct node *right_child;
};
typedef struct node BSTree;
typedef struct node* BSTreePos;
BSTree *bs_tree_make(int value){
// Allocate memory for new node
struct node* origin = (struct node*)malloc(sizeof(struct node));
// Assign data to this node
origin->value = value;
// Initialize left and
// right children as NULL
origin->left_child = NULL;
origin->right_child = NULL;
return (origin);
}
BSTreePos bs_tree_insert_left(int value, BSTreePos pos){
pos->left_child = bs_tree_make(value);
return pos->left_child;
}
void insert_value(int value, BSTreePos pos)
{
if (pos == NULL) return bs_tree_make(value);
if (value < pos->value)
{
pos->left_child = bs_tree_insert_left(value, pos->left_child);
}
else if (value > pos->value)
{
pos->right_child = bs_tree_insert_right(value, pos->right_child);
}
}
int main(void)
{
// Create an array with the values 1, 2, ..., 10 and print out the content.
int n = 10;
int arr[n];
for (int i = 0 ; i < n ; i++) {
arr[i] = i + 1;
}
print_array(n, arr);
BSTree *tree = bs_tree_make(arr[0]);
for (int i = 1 ; i < n ; i++) {
BSTreePos pos = bs_tree_root(tree);
insert_value(arr[i], pos);
}
return 0;
}
You know what, I'm just going to write the correct algorithm that uses the double pointer to maximum effect.
void insert_value(int value, struct node **node)
{
if (*node == NULL) {
*node = malloc(sizeof(struct node));
node[0]->value = value;
node[0]->left_child = NULL;
node[0]->right_child = NULL;
} else if (node[0]->value < value)
insert_value(value, &node[0]->left_child);
else if (node[0]-> value > value)
insert_value(value, &node[0]->right_child);
/* else duplicate value found -- don't insert (from OP's code) */
}
BSTree *tree = NULL;
for (int i = 0 ; i < n ; i++) {
insert_value(arr[i], &tree);
}
node[0]->value is the idiomatic way of accessing a struct through a double pointer.
But let's look at how this works and how much value this gets out of the double pointer. The empty tree is stored as the NULL pointer. This makes initializing the tree and adding a node to the tree the same code. Notice how insert_value takes a double pointer to the tree; this allows it to fill out the root node when adding the first node, or any child node thereof. Thus double pointer which is pointer to pointer is used to update a pointer to a node when we make a new one.
With this algorithm, having a bs_tree_insert_left literally makes no sense. The whole idea is the code that does the insertion doesn't know where it is inserting the node.
Fun fact: the compiler will transform away the recursion for us when compiling with optimizations.
I have this struct:
typedef struct node {
struct node *m_Next;
int id;
} NODE;
And I need to split linked list in half. If it can't be split into two same halves, I want to remove the last one from the bigger list.
Example: The whole list: {1,2,3,4,5}; What I need: A:{1,2} B:{3,4} (The last one is discarded)
I have this function to separate the list:
void split(NODE *src, NODE **p1, NODE **p2) {
int len = get_length(src);
if (len < 2) {
*p1 = NULL;
*p2 = NULL;
return;
}
struct node *current = src;
int c = (len - 1) / 2;
for (int i = 0; i < c; i++) {
current = current->m_Next;
}
*p1 = src;
*p2 = current->m_Next;
current->m_Next = NULL;
}
It works fine with even lists, but when I try to separate something with 7 structs, I have two problems:
a) The last one doesn't point to NULL
b) It shuffles the data somehow (I expect: A:{1,2,3} B:{4,5,6} | I get: A:{1,2,3} B:{5,4,7} for example)
Could anyone please help me splitting the list correctly and adding the even/odd condition?
I already have the function to delete the last struct:
deleteNode(struct TSoldier *firstNode)
I just don't use it currently, because the split function is bugged.
Thanks :)
First of all, it is worth noting that the following code probably causes a memory leak:
if (len < 2) {
*p1 = NULL;
*p2 = NULL;
return;
}
If the number of nodes is equal to 1, then, unless you keep some other reference to this node, the memory will be leaked. You probably have such a reference outside the function, but you are probably discarding this reference and only keeping the values written to p1 and p2, which means the memory is leaked.
Therefore, assuming that you allocated the node with malloc, you will probably want to add the line
free( src );
in order to prevent the memory leak, or use your function deleteNode.
As already pointed out in the other answer, the line
int c = (len - 1) / 2;
is wrong. It should be:
int c = len / 2 - 1;
At the end of your function split, if the number of nodes is odd, you must add code to discard the final node, for example like this:
if ( len % 2 == 1 )
{
current = *p2;
for (int i = 0; i < c; i++) {
current = current->m_Next;
}
free( current->m_Next );
current->m_Next = NULL;
}
To determine the last node of the first half, instead of int c = (len - 1) / 2; you should use this formula that works for even and odd lengths:
int c = len / 2 - 1;
Similarly, to drop the last node if the length is odd and greater than 1:
if (len & 1) {
NODE *node = src;
for (int i = 2; i < len; i++) {
node = node->m_Next;
}
deleteNode(node->m_Next);
node->m_Next = NULL;
}
Here is an alternative approach using the fast and slow scan trick:
void split(NODE *src, NODE **p1, NODE **p2) {
NODE *last = src;
*p1 = *p2 = NULL;
if (src && src->m_Next) {
NODE *slow = src;
NODE *fast = src;
while (fast->m_Next && fast->m_Next->m_Next) {
slow = slow->m_Next;
fast = fast->m_Next->m_Next;
}
*p1 = src;
*p2 = slow->m_Next;
slow->m_Next = NULL;
last = fast->m_Next; // last will be non NULL if length is odd
fast->m_Next = NULL;
}
if (last) {
deleteNode(last); // drop the last node if required
}
}
typedef struct cache_line {
char valid;
mem_addr_t tag;
struct cache_line* next;
} cache_line_t;
typedef cache_line_t* cache_set_t;
typedef cache_set_t* cache_t;
/* The cache we are simulating */
cache_t cache;
void initCache()
{
cache = malloc (S * sizeof(cache_set_t));
for (int i = 0; i < S; i ++ ){
cache[i]= malloc(sizeof(cache_line_t));
cache_line_t *temp = *(cache+i);
temp -> valid = 0;
temp -> tag = 0;
cache_line_t* curr = *(cache+ i );
for (int j = 1; j < E; j++){
curr.next = malloc(sizeof(cache_line_t));
curr = curr.next;
curr.valid=0;
curr.tag=0;
}
curr.next = NULL;
}
}
So my head is swimming trying to remember all the details of pointers and structs and I've been up for a while trying to finish this project. What I'm trying to do here is allocate an array of this structure (a linked list) on the heap and I keep having issues with type mismatches and whatnot (sorry if its messy I keep on trying new things and recompiling). Any help on where I'm going wrong would be appreciated.
Well, the fact the code is terribly obfuscated with abuse of typedef probably goes a long way towards both yours and the compilers problems. I wouldn't have a single typedef in this program myself. It serves no real abstraction here. Here's what I'd suggest (with some omission of error checking):
struct cache_line {
char valid;
mem_addr_t tag;
struct cache_line* next;
};
struct cache_line** cache;
void initCache()
{
cache = malloc (sizeof(*cache) * S);
for (int i = 0; i < S; i ++ ){
struct cache_line** curr_p = &cache[i];
for (int j = 1; j < E; j++){
*curr_p = malloc(sizeof(**curr_p));
(*curr_p)->valid = 0;
(*curr_p)->tag = 0;
(*curr_p)->next = NULL;
curr_p = &(*curr_p)->next;
}
}
}
Key things to note:
I removed all the typedefs. They served no real purpose here but an attempt to save typing. And they did it at the cost of code quality. I also removed it from the struct, since I believe the previous statement applies to it as well.
I allocated memory canonically. By writing malloc(sizeof(*pointer_variable)), you allocate enough memory regardless of what pointer_variable points at. It's somewhat type agnostic.
I traverse the linked list with the "link traversal" idiom. Instead of keeping track of the "node", I keep track of the pointer that is pointing at the node. In the beginning it's cache[i], and at every iteration it becomes the pointer inside the newly allocated node.
I have the following data structure:
struct scoreentry_node {
struct scoreentry_node *next;
int score;
char name[1];
};
typedef struct scoreentry_node *score_entry;
I am trying to create a function that consumes my structure in order and arranges them in ascending order based on the name. I want to modify the input without allocating any memory or freeing anything:
I've tried your suggestions:
void selectionsort(score_entry *a) {
for (; *a != NULL; *a = (*a)->next) {
score_entry *minafteri = a;
// find position of minimal element
for (score_entry j = (*a)->next; j != NULL; j = j->next) {
if (strcmp(j->name, (*minafteri)->name) == -1) {
*minafteri = j;
}
}
// swap minimal element to front
score_entry tmp = *a;
a = minafteri;
*minafteri = tmp;
}
}
I'm testing the above code with the following:
score_entry x = add(8, "bob", (add( 8 , "jill", (add (2, "alfred", NULL)))));
iprint("",x);
selectionsort(&x);
iprint("", x);
clear(x); //Frees the whole list
iprint() prints the score and name fields in the struct. My add function is as follows:
score_entry add(int in, char *n, score_entry en) {
score_entry r = malloc(sizeof(struct scoreentry_node) + strlen(n));
r->score = in;
strcpy(r->name, n);
r->next = en;
return r;
}
I'm getting heap errors and my second print doesn't print the sorted list, it prints nothing. What am I doing wrong, and what can I do to fix it?
besides passing the pointer by address (see comments below) you also need to fix the way you swap elements too
void selectionsort(score_entry *a) {
for (; *a != NULL; *a = (*a)->next)
{
score_entry *minafteri = a;
// find position of minimal element
for (score_entry j = (*a)->next; j != NULL; j = j->next) {
if (strcmp(j->name, (*minafteri)->name) == -1) {
*minafteri = j;
}
}
// swap minimal element to front
score_entry tmp = *a;
a = minafteri; // put the minimal node to current position
tmp->next = (*a)->next ; //fix the links
(*minafteri)->next=tmp; //fix the links
}
}
You have to pass the argument to selectionsort by reference:
void selectionsort(score_entry *a) {
for (; *a != NULL; *a = (*a)->next)
{
score_entry *minafteri = a;
// find position of minimal element
for (score_entry j = (*a)->next; j != NULL; j = j->next) {
if (strcmp(j->name, (*minafteri)->name) == -1) {
*minafteri = j;
}
}
// swap minimal element to front
score_entry tmp = *a;
a = minafteri;
*minafteri = tmp;
}
}
This code is hideous! Not only have you not provided us with all of the necessities to reproduce your problem (we can't compile this!), but you've hidden pointer abstractions behind typedef (also a nightmare for us). Generally speaking, one shouldn't even use linked lists in C anymore let alone sort them...
Nonetheless, there are two answers here.
*minafteri = j; found within your find loop actually modifies your list! Why should your find loop be modifying your list?
Answer: it shouldn't! By instead assigning minafteri = &j->next, you won't be modifying the list with your find loop...
Alternatively, you could perform the swap inside of that loop.
*minafteri = j; would need to swap the following, in this order:
(*minafteri)->next and j->next
*minafteri and j
Do you think that single line of code is capable of performing those two swaps? Well, it gets half way through one of them... and removes a heap of elements from your list in the process!
The following appears to be a faulty attempt swapping elements:
score_entry *minafteri = a; // half of assigning `a` to `a`
/* SNIP!
* Nothing assigns to `minafteri` in this snippet.
* To assign to `minafteri` write something like `minafteri = fubar;` */
score_entry tmp = *a; // half of assigning `*a` to `*a`
a = minafteri; // rest of assigning `a` to `a`
*minafteri = tmp; // rest of assigning `*a` to `*a`
It's really just assigning *a to *a and a to a... Do you think you need to do that?
I'd have thought you'd notice that when you were creating your MCVE... Ohh, wait a minute! Shame on you!
Focus on swapping two nodes within a list as a smaller task. Once you've done that, consider taking on this task.
There are multiple problems in your code:
if (strcmp(j->name, (*minafteri)->name) == -1) { is incorrect: strcmp() does not necessarily return -1 when the first string is less than the second, it can return any negative value.
The way you adjust the links in order to move the lower entry is incorrect: you cannot update the link from the previous node to the one you move to the start. The list is corrupted.
Here is an improved version:
void selectionsort(score_entry *a) {
for (; *a != NULL; a = &(*a)->next) {
// find position of minimal element
score_entry *least = a;
for (score_entry *b = &(*a)->next; *b != NULL; b = &(*b)->next) {
if (strcmp((*b)->name, (*least)->name) < 0) {
least = b;
}
}
if (least != a) {
// swap minimal element to front
score_entry n = *least;
*least = n->next; /* unlink node */
n->next = *a; /* insert node at start */
*a = n;
}
}
}
Here is the Java Implementation of Selection Sort on Linked List:
Time Complexity: O(n^2)
Space Complexity: O(1) - Selection sort is In-Place sorting algorithm
class Solution
{
public ListNode selectionSortList(ListNode head)
{
if(head != null)
{
swap(head, findMinimumNode(head));
selectionSortList(head.next);
}
return head;
}
private void swap(ListNode x, ListNode y)
{
if(x != y)
{
int temp = x.val;
x.val = y.val;
y.val = temp;
}
}
private ListNode findMinimumNode(ListNode head)
{
if(head.next == null)
return head;
ListNode minimumNode = head;
for(ListNode current = head.next; current != null; current = current.next)
{
if(minimumNode.val > current.val)
minimumNode = current;
}
return minimumNode;
}
}