Linked List Insertion & Selection - c

I define a linked list in the same way as it is commonly used, i.e. with a data part and a
self referencing pointer. My logic of insertion is as follows:
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node *));
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
i) Is this logic correct?
ii) a) I possibly get a run-time error, when I insert two nodes (in one system) or three nodes(in another).
b) The nodes are inserted in the correct order, every time I insert a node.
Is the run-time error as a result of this code...???

struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node));// You dont need * here
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
tempPtr = start; // you missed this.
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}

disregard the answer as it is c++, the original question was tagged c++
The original code, once the small issues are solved (actual allocation of the node, setting the value, definition of the temporary pointer to help walk the list) should work. But there are other approaches that you can take to simplify the code (well, not that it is hugely complex), which basically imply finding the point of insertion before creation first then creating the new element:
Node** insertPoint = &start;
while (*insertionPoint)
insertionPoint = &((*insertionPoint)->next);
*insertionPoint = new Node(value);
Use a pointer to pointer to walk through the list, initialized with the address of the head pointer move it until it refers to the Node* where the new element will be appended (note, appended, not inserted). Then create the new node in that position. This assumes that the Node constructor takes care of copying the value and initializing the next pointer.
Alternatively you can write this recursively and let the compiler perform the tail optimization for you (it might be a bit simpler to read, some people find recursion simpler, some don't):
void append( Node*& tail, Value value ) {
if ( tail==NULL )
list = new Node(value);
else
append( list->next, value );
}
Calling code:
append( start, 100 ); // assuming nits contained in the list
In this case, instead of a double pointer we can use a reference to the pointer, as we don't need to modify it

struct node *newPtr, **hnd;
newPtr = malloc(sizeof *newPtr);
if (!newPtr) barf();
scanf("%d", &newPtr->data);
newPtr->nextPtr = NULL;
for(hnd = &start; *hnd; hnd = &(*hnd)->next) {;}
*hnd = newPtr;

Related

This function returns a list that contains the values that appear in list "A" at positions given in "pos_list"

-If A list has integer data such as: 1->2->3->4->5->6
-And pos_list has integer data such as: 4->0->5
-Then this function should return a New List hat contains the values that appear in list A at positions given in pos_list
such that New List= 5->1->6
I am implementing deep copy to make new List.
I am trying to use a loop that iterates according to the data of pos_list. Inside this loop, node of A will move to position of pos_list data. In this time i will copy the node A in new list to make another list.
Say for first case, pos_list has data 4, so the loop will run 4 times until the node of list A points to its fourth position. Inside this loop i will copy the data of list A in a new loop.
I need a guidance to solve this problem.
struct node * sublist(struct node * A, struct node * pos_list) {
struct node* newList=NULL;
struct node * curr;
int i=0;
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data.
struct node* newList = (struct node *) malloc(sizeof (struct node));
for(int i=0;i<=pos_list->data;i++){ //counter for pos_list as it will be (3 then 0,6 and 4)
if(i==pos_list->data){ //At the time when i == pos_list->data(3 or 0 or 6..)
newList->data = A->data; //Putting value of list A data in new list.
newList = newList->next; //Linking
printf("%d\t", newList->data); //Just for log
}
A=A->next; //Going to next position on A
}
pos_list=pos_list->next; //Going to next position on B
}
return newList ;
}
If A list is : 1->2->3->4->5->6
And pos_list is: 4->0->5
I expect the output is new list as 5->1->6
Your code has several problems:
You should start your traversal with pos_list, not with pos_list->next. The node pointed to by the head pointer is part of the list. Further, if pos_list == NULL, pos_list->next will lead to undefined behaviour.
The outer definition of int i isn't useful. Delete it.
Don't iterate through A by means of the position. If the position isn't valid, you will walk beyond the end of the list, get null pointers and invoke undefined behaviour. Lists should be iterated by list nodes accessed from the previous nodes' next pointers. (It is, of course, the caller's resposibility to provide valid positions, but your program should handle invalid input gracefully.)
Create the new node only when you have found a valid position. Otherwise you create a node that is never inserted and thus leak memory.
Here: newList = newList->next, newList->next isn't initialized. Remember that malloc gives you a chunk of uninitialized data.
You try to make newList point to the end of the newly created list, so that appending new nodes ist fast. That's a good idea, but if you return that pointer, you'll get a list that consists only of one element. (You'll also no loger be able to access any previously created nodes in that list.)
Here's an implementation that should work:
struct node *sublist(struct node *A, struct node *pos_list)
{
struct node *newHead = NULL;
struct node *newTail = NULL;
struct node *pos = pos_list;
while (pos) {
struct node *a = A;
int i = 0;
while (a) {
if (i == pos->data) {
struct node *node = malloc(sizeof(*node));
if (newHead == NULL) newHead = node;
if (newTail) newTail->next = node;
node->data = a->data;
node->next = NULL;
newTail = node;
break;
}
a = a->next;
i++;
}
pos = pos->next;
}
return newHead;
}
The question does not condone using a "struct" to implement the solution.
If it does, I am mistaken but if it does not, isn't it an overkill, when something akin to the following can be implemented....
#include <stdio.h>
#define CREATE_ARRAY(n) int result[n]
void main() {
int data[] = {1,2,3,4,5,6};
int pos[] = {4,0,5};
int i;
CREATE_ARRAY(sizeof(pos)/sizeof(int));
for(i = 0; i < sizeof(pos)/sizeof(int);++i)
result[i] = data[pos[i]];
/*
To print the values stored in result
for(i = 0;i < sizeof(result)/sizeof(int); ++i)
printf("%d ",result[i]);
putchar('\n');
}
*/
For starters the function sublist should be declared like
struct node * sublist( const struct node *A, const struct node *pos_list );
because neither the list A nor the list pos_list are changed in the function. Otherwise the declaration of the function confuses readers of the code.
It is a bad idea that the list pos_list contains a dummy node as it is wrote in the comment to this statement
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data
Neither dummy node should be in the list.
In this inner loop
for(int i=0;i<=pos_list->data;i++){
there is not used the dummy node of the list. Moreover the pos_list is traversed in the two loops: the outer loop and the inner loop
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data.
struct node* newList = (struct node *) malloc(sizeof (struct node));
for(int i=0;i<=pos_list->data;i++){
Within the loops the value of the variable newList is changed
newList = newList->next;
So as a result the function always returns some indeterminate value instead of the head of the newly created list. The value is indeterminate because the data member next of a new created node is not initialized.
newList->data = A->data; //Putting value of list A data in new list.
newList = newList->next;
The function can be defined the following way
struct node * sublist( const struct node *A, const struct node *pos_list )
{
struct node *newList = NULL;
struct node **current = &newList;
for ( ; pos_list != NULL; pos_list = pos_list->next )
{
const struct node *target = A;
for ( int index = pos_list->data; index != 0 && target != NULL; --index )
{
target = target->next;
}
if ( target != NULL )
{
*current = malloc( sizeof( struct node ) );
( *current )->data = target->data;
( *current )->next = NULL;
current = &( *current )->next;
}
}
return newList;
}

When adding first node to linked list in hashmap, why must the new node be assigned directly to the indexed pointer?

Here is my implementation of a hashmap in c and its initialization and insert code.
In the hashmap_t structure, I use an array of pointers (table) to nodes which contain the key/value pairs. In hashmap_init, I allocate the desired amount of nodes and loop through the array setting each pointer to NULL.
What I'm confused about is in the hashmap_put function. I find the index of which list the key should be inserted in and that first pointer is referenced by hm->table[i]. For clarity, I want to make sure it's obvious that hm->table[i] is the start of the list so I assign it to hashnode_t *head.
So when inserting the first node (head == NULL), I originally used head = new_node, but none of my inserts worked. It only works when I use hm->table[i] = new_node.
I don't understand why that's the case. head points to the same thing so why does setting head equal to the new_node not work? I'm also confused later in the function when last->next = new_node does work. Last is a pointer just like head but it works there.
Thanks for any clarification.
typedef struct hashnode {
char key[128];
char val[128];
struct hashnode *next;
} hashnode_t;
typedef struct {
int item_count;
int table_size;
hashnode_t **table;
} hashmap_t;
void hashmap_init(hashmap_t *hm, int table_size) {
hm->table_size = table_size;
hm->item_count = 0;
hm->table = malloc(table_size * sizeof(hashnode_t));
for (int i = 0; i < table_size; i++) { // loop through array of pointers to nodes
hm->table[i] = NULL;
}
}
int hashmap_put(hashmap_t *hm, char key[], char val[]) {
hashnode_t *new_node = malloc(sizeof(hashnode_t)); // allocate new node
strcpy(new_node->key, key);
strcpy(new_node->val, val);
new_node->next = NULL;
int i = hashcode(key) % hm->table_size; // index of list hashed to
hashnode_t *head = hm->table[i];
hashnode_t *cur = head;
hashnode_t *last;
if (!head) { // list is empty
new_node->next = head;
hm->table[i] = new_node;
//why does head = new_node not work?
hm->item_count += 1;
return 1;
}
while (cur) { // loop through nodes
if (strcmp(cur->key, key) == 0) {
strcpy(cur->val, val);
free(new_node);
return 0;
}
last = cur; // save pointer to node that points to NULL
cur = cur->next;
}
last->next = new_node;
//why does it work here?
hm->item_count += 1;
return 1;
}
'head' is pointing to a hashnode_t and so is 'hm->table[i]'. So, they are both pointing to the same object. Changing 'head' just makes 'head' point elsewhere. You have not actually assigned a pointer in the hashmap_t to the 'new_node'.
The reason that 'last' works is that you are changing a member variable to a new value. And, since 'last' is pointing to an object already in the hashmap_t, the assignment updates the object pointed to in the hastmap_t. So, an update to 'last->next = new_node' is the same as 'hm->table[x]->next = new_node' ('x' is some arbitrary index).

Issues with linked list and pointers (C)

I am writing a C program to sort a linked list according to the largest values. I met an issue whereby the program just hangs when the program reached "prevPtr->next = headPtr".
I want the prevPtr->next to equate to headPtr, if the sum of prevPtr is larger than the sum of headPtr, however the program just hangs there.
compareNodes() function is used to compare the nodes to see if newNode has the same name as any other structs in the linked list, then it will add in the sum.
sortSimilarNodes() function is used to sort the nodes according to the sum of each struct.
The struct is here below:
struct purchase {
char name[30];
double sum;
struct purchase * next;
} ;
LOG * compareNodes(LOG * headPtr, char * name, char * price){
.
.
.
while (curPtr != NULL) {
if (strcmp(newNode->name, curPtr->name)==0) {
curPtr->sum += newNode->sum;
free(newNode);
similar = 1;
break;
}
//advance to next target
prevPtr = curPtr;
curPtr = curPtr->next;
}
/*if (curPtr == NULL){
if(strcmp(newNode->name, prevPtr->name)==0){
prevPtr->sum += newNode->sum;
free(newNode);
similar = 1;
}
}*/
if (similar == 1){
headPtr = sortSimilarNodes(curPtr, headPtr);
}
else{
headPtr = sortNodes(newNode, headPtr);
}
return headPtr;
}
LOG * sortSimilarNodes(LOG * newPtr, LOG * headPtr){
LOG * curPtr;
LOG * prevPtr;
if(headPtr->sum < newPtr->sum){
newPtr->next = headPtr;
return newPtr;
}
prevPtr = headPtr;
curPtr = headPtr->next;
while (curPtr == NULL){
}
while (curPtr != NULL){
if(strcmp(curPtr->name, newPtr->name)==0){
break;
}
prevPtr = curPtr;
curPtr = curPtr->next;
}
return headPtr;
}
This is the output of the program.
Thank you!
It's hard to tell from your code, because you haven't posted all of it, but you seem to have some misconceptions about linked lists. In particular:
There is no need for new nodes unless you really add new nodes to the list. That also means that you don't call malloc except when adding nodes. (There's no malloc in your code, but a suspicious free in your comparison function. Comparing does not involve creating or destroying anything; it just means to look what is already there.)
A corollary to the first point is that there should be no nodes in an empty list, not even dummy nodes. An empty list is a list whose head is NULL. Make sure that you initialise all head pointers before creating a new list:
LOG *head = NULL; // empty list
When you sort the list, the order of the list has changed and the old head is invalid. You cater for that by returning the new head:
head = sort(head);
But that seems redundant and it also seems to imply that the two pointers can be different. That's not the case, because the old pointer will point somehwre in the sorted list, not necessarily at its head. It's probably better to pass the head pointer's address in order to avoid confusion:
sort(&head);
Sorting linked lists can be tricky. One straightforward way is selection sort: Find the node with the highest value, remove it from the original list and add it at the front of a new list. Repeat until there are no more nodes in the original list.
Adding a new node n at the front of a list given by head is easy:
n->next = head;
head= n;
Adding a new node at the end of a list that is given by head is a bit more involved:
LOG **p = &head;
while (*p) p = &(*p)->next;
*p = n;
n->next = NULL;
Here, p is the address of the pointer that points to the current node, *p. After walking the list, that address is either the address of the head node (when the list is empty) or the address of the next pointer of the precedig node.
You could achieve something similar by keeping a prev pointer, but the pointer-to-pointer solution means that you don't have to treat the cases where there is no previous node specially at the cost of some extra & and * operators.
With that, your sorting routine becomes:
void sortByName(LOG **head)
{
LOG *sorted = NULL;
while (*head) {
LOG **p = head; // auxiliary pointer to walk the list
LOG **max = head; // pointer to current maximum
LOG *n; // maximum node
while (*p) {
if (strcmp((*p)->name, (*max)->name) > 0) max = p;
p = &(*p)->next;
}
n = *max;
*max = (*max)->next;
n->next = sorted;
sorted = n;
}
*head = sorted;
}
If you want to sort by sum, change the comparison to:
if ((*p)->sum > (*max)->sum) max = p;
Call the function like this:
LOG *head = NULL;
insert(&head, "apple", 2.3);
insert(&head, "pear", 1.7);
insert(&head, "strawberry", 2.2);
insert(&head, "orange", 3.2);
insert(&head, "plum", 2.1);
sortByName(&head);
print(head);
destroy(&head);
with the insert, destroy and print functions for completeness:
void insert(LOG **head, const char *name, double sum)
{
LOG *n = malloc(sizeof(*n));
if (n) {
snprintf(n->name, sizeof(n->name), "%s", name);
n->sum = sum;
n->next = *head;
*head = n;
}
}
void destroy(LOG **head)
{
LOG *n = *head;
while (n) {
LOG *p = n;
n = n->next;
free(p);
}
*head = NULL;
}
void print(LOG *l)
{
while (l) {
printf("%s: %g\n", l->name, l->sum);
l = l->next;
}
puts("");
}

Segmentation fault deleting nodes from singly linked list

this is the case i am working on
[11] -> [12] -> [13] -> NULL
I am trying to delete the elements from the liked list above(example) but I keep getting segfault and on running GDB doesnot help much. I am not looking for an answer but and explanation on where I am going wrong logically.
here is the code
int
List:: remove( int val )
{
ListNode *headNode = _head;
ListNode *tempNode = NULL;
if(headNode->_value == val){
tempNode = headNode->_next;
delete headNode;
_head = tempNode;
}
else
{
while(headNode->_value != val){
tempNode = headNode;
headNode = headNode->_next;
}
tempNode->_next = headNode->_next;
delete headNode;
}
}
You're not accounting for the following conditions:
The list may be empty; i.e. _head is NULL;
The value may not be in the list at all.
Your function is declared to return int, but makes no such return
Assuming the rest of your code is correct (and that is a big assumption), I'm all-but-certain this is what you're trying to do:
void List::remove( int val )
{
ListNode *headNode = _head;
ListNode *tempNode = NULL;
while (headNode && headNode->_value != val)
{
tempNode = headNode;
headNode = headNode->next;
}
if (headNode)
{
if (tempNode)
tempNode->next = headNode->next;
else
_head = headNode->next;
delete headNode;
}
}
Alternatively, if so inclined this can get (arguably) simpler utilizing a pointer-to-pointer to traverse the pointers in the list, not just their values. It is worth investigating how the following works, which still covers all the bases described previously, but does so using the actual pointers in the list nodes themselves, including _head, by-address rather than by-value, thereby eliminating the need for a walk-behind temporary pointer:
void List::remove( int val )
{
ListNode **pp = &_head;
while (*pp && (*pp)->_value != val)
pp = &(*pp)->next;
if (*pp)
{
ListNode *p = *pp;
*pp = p->next;
delete p;
}
}
In your remove method you are assuming there are always elements in your list. - What if it is empty?
What if the value isn't in the list? You need to handle this case as well.
You're headed in the right direction - there are just a few cases that you haven't considered that can lead you to seg fault.
Example of forward traversal with deletion (forward-only linked list):
// Start from the beginning (head), then while the current isn't null,
// move to the next node.
for (ListNode* current = head; current != null; current = current->next) {
// Check the next item if there is one, and remove it if it matches the value.
// We check the next one because you can't delete the current node in a
// forward only linked list (can in a doubly-linked list however)
if (current->_next != nullptr && current->_value == value) {
// Make this item point to the next next item
// (Since we're gonna delete the next item)
current->_next = current->_next->next;
// Delete the next item.
delete current->_next;
}
}

Maintaining chain of pointers to address

This is something of a followup to a question I asked earlier. I'm still learning my way around pointers, and I'm finding it difficult to maintain a reference to the physical address of a struct while iterating through a data structure. For example, I have a simple, barebones linked list that I'd like to delete from via a searching pointer:
struct Node{
int value;
struct Node* next;
};
struct Node* createNode(int value){
struct Node* newNode = malloc(sizeof *newNode);
newNode->value = value;
newNode->next = NULL;
return newNode;
}
void nodeDelete(Node **killptr){
free(*killptr);
*killptr = NULL;
}
int main(){
struct Node* head = createNode(16);
head->next = createNode(25);
head->next->next = createNode(51);
head->next->next->next = createNode(5);
// Working code to delete a specific node with direct reference address
struct Node** killptr = &head->next;
nodeDelete(killptr);
return 0;
}
The above shows deleting by passing nodeDelete a pointer to the address of the head pointer. What I want to do is be able to move my pointer ->next until it finds something that satisfies a delete condition, and call nodeDelete on that. I've tried the following:
struct Node* searchAndDestroy = head;
while(searchAndDestroy->value != NULL){ // Search until the end of the structure
if (searchAndDestroy->value == 25){ // If the value == 25
nodeDelete(&searchAndDestroy); // Delete the node (FAILS: Nullifies the
// address of search variable, not the
break; // original node)
}else{
searchAndDestroy = searchAndDestroy->next;
}
}
I've also tried something along the lines of:
if (searchAndDestroy->value == 25){
struct Node** killptr = (Node**)searchAndDestroy);
nodeDelete(killptr); // Still fails
}
I need to be able to move my pointer to the ->next point, but also maintain a reference to the address of the node I want to delete (instead of a reference to the address of the search node itself).
EDIT: Some clarification: I realize that deleting from a linked list in this fashion is naive, leaks memory, and drops half the list improperly. The point is not to actually delete from a linked list. Ultimately the idea is to use it to delete the leaves of a binary search tree recursively. I just figured a linked list would be shorter to portray in the question as an example.
struct Node **searchAndDestroy;
for (searchAndDestroy = &head;*searchAndDestroy; searchAndDestroy = &(*searchAndDestroy)->next ){
if ((*searchAndDestroy)->value == 25){
nodeDelete(searchAndDestroy); // Function should be changed to assign the ->next pointer to the **pointer
break;
}
}
And change nodeDelete like this:
void nodeDelete(Node **killptr){
Node *sav;
if (!*killptr) return;
sav = (*killptr)->next;
free(*killptr);
*killptr = sav;
}
Unless I'm missing something, your nodeDelete function is working as designed, but you want to keep a way of accessing the next node in the chain. The easiest way of doing this is just to add a temporary variable:
struct Node *searchAndDestroy = head, *temp = NULL;
while(searchAndDestroy != NULL){ // Need to check if the node itself is null before
// dereferencing it to find 'value'
temp = searchAndDestroy->next;
if (searchAndDestroy->value == 25){
nodeDelete(&searchAndDestroy);
break;
}else{
searchAndDestroy = temp;
}
}
if you give the Address of the previous Node that is where the link to deleting node present then it is very simple
code snippet for that:-
void delete_direct (struct Node *prevNode)
{/*delete node but restrict this function to modify head .So except first node use this function*/
struct Node *temp;/*used for free the deleted memory*/
temp=prevNode->link;
prevNode->link=temp->link;
free(temp);
}
struct Node * find_prev(struct Node *trv_ptr,int ele)
{
/*if deleting element found at first node spl operation must be done*/
if(trv_ptr->data==ele)
return trv_ptr;
while((trv_ptr->link)&&(trv_ptr->link->data!=ele))
{
trv_ptr=trv_ptr->link;
}
if(trv_ptr->link==NULL)
{
return NULL;
}
else
return trv_ptr;
}
main()
{
/*finding Node by providing data*/
struct Node *d_link;
struct Node *temp;
d_link=find_prev(head,51);
if(d_link==NULL)
{//data ele not present in your list
printf("\nNOT FOUND\n");
}
else if(d_link==head)
{//found at first node so head is going to change
temp=head;
head=head->link;
free(temp)
}
else
{//other wise found in some where else so pass to function
delete_direct (d_link);
}
}

Resources