I'm trying to insert nodes into a linked list so the strings contained in the data of each node are sorted alphabetically. If a duplicate word is inputted, the "count" integer of a node is incremented instead. I'm given a makeLnode() function that creates a node, a isGreater() function that compares two strings, and a getLnodeValue() function that returns the string with each node.
lnode insertWord(char * word, lnode head) {
/* Your code to insert a word in the linked list goes here */
lnode temp = makeLnode(word);
if(head == NULL) // if head is null, make head=temp
{
head = temp;
}
else if(isGreater(getLnodeValue(temp),getLnodeValue(head)) == -1) // if temp < head, place temp before head
{
temp->next = head;
head = temp;
}
else
{
lnode curr;
for(curr = head; curr; curr = curr->next) // loop through linked list
{
if(isGreater(getLnodeValue(temp),getLnodeValue(curr)) == 0) // if curr = temp, increment curr
{
curr->count++;
break;
}
else if(isGreater(getLnodeValue(temp),getLnodeValue(curr)) == -1) // if temp < curr, place temp before curr
{
temp->next = curr->next;
curr->next = temp;
break;
}
else if(curr->next == NULL) // if we reach the end of the list and temp > all other nodes, place temp at end of list
{
curr->next = temp;
break;
}
}
}
return head;
}
Only some words are incremented and there are multiples of some words. My output is as follows:
1. - 2 - a
2. - 2 - is
3. - 1 - broadcasting
4. - 1 - emergency
5. - 1 - be
6. - 1 - for
7. - 2 - this
8. - 1 - system
9. - 1 - system
10. - 1 - the
11. - 1 - testing
12. - 1 - seconds
13. - 1 - sixty
14. - 1 - next
15. - 1 - the
16. - 1 - test
17. - 1 - only
18. - 1 - test
19. - 1 - well
You say // if temp < curr, place temp before curr but actually is putting it after:
temp->next = curr->next;
curr->next = temp;
As you see your output is not ordered because of that.
There could be an issue with isGreater too, and there are memory leaks as well, but this should be the first thing to fix.
I don't want to refactor the entire code here since it wasn't the question, feel free to ask if there still a problem.
First, you create a node before even checking if you need to create one : in case the word is present in the list, you don't need that new node.
Then, you should browse the list until you find a greater value or you reach the end. Then you insert your node. No need to test the three cases.
For example :
// check for the following base cases : no node, one node, then :
lnode node = head;
while (node->next && (isGreater(word,getLnodeValue(node->next)) == 1))
{
node = node->next;
}
// check if the next node value is the same as your word and if it is, increment its count.
if (isGreater(word,getLnodeValue(node->next)) == 0)
{
node->next->count++;
}
// Else, create a node with the word and insert the new node after the current node :
else
{
lnode new_node = makeLnode(word);
new_node->next = node->next;
node->next = new_node;
}
This code is not complete and is not really good but you can start with that.
Related
Today, I got a new homework from my teacher.
He told me that this homework might be a sample for final exam.
I tried it for about 2 ~ 3 hours, but I can't get it.
He gave me a simple LinkedList Code. Below in bold is what he wants.
Would you give me some hint about comparing size of Nodes?
Adding Nodes Compared with pre Node and After Node.
2 --> 5 --> 10 --> 20
When I InsertMiddleNode( 7 ), Automatically compare input number(7) with ListNode And locate the right Place
My Goal : 2 --> 5 --> 7(which is my input) --> 10 --> 20
Teacher's code is below:
void insertMiddleNode(linkedList_h* L, listNode* pre, int x) {
listNode* newNode;
newNode = (listNode*)malloc(sizeof(listNode));
newNode->data = x;
if (L == NULL) { // Empty
newNode->link = NULL; // connect
L->head = newNode;
}
else if (pre == NULL) { //
L->head = newNode; // Insert Node at First
}
else {
newNode->link = pre->link; // after pre node
pre->link = newNode;
}
}
Or could it be possible for implementing the same function in main code?
int main() {
linkedList_h* L;
listNode* p;
L = createLinkedList_h();
insertLastNode(L, 1);
insertLastNode(L, 5);
insertLastNode(L. 10);
insertLastNode(L, 20); // 1 - 5 - 10 - 20
insertMiddleNode(L, p, 7) // using p = scanf("%d") with If ( p < pre Node )
printList(L) // 2 - 5 - 7 - 10 - 20
}
void MiddleNode(linkedList_h* L, int x) {
if (L == null)
return
//setp 1: find the previous node
listNode* prev = null;
for (listNode* node = L->head; node && node->data < x; node = node->link)
prev = node;
//step2: be sure prev is not null
if (prev == null)
return;
//or call inserFirstNode(L, x) and return
//step 3: call your teacher's function
insertMiddleNode(L, prev, x);
return;
}
return if L doesn't exist, or you'll crash
the first step is quite simple, loop through the list to find the previous element
but you may end up with null as prev node (either cause the list is empty or x is the smallest), in both case you need to return (or you'll break the list).
Then just call your teacher's function
I have doubly linked list set up using an insertion method which works.
Using this struct:
struct NODE
{
struct NODE *fwd;
struct NODE *bwd;
int value;
};
typedef struct NODE Node;
And this initialization:
void initializeList(Node *rt)
{
rt->fwd = NULL;
rt->bwd = NULL;
rt->value = 0;
}
My main function is:
main()
{
Node root;
int j;
initializeList(&root);
for (j = 0; j < 15; j++)
insertFirst(&root, j);
printf("The list traversed forward \n");
traverseForward(root);
printf("\n");
printf("The list traversed backward \n");
traverseBackward(root);
printf("\n");
printf("After first deletion traverse forward\n");
deleteFirst(&root);
traverseForward(root);
printf("\n");
printf("After first deletion traverse backwards\n");
printf("\n");
traverseBackward(root);
}
My deletefirst function is:
void deleteFirst(Node *rt)
{
Node *newnode = rt;
Node *tmp = NULL;
if (newnode != NULL)
{
if (newnode->fwd != NULL)
{
newnode = newnode->fwd;
tmp = newnode->bwd;
*rt = *newnode;
}
else
tmp = newnode;
}
free(tmp);
}
Insert function:
int insertFirst(Node *rt, int val)
{
Node *node = (Node *)malloc(sizeof(Node));
if (node == NULL) return 0;
node->value = val;
/* For a previously empty list */
if (rt->fwd == NULL)
{
rt->fwd = node;
rt->bwd = node;
node->fwd = NULL;
node->bwd = NULL;
}
/* For a list with at least one node */
else
{
/* previous first node now new node's successor */
rt->fwd->bwd = node;
node->fwd = rt->fwd;
/* no predecessor to the new first node */
node->bwd = NULL;
/* root points to this new first */
rt->fwd = node;
}
return 1;
}
Traverse functions:
void traverseForward(Node root)
{
Node *q = root.fwd;
while (q)
{
printf("%d ", q->value);
q = q->fwd;
}
}
void traverseBackward(Node root)
{
Node *q = root.bwd;
while (q)
{
printf("%d ", q->value);
q = q->bwd;
}
}
The system prints out the list traversed forward
14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
The system prints out the list traversed backward
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
After first deletion forward traversal
13 12 11 10 9 8 7 6 5 4 3 2 1 0
After first deletion backward traversal
(Nothing is printed)
I cant figure out how to adjust the pointers to get it to work.
I believe the problem is because the odd way you are storing the head and tail pointers to the start and end of the list in a root node and then mixing that interchangeably with the actual nodes of the list. This confusion could be eliminated if you just have simple Node *head and Node *tail pointers, but that is only a suggestion.
In your delete function, you set the root node to effectively rt->fwd, which is fine for forwards traversal as rt->fwd->fwd is what is desired, but you forget to consider the value of rt->fwd->bwd which is always pointing at NULL for the first item in the list (as there is nothing technically before this node), not the actual tail of the list which is the desired functionality by that logic.
This obviously causes a problem when you try to use it to iterate backwards as it thinks the list is empty. You should change your deletion code to something like this:
void deleteFirst(Node *rt)
{
if (rt == NULL)
{
return; /* Return if an invalid root was passed in */
}
if (rt->fwd == NULL) {
return; /* Return if the list is already empty */
}
Node *tmpfwd = rt->fwd; /* Store the current "head" */
rt->fwd = rt->fwd->fwd; /* Set the root's head to the current head's next node */
rt->fwd->bwd = NULL; /* Set the new head's previous node to NULL as it is the start of the list */
free(tmpfwd); /* Delete the old "head" */
}
There are a lot of other problems here regarding edge cases and things the comments have mentioned (just the overall design makes this very problematic) but I think this is the problem you are having currently.
I have built a binary tree (huffman tree) using the code below which takes a sorted in ascending order linked list, however when it finishes running it prints the bit-patterns and a few of the nodes that should be in the tree aren't.
The code essentially:
sets parent node to point at two lowest nodes
assigns internal frequency of parent node
points the start of the list to now be at nodes 2 along from where it was (to avoid re-using nodes)
inserts the new parent node into the correct position in the tree
gets the length of the tree
print all nodes left in list
iterates until one node is left (which is the root).
Any ideas as to why its 'losing' nodes along the way?
void build_tree(pqueue *list)
{
node *temp;
node* parent_node;
int min_1, min_2, ind = 0, counter = 0, length = 2, head;
int characters[CHARACTERS];
temp = new_node();
while (length > 1)
{
min_1 = 0;
min_2 = 0;
temp = list->start;
parent_node = new_node();
parent_node->letter = '#';
min_1 = temp->frequency;
parent_node->left = temp;
temp = temp->next;
min_2 = temp->frequency;
parent_node->right = temp;
parent_node->frequency = min_1 + min_2;
list->start = temp->next;
while (ind == 0) /* inserting a node to the correct place */
{
if (temp != NULL && temp->next != NULL)
{
temp = temp->next;
if (temp->frequency >= parent_node->frequency) /* in the middle */
{
parent_node->next = temp->next;
temp->next = parent_node;
ind = 1;
}
else if (temp->next == NULL) /* at the end */
{
temp->next = parent_node;
parent_node -> next = NULL;
ind = 1;
}
}
}
ind = 0;
temp = list->start;
while (temp->next != NULL) /* get number of nodes left to insert into tree */
{
temp = temp->next;
counter++;
printf("%c : %d\n", temp->letter, temp->frequency);
}
printf("----------------------------------------------\n");
length = counter;
counter = 0;
}
printf("Found root with value of: %d\n", temp->frequency);
head = 0;
BitPatterns(temp, characters, head);
temp = list->start;
deallocate(temp, list);
}
void BitPatterns(node* root, int characters[], int head)
{
if (root->left)
{
characters[head] = 0;
BitPatterns(root->left, characters, head +1);
}
if (root->right)
{
characters[head] = 1;
BitPatterns(root->right, characters, head +1);
}
if (isLeaf(root))
{
printf("'%c' : ", root->letter);
GetChars(characters, head);
}
}
void GetChars(int characters[], int n)
{
int i, counter = 0;
for (i = 0; i < n; ++i)
{
printf("%d", characters[i]);
counter++;
}
printf(" (%d * \n", counter);
}
int isLeaf(node* root)
{
return !(root->left) && !(root->right) ;
}
Ok! It was a tough one to debug. But, I think I have found the problem. The problem is with the while loop, where you find the length of the list, that is left for processing. Since the condition in the while loop is temp->next != NULL, so, consider that your List is of size 2, something like this ::
3 --> 4 --> NULL (Numbers represent the sum of frequencies of some nodes)
With list->start pointing to 3. And you will measure the length of this list to 1 and not 2, because you are checking temp->next != NULL.
Because of this you miss a crucial second node of the list, and you run BitPatterns() only on the first node, and you miss a few nodes.
A possible solution to this would be to insert a while loop at the beginning of the function to measure the length for once, and that could be decremented by 1 in every consecutive iteration of the while loop, where you combine two nodes, since you are removing two nodes and adding one node to the list always, you only have to decrement the length by 1. This would also save a lot of extra computation that you do at the end of the list for computing the length of the list everytime.
Something like this ::
temp = list->start;
while(temp != NULL) {
length++;
temp = temp->next;
}
EDIT ::
Moreover, there's another logical bug that I see in your code ::
Consider that the initial list is this ::
1 --> 2 --> 4 --> 5 --> NULL
You combine the first two nodes, let that node be called A (with freq = 3) for the moment and list_start points to 4. So, when you insert the node in the list looks something like this ::
4 --> A --> 5 --> NULL
Though the list, shall look something like this ::
A --> 4 --> 5
This, does not affect the functioning of the code, but might lead to some un-optimized huffman code results.
I have created a linked list of 5 nodes of type:
typedef struct node
{
int i;
struct node* link;
}node;
node* head = NULL;
When printing out, this gives:
4 3 2 1 0
The head pointer is set to point at 4. I have then written a function to bubble sort the linked list as follows:
void sort(void)
{
node* cur = head;
node* next = cur->link;
node* prev = NULL;
while(cur->i > next->i)
{
printf("cur is greater than next\n");
while(prev != head)
{
cur->link = next->link;
next->link = cur;
head = next;
next = cur->link;
prev = head;
}
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
printf("second while loop exited\n");
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
printf("%d", ptr->i);
}
cur = head;
next = cur->link;
}
}
There are various printf statements to check that the program is working. What I find is that after the first run-through, 4 is successfully bubbled up as follows:
3 2 1 0 4
However, after re-setting the cur pointer to 3 and next to 2, the next run-through provides the following:
2 1 0 4 3
Ultimately, we finish with
0 4 3 2 1
So as can be seen "3", "2" and "1" are being bubbled up too far. I have tried various conditonals in place of the third while loop to correct this but in the majority of cases this leads to seg faults. Of course, the other thing here is that my logic could be completely wrong and there may be a better way to implement this. Could you get away with just swapping the contents of nodes and not pointers themselves? Any help would be much appreciated. Thanks in advance
Ordinary bubble-sort implementations for sorting arrays make use of the direct addressing and a known size of the array: they naturally use indices, that is ordinal numbers of items, so they can easily shrink the area sorted as the work progresses, because they know how many items are already on their final places.
A linked list is processed purely sequentially, so it doesn't allow such simple optimization without adding artificial 'index', incremented along the list iteration. That's why it's easiest to iterate always through the whole list and terminate when no more items were swapped, hence the list is sorted:
void sort(void)
{
int swapped = 1;
while(swapped)
{
node **prev = &head, *curr, *next;
swapped = 0;
for(curr = head; curr; prev = & curr->link, curr = curr->link)
{
next = curr->link;
if(next && curr->i > next->i)
{
curr->link = next->link;
next->link = curr;
*prev = next;
swapped = 1;
}
}
}
}
EDIT – some explanations in reply to questions in Matthew2015 comments.
Logical conditions in C expect a numeric or pointer expression which are considered 'true' if they are different from zero or different from NULL, respectively. That means while(swapped) is essentially equivalent to while(swapped != 0) and next && ... is equivalent to next != NULL && .... The condition in while(swapped != 0) means the loop will terminate when some execution of internal for does not set swapped to 1, which happens when no item in the list is greater than its successor – that is, when the list is sorted.
The for loop condition expression is curr alone, equivalent to curr != NULL. That makes the for loop iterate along the list until there is no 'current' node.
The node **prev variable points to a pointer, which points to the current node. When the 'current' and the 'next' node need to be swapped, then the 'previous' link should no longer point to the 'current' node but to the 'next' node instead. Of course one might keep the pointer to the 'previous node' and assign a new value to the (previous node)->link — but that would not work in case of the first node in a list, which has no 'previous node' but is pointed to by the head variable. One must use additional condition to verify if the current node is the first node to resolve this inconsistency. Having a pointer to pointer, which originally points to head and then to 'previous node'.link makes the whole code much simpler, shorter and also a bit faster.
I would look at the third while
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
Here you're always moving elements without testing whether they have to be moved - i.e. cur->i > next->i.
By the way, if it's guard is true, the second while gets executed only once and so it's the same as an if so I would use an if, at least for clarity reasons.
Related to my previous post Editing a node in a Linked list. I've done the following steps in editing the node:
Edit target node data
Remove target node
Re-insert target node
THE PROBLEM IS THAT I CANNOT RE-INSERT IT AT THE TOP OF THE NODE as follows....
std1 90 -> std 2 50 -> std3 20 -> NULL
I edited std3 to 100. The result will be like this
std2 50 -> std3 20 -> NULL
In short, i cannot put it back on the top node. Re-inserting anywhere other than the top node works fine.
You'll have an issue if the head node is a 97%, and you pass a node with a 97%. You need to say
while (curr_std != NULL && to_add->grade <= curr_std->grade){
You'll also have an issue if the student you're editing is the first node, because this:
while((cur != NULL) && (strcmp(cur->name,temp) != 0)){
will evaluate to true, and
prev = cur;
will never get called, leaving prev = null. Then when you get to
prev->next = cur->next;
you have a null reference. You need to explicitly test for adding to the head node; it's its own special case.
scanf("%d", &(cur->grade));
if (prev == null) { // you matched the head
head = cur->next;
}
else {
prev->next = cur->next;
}
EDIT
When you add to the head, in your code, you haven't set the head to point to your new node. You're returning the old head, which now points to the second node in the list. Try:
while (curr_std != NULL && to_add->grade < curr_std->grade){
prev_std = curr_std;
curr_std = curr_std->next;
}
// if you're adding to the head, you didn't go into the above loop
// curr_std is still pointing to head in this case
if (curr_std == head) {
head = to_add
}
else {
prev_std->next = to_add;
}
to_add->next = curr_std;
return head;