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
Related
I used a function to insert new nodes to my singly-linked list but when i print out all the values inside the nodes after insertion, i only get the value of the first node:
// Make list
createList(head, 17);
// Insert to list
for (int x = 9; x > 0; x /= 3)
{
if (!insertToList(head, x))
{
fprintf(stderr, "%s", error);
return 1;
}
}
The function:
bool insertToList(NODE *head, int value)
{
NODE *node = malloc(sizeof(NODE));
if (node == NULL)
return false;
node -> number = value;
node -> next = head;
head = node;
return true;
}
-- Output: 17
When i don't use a function, everything works as expected:
// Make list
createList(head, 17);
// Insert to list
for (int x = 9; x > 0; x /= 3)
{
NODE *node = malloc(sizeof(NODE));
if (node == NULL)
{
fprintf(stderr, "%s", error);
return 1;
}
node -> number = x;
node -> next = head;
head = node;
}
-- Output: 1 3 9 17
Why ?
You are passing the pointer in the function, updating it and not returning it back in which case, the outside function can never know if the head has changed. You must update the head appropriately in the for loop as well.
In the case where you don't use the function, your for loop knows the correct address ofhead every time you insert.
Probably if you return the head pointer and properly update that, it should solve your problem.
I'm implementing circular linked list in C of which the central part is the add2list() function which adds nodes based on the int data field in ascending order. I have 5 different scenarios of when to add the node in the function which makes me think that it's kind of too much. Most of the implementations I've seen in google have 2 or 3 cases. However most of those implementations also use multiple functions for adding a node (separate function for adding a node to the beginning/end of the list). I would appreciate your feedback whether I have cases that can be merged (for example case 2 and 4 are quite similar). I added printList() function if you would like to print the list.
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node * ptr;
typedef struct node {
int data;
ptr next;
}item;
void add2list(ptr *head, int num);
void printList(ptr p);
int main() {
ptr head = NULL;
add2list(&head, 1);
add2list(&head, 2);
add2list(&head, 5);
add2list(&head, 3);
add2list(&head, 0);
add2list(&head, 4);
add2list(&head, -2);
printList(head);
return 0;
}
void add2list(ptr *head, int num) {
ptr p1, p2, t;
t = (ptr) malloc(sizeof(item));
if(!t) {
printf("not enough memory\n");
exit(0);
}
t -> data = num;
p1 = *head;
while(p1 != NULL && p1 -> next != *head && p1 -> data < num) {
p2 = p1;
p1 = p1 -> next;
}
if(!p1) {
//case 1 - if the list is empty
*head = t;
t -> next = *head;
} else if(p1 == *head) {
if(p1 -> data < t -> data) {
//case 2 - if we need to add a node to the end of the list if there was only one node before
(*head) -> next = t;
t -> next = *head;
} else {
//case 3 - if we need to add a node to the beginning of the list
while(p1 -> next != *head) {
p1 = p1 -> next;
}
p1 -> next = t;
t -> next = *head;
*head = t;
}
} else if(p1 -> data < t -> data){
//case 4 - need to add a node at the end of the list if there's more than one node
p1 -> next = t;
t -> next = *head;
} else {
//case 5 - need to add a node in the middle
p2 -> next = t;
t -> next = p1;
}
}
void printList(ptr head) {
ptr tmp;
tmp = head;
while(tmp -> next != head) {
printf("%d ->\n", tmp -> data);
tmp = tmp -> next;
}
printf("%d ->\n", tmp -> data);
}
Here's my attempt (warning, code is untested):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct Node Node;
struct Node {
int data;
Node *next;
};
void add2list(Node **proot, int value) {
Node **pcur;
Node *new;
if (!(new = malloc(sizeof *new))) {
fprintf(stderr, "malloc(%zu): %s\n", sizeof *new, strerror(errno));
exit(EXIT_FAILURE);
}
new->data = value;
if (!*proot) {
// case 1: insert into empty list
new->next = new;
*proot = new;
return;
}
if ((*proot)->data >= value) {
// case 2: insert at beginning of list
pcur = &(*proot)->next;
while (*pcur != *proot) {
pcur = &(*pcur)->next;
}
new->next = *proot;
*proot = *pcur = new;
return;
}
// case 3: insert elsewhere
pcur = &(*proot)->next;
while (*pcur != *proot && (*pcur)->data < value) {
pcur = &(*pcur)->next;
}
new->next = *pcur;
*pcur = new;
}
The function first allocates a new node and sets its data member. This is common to all three cases, as in your code.
Case 1 is insertion into an empty list. This is pretty trivial.
Case 3 is the "normal" case and almost identical to insertion into a non-circular list (the only difference being the test for end-of-list, which involves NULL for a non-circular list). (This subsumes your cases 2, 4, 5.)
Case 2 (insertion at the beginning) is where it gets tricky. This case is special because here we have to update two variables, not just one: The variable in the caller, *proot (because it has to be updated to the new head of the list), as well as the next pointer of the last node in the list (to keep it properly circular). In this case we have an extra loop that walks through the whole list just to find the address of the last next pointer in the list (stored in pcur). At the end we update *proot and *pcur together. (This is your case 3.)
Yes, there are definitely too many cases. You should avoid situations like these one and use a top-down approach whenever possible.
Doing so your code will be cleaner and more maintainable.
Moreover you can reuse functions whenever you need them and if you find a bug inside a function it's a matter of correcting the function to make everything works fine.
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'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.
I have a simple question about removing an element from a linked list. The only difference between what I am trying to accomplish and what I have seen in code online is that I am trying to remove an element, given a position, rather than given the actual element that needs to be removed.
Any help is appreciated.
You can do that, Here is the sample program which can delete any node based on the index you are supplying as an argumenT.
start -> Pointing to the first node
traverse ->pointing to the node which has to be deleted
traverseNext->pointing to the previous of node which has to be deleted.
And the code looks like below.
#include <iostream>
struct myList
{
int data;
struct myList *next;
};
struct myList *start=NULL;
//this method removes a node from the position index
void remove(int index)
{
myList *traverse = start;
myList *traverseNext = NULL;
int i = 1;
while(i<(index-1))
{
traverse = traverse->next;
i++;
}
traverseNext = traverse;
traverse = traverse->next;
if(traverse->next == NULL)
{
delete traverse;
traverseNext->next = NULL;
traverse = NULL;
return;
}
else
{
traverseNext->next = traverse->next;
delete traverse;
traverse = NULL;
return;
}
}
int main(void)
{
myList *node1;
myList *node2;
myList *node3;
node1 = new myList;
node2 = new myList; //Created 3 nodes of type myList
node3 = new myList;
node1->data = 10;
node1->next = node2;
node2->data = 20;
node2->next = node3;
node3->data = 30;
node3->next = NULL;
start = node1; //start is pointing to node1
remove(2); //removing the node 2, so the output will be 10 30
while(start) //iterating through all the nodes from start, since start
{ //is pointing to the first node.
std::cout<<start->data<<" ";
start = start->next;
}
}
Deleting a node in a linked list to which the pointer is given can be done in O(1) time. We don't have to do traversal.
I am assuming that by position you meant the pointer to the node is given:
Lets say node is the element that needs to be removed.
node->data = node->next->data;
Node* temp = node->next;
node->next = node->next->next;
free(temp);
But if the position means the nth element in the list, the only way would be to traverse up to the (n-1)th element and delete the next element by (regular deletion in a linked list):
Node* temp = previous->next;
previous->next = temp->next;
free(temp);
This is all assuming that the linked-list is a pointer based linked-list
This is simple:
1) Locate the Nth item by iterating through the list, additionally using a counter to keep track of which node you're one.
2) Remove that node, as you would any other linked list.
Seek the list until you find the nth element (use a counter), and then update the previous node's next pointer to point to the one after the one you're currently at (effectively removing it). Adjust the previous pointer if you're using them, too.
If you want to remove multiple items you can first iterate over the list and then collect all items that you want to remove to another list. Then simply call 'removeAll' passing in the collected list.
#include <stdio.h>
#include <stdlib.h>
typedef struct element{
int num;
struct element * next;
} element;
void delNth(element **header, int pos){//pos : zero origin
element *prev, *tmp;
int i;
if(header == NULL || *header == NULL || pos < 0) return ;
if(pos == 0){
tmp = (*header)->next;
free(*header);
*header = tmp;
} else {
prev = *header;
tmp = (*header)->next;
for(i=1;i<pos;++i){
prev = tmp;
tmp = tmp->next;
if(tmp == NULL) return ;//or rise error
}
prev->next = tmp->next;
free(tmp);
}
}
void drop(element *header){
if(header){
drop(header->next);
free(header);
}
}
void printList(element *header){
while (header!=NULL){
printf("%d ",header->num);
header=header->next;
}
printf("\n");
}
int main(int argc, char **argv){
int pos = atoi(argv[1]);
element *a;
element *b;
element *c;
a=malloc(sizeof(element));
b=malloc(sizeof(element));
c=malloc(sizeof(element));
a->num=5;
b->num=6;
c->num=7;
a->next=b;
b->next=c;
c->next=NULL;
printList(a);
delNth(&a, pos);
printList(a);
drop(a);
return 0;
}
/* execute result
>a 0
5 6 7
6 7
>a 1
5 6 7
5 7
>a 2
5 6 7
5 6
>a 3
5 6 7
5 6 7
*/