Add names into a Multi-linked list - c

I am creating a multi-linked list of first name, last name, and phone number. I have an add function that allocates memory for the list but I don't know how to add into this list that will link first and last name in alphabetical order. How do I add to a multi-linked list? Is it much different from adding into a single linked list?
structures:
typedef struct node {
char *first;
char *last;
long number;
struct node *nextFirst;
struct node *nextLast;
} Node;
typedef struct mlist {
Node *headFirstName;
Node *headLastName;
} MultiLinkedList;
add function:
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
// add this new node at the head of the "byFirst" list
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
// add this new node at the head of the "byLast" list
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
// return the multi-list object with updated head pointers
return list;
}
Edit: Here I have added in an updated code of my add function that I modified with adding to a list that I have used for a single linked list
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
Node *tempf = list->headFirstName;
Node *templ = list->headLastName;
while (tempf && templ) {
if (strcasecmp(tempf->first, first) == 0 && strcasecmp(templ->last, last) == 0) {
printf("Error - name %s %s already exists\n", first, last);
return list;
}
tempf = tempf->nextFirst;
templ = templ->nextLast;
}
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
newNode->nextFirst = NULL;
newNode->nextLast = NULL;
if(list == NULL)
return newNode;
if(strcasecmp(first, list->headFirstName->first) < 0){
newNode->nextFirst = list->headFirstName;
return newNode;
}
Node *prevf = list->headFirstName;
Node *currf = list->headFirstName->nextFirst;
while(currf && strcasecmp(currf->first, first) < 0){
prevf = currf;
currf = currf->nextFirst;
}
prevf->nextFirst = newNode;
newNode->nextFirst = currf;
if (list == NULL)
return newNode;
if (strcasecmp(last, list->headLastName->last) < 0) {
newNode->nextLast = list->headLastName;
return newNode;
}
Node *prevl = list->headLastName;
Node *currl = list->headLastName->nextLast;
while (currl && strcasecmp(currl->last, last) < 0) {
prevl = currl;
currl = currl->nextLast;
}
prevl->nextLast = newNode;
newNode->nextLast = currl;
// add this new node at the head of the "byFirst" list
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
//list->headFirstName = addToFirstNameList(list->headFirstName, newNode);
// add this new node at the head of the "byLast" list
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
//list->headLastName = addToLastNameList(list->headLastName, newNode);
// return the multi-list object with updated head pointers
return list;
}

I'm not going to write out the entire code for this, but here's the algorithm you want to use:
For the last names list, every time you insert, iterate through the list until you reach a last name that comes after the name you're trying to insert. Insert your current last name before this one. If you don't find one, insert it at the end.
Do the same for the first names list.

Related

Inserting elements in a linked list in various indices using one function only

This is the code I tried writing down to add an element in a double linked list, that takes an index and a value and adds a new element to the original list.
It is taking index and value but just adds the elements I give like a stack.
node *add(node *head, int index, int val)
{
node *new = create(val);
node *temp = malloc(sizeof(node));
if (head == NULL)
{
head = new;
temp = head;
//printf(": %d",temp->data);
}
temp = head;
int i = 1;
while (i < (index - 1) && (temp->next != NULL))
{
i++;
temp = temp->next;
}
temp->next = new;
new->next = NULL;
new->prev = temp;
return head;
}
however this code(for a doubly linked list) just adds elements one after the other, disregarding the index passed.
My prof gave us a code for a singly linked list where he did something similar.
struct Node *insert(struct Node *listp, int pos, int info)
{
/*Inserts a Node in list at position pos with data info
pos>0. If pos>list length then new node added at end.
If pos<1 adds at beginning.
*/
struct Node *new=malloc(sizeof(struct Node)), *prev;// new is the new node we create everytime.
//create new node and initialize fields
new->data=info;
new->next=NULL;
if (listp==NULL) listp=new;
else
if (pos<=1) { //negative or 1 index.
new->next=listp; //first node bann gaya new
listp=new; //head is pointing at new
}
else {
//pos>1. Go to node at pos-1.
prev=listp;
int i=1;
while ((i++<pos-1) && prev->next!=NULL) { //indexing
prev=prev->next;
}
new->next=prev->next;
prev->next=new;
}
return listp;
}
how do I address this problem?
To implement a doubly linked list, your node needs to have pointers to the previous node and next node, then you can write something almost as similar to what your professor gave you for single linked list:-
#include <stdlib.h>
#include <stdio.h>
//Doubly linked list Node
typedef struct Node{
int info;
struct Node* next;
struct Node* prev;
} Node;
Node* insert(Node* listp, int pos, int info){
//Allocate memory for node and its previous neighbor
Node* new = malloc(sizeof(Node));
Node* prev = malloc(sizeof(Node)), *tail;
//initialize new node with these values
new->info = info;
new->next = NULL;
new->prev = NULL;
//if head doesn't exist then create one
if(listp == NULL){
/*
listp gets whatever new had, ie
listp->info = info
listp->next = NULL
listp->prev = NULL
*/
Node* tail = malloc(sizeof(Node));
tail->info = 0;
tail->next = NULL;
tail->prev = NULL;
listp = new;
listp->next = tail;
tail->prev = listp;
}
//Lets Loop through the List and insert node at pos
else {
if(pos <= 1){
/*
This should replace the current head
listp = new
*/
new->next = listp;
new->prev = listp->prev;
listp->prev = new;
listp = new;
}
else{
int i = 2;
prev = listp->next;
printf("%d\n", prev->prev->info);
while(i != pos){
printf("%d\n", new->info);
prev = prev->next;
i++;
}
new->next = prev;
new->prev = prev->prev;
prev->prev->next = new;
prev->prev = new;
}
}
return listp;
}
// Test case
int main(){
Node* listp;
listp = insert(NULL, 0, 2);
listp = insert(listp, 1, 3);
listp = insert(listp, 2, 5);
Node* cnt = listp;
printf("|");
while(cnt->next != NULL){
printf("--%d-->", cnt->info);
cnt = cnt->next;
}
printf("\n");
}
Try that. Make any typo corrections if any
#include <stdio.h>
#include <stdlib.h>
/**
* add_node_end - adds a new node at the end of a dllist list
* #head: head of linked list
* #n: integer value of node
*
* Return: address of new element, NULL if fails
*/
node *add_node_end(node **head, const int n)
{
node *new, *temp;
new = malloc(sizeof(node));
if (new == NULL)
return (NULL);
new->n = n;
new->next = NULL;
if (*head == NULL)
{
new->prev = NULL;
*head = new;
return (*head);
}
temp = *head;
while (temp->next)
{
temp = temp->next;
}
temp->next = new;
new->prev = temp;
return (new);
}
/**
* add_dnodeint - adds a new node at the beginning of a dlistint_t list
* #head: head of linked list
* #n: integer value of node
*
* Return: address of new element, NULL if fails
*/
node *add_node_start(node **head, const int n)
{
node *new;
new = malloc(sizeof(node));
if (new == NULL)
return (NULL);
new->n = n;
new->prev = NULL;
if (*head == NULL)
{
new->next = NULL;
*head = new;
return (*head);
}
new->next = *head;
(*head)->prev = new;
*head = new;
return (*head);
}
/**
* node_len - returns the number of elements in a dllist list
* #h: head of doubly linked list
*
* Return: number of nodes
*/
size_t node_len(const node *h)
{
int count = 0;
while (h)
{
count++;
h = h->next;
}
return (count);
}
/**
* insert_dnodeint_at_index - inserts a new node at a given position
* #h: a pointer to a pointer of the first node of node linked list
* #index: the position to add the new node
* #val: the data n of the new node
* Return: if the function fails = NULL
* otherwise - the address of the new node/element
*/
node *insert_dnodeint_at_index(node **h, unsigned int index, int val)
{
node *newNode, *current;
size_t list_length;
unsigned int i = 0;
if (h == NULL)
return (NULL);
if (index == 0)
return (add_node_start(h, n));
list_length = node_len(*h);
if (index == (list_length - 1))
return (add_node_end(h, n));
newNode = malloc(sizeof(node));
if (newNode == NULL)
return (NULL);
newNode->val = val;
if (*h == NULL)
{
newNode->prev = NULL;
newNode->next = NULL;
return (newNode);
}
current = *h;
while (current)
{
if (i == index)
{
newNode->next = current;
newNode->prev = current->prev;
current->prev->next = newNode;
current->prev = newNode;
return (newNode);
}
current = current->next;
i++;
}
free(newNode);
return (NULL);
}

How can I insert a node in a singly linked list using recursion given: 1. a pointer to the head node 2. the index to insert the new node

The function below is the one I am trying to work on. The problem I am running into is that I do not know how to "keep" the pointer to the original head to the list as that is what I have to return after insertion.
There is no Driver code so everything must be done inside this function.
Because I must do this recursively I cannot just create a temporary node to point to the original head. I am just getting used to recursion and I cannot find a solution.
NOTE: There are some other problems with my function as I believe it wouldn't work well for inserting a new node into the beginning and end of the linked list but I am confident I could work out those edge cases.
The main thing I am trying to learn is how to "store" the original head of my list.
All help is appreciated.
Node* insert(Node* head, int index, int data)
{
if (head == NULL) return NULL; // if list is empty
if (index == 1) // if we have accessed node before insertion
{
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->next = head->next; // new_node->next now links to the node next in the list
head->next = new_node; // head->next links to new node
new_node->data = data; // assigns new node its data
return head; // not sure how to return original head
}
return insert(head->next, index - 1, data);
}
Node *insertRecursive(Node* head,int pos,int val)
{
if(pos==0 || head==NULL)
{
Node *newNode= new Node(val);
newNode->next=head;
head=newNode;
return head;
}
else
head->next = insertRecursive(head->next,pos-1,val);
}
For starters the parameter that specifies the position where a node has to be inserted should have an unsigned integer type, for example, size_t. Positions should start from 0.
The function can be defined the following way
struct Node * insert( struct Node *head, size_t pos, int data )
{
if (head == NULL || pos == 0 )
{
struct Node *new_node = malloc( sizeof( struct Node ) );
new_node->next = head;
new_node->data = data;
head = new_node;
}
else
{
head->next = insert( head->next, pos - 1, data );
}
return head;
}
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
struct Node * insert( struct Node *head, size_t pos, int data )
{
if (head == NULL || pos == 0)
{
struct Node *new_node = malloc( sizeof( struct Node ) );
new_node->next = head;
new_node->data = data;
head = new_node;
}
else
{
head->next = insert( head->next, pos - 1, data );
}
return head;
}
void print( const struct Node *head )
{
for (; head != NULL; head = head->next)
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
int main( void )
{
struct Node *head = NULL;
head = insert( head, 0, 3 );
print( head );
head = insert( head, 0, 0 );
print( head );
head = insert( head, 1, 1 );
print( head );
head = insert( head, 2, 2 );
print( head );
}
The program output is
3 -> null
0 -> 3 -> null
0 -> 1 -> 3 -> null
0 -> 1 -> 2 -> 3 -> null
Node* insert_Node_recursively(Node* head,int data,int position){
//Inserting on the first node.
if(position==0){
Node* newNode=new Node(data);
newNode->next=head;
head=newNode;
return head;
}
if((head->next==NULL && position==0) /*for adding on the end of the list */ || position==1 /*Inserting on node in between */){
Node* newNode=new Node(data);
newNode->next=head->next;
head->next=newNode;
return head;
}
//in case the position exceeds the total number of nodes
if(head->next==NULL && position>0){
return head;
}
else{
head->next=insert_Node_recursively(head->next,data,position-1);
}
return head;
}
this will work I think, covered all the aspects
//if you have created a node using class then here is the solution
//to insert a node at a position recurssively
Node * insertRecursive(Node * head, int data , int key)
{
if (head == NULL || key == 0)
{
Node * newNode = new Node(data);
newNode -> next = head;
head = newNode;
}
else
{
head -> next = insertRecursive(head -> next , data , key - 1);
}
return head;
}
//here is the full solution to add a node recursively at a position
#include<iostream>
using namespace std;
//the below code is for creation of class for node
class Node
{
public:
int data;
Node * next;
Node(int data) //constructor
{
this -> data = data;
next = NULL;
}
};
//the below code is for creation of linked list
//a terminator -1 is used to stop taking input
Node * takeInput()
{
int data;
cout<<"Enter the data of the node to be inserted ( use -1 to terminate
the insertion ) : ";
cin>>data;
Node * head = NULL;
Node * tail = NULL;
while(data != -1)
{
Node * newNode = new Node(data);
if(head == NULL)
{
head = newNode;
tail = newNode;
}
else
{
tail->next=newNode;
tail = tail -> next;
}
cout<<"Enter the data of the node to be inserted ( use -1 to
terminate the insertion ) : ";
cin>>data;
}
return head;
}
//the below code is to print the linked list
void print(Node * head)
{
if(head == NULL)
{
cout<<"The linked list id empty !"<<endl;
return;
}
Node * temp = head;
while(temp != NULL)
{
cout<<temp->data<<" ";
temp = temp -> next;
}
cout<<endl;
}
//the below part is the main solution to the problem
//insertion at a position using recursion
Node * insertRecursive(Node * head, int data , int key)
{
if (head == NULL || key == 0)
{
Node * newNode = new Node(data);
newNode -> next = head;
head = newNode;
}
else
{
head -> next = insertRecursive(head -> next , data , key - 1);
}
return head;
}
//this is the main from where all the function calls happen
int main()
{
int data, key;
Node * head = takeInput();
print(head);
cout<<"Enter the data of the node to be inserted : ";
cin>>data;
cout<<"Enter the position of insertion : ";
cin>>key;
head = insertRecursive(head,data,key);
print(head);
}

Appending a ADT list seg fault

So im trying to append a list but every time I use the append function, it just crashes (SEG FAULT). I narrowed it down to around a line that in insert value and I marked it in the code below.
so here is the structs/lists
/*Declration of the struct*/
typedef struct Element {
value_type value;
Key_type key;
struct Element * next;
struct Element * sort;
}Node;
/*ADT declration*/
typedef struct List {
Node * head;
Node * head_sort;
Node * tail;
Node * tail_sort;
int size;
}Sorted_List;
Here is the rest of the code
/*Fucntion to add values ot the end using tail*/
int append_list (Sorted_List * List, value_type value, Key_type key){
int result = insert_value(List->tail, value, key) != NULL;
if ( result == SUCCESS){
List->size++;
List->tail = List->tail->sort;
}
return result;
}
int append (Sorted_List * List, value_type value, Key_type key){
return is_empty(List) ? push(List, value, key)
: append_list(List, value, key);
}
/*Function to insert value into list*/
Node * insert_value (Node * node, value_type value, Key_type key){
/*Setting a new node and mallocing it */
Node * new_node = malloc(sizeof(Node));
/*Checking for the new node to not equal null*/
if (new_node != NULL){
/*Setting the values for it*/
new_node->value = value;
new_node->key = key;
/*Setting the new node next to equal old nodes next*/
new_node->sort = node->sort;
/*Setting old node next to equal new node*/
node->sort = new_node;
/////I receive the error around this line^^^^/////
}
return new_node;
}
EDIT::
so here is the code for the push function used in the program
add front's job is to add the values rot the front
and find_prev_gt's job is to find the previes largest valus's location to add the new number
/*Function to push a value to to the front of the list*/
int push (Sorted_List * List, value_type value, Key_type key) {
Node * node = NULL;
int empty = 0;
empty = is_empty(List);
Node * next_node = NULL;
Node * insert_node = find_prev_gt(List->head, key);
int result = FAILURE;
if (insert_node == NULL) {
add_front(&(List->head), value,key);
}
else {
next_node = insert_node->sort;
if (next_node == NULL || next_node->key != key)
insert_value(insert_node, value,key);
}
result = (node != NULL );
/*Returns success if reseult is succesfull*/
if ( result == SUCCESS) {
List->size++;
if (empty)
List->tail = List->head;
}
return result;
}
Node * add_front(Node ** head, value_type value, Key_type key){
Node *new_node = malloc(sizeof(Node));
if (new_node != NULL) {
new_node->key = key;
new_node->value = value;
new_node->sort = *head;
*head = new_node; }
return new_node;
}
/*Function to check if list is empty*/
int is_empty (Sorted_List * list){
return list->head == NULL;
}
Node * find_prev_gt ( Node * head, Key_type key ) {
Node * node = head, * prev = NULL;
while (node != NULL && node->key < key){
prev = node;
node = node->sort;
}
return prev;
}
every time I use the append function, it just crashes
Your problem is in the function push where the value of node does not change after its initialization to NULL, so in
if ( result == SUCCESS) {
List->size++;
if (empty)
List->tail = List->head;
}
the test is always false and the associated code is not executed
You just need to change two lines, replace the line
add_front(&(List->head), value,key);
by
node = add_front(&(List->head), value,key);
and the line
insert_value(insert_node, value,key);
by
node = insert_value(insert_node, value,key);
If I do these two changes and I prefix your code by the definitions
#include <stdlib.h>
#include <stdio.h>
typedef int value_type;
typedef int Key_type;
#define SUCCESS 1
#define FAILURE 0
and add the following main :
int main()
{
Sorted_List list = { 0, 0, 0, 0, 0 };
Node * node;
append(&list, 2, 22);
append(&list, 3, 33);
append(&list, 1, 11);
for (node = list.head; node != NULL; node = node->sort)
printf("[key=%d, value=%d] ", node->key, node->value);
putchar('\n');
return 0;
}
the execution writes :
[key=22, value=2] [key=33, value=3] [key=11, value=1]
Out of that in Sorted_List your code change head and tail but not head_sort nor tail_sort but in Node you set sort but not next, this is not logical, furthermore the nodes are not sorted

What is wrong with my function for counting names in a linked list?

This is part of a larger bit of code but I will include what I think is important. There are actually two types of linked lists I am working with. As you will see the first struct just links to the first node of the list.
Here's the first:
typedef struct mlist {
Node *headFirstName;
Node *headLastName;
} MultiLinkedList;
Here's the second:
typedef struct node {
char *first;
char *last;
long number;
struct node *nextFirst;
struct node *nextLast;
} Node;
Here is how names and numbers are currently added to the list:
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
// add this new node at the head of the "byFirst" list
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
// add this new node at the head of the "byLast" list
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
// return the multi-list object with updated head pointers
return list;
}
And here is how I am currently attempting to count the names in the list:
int size(MultiLinkedList *list) {
int count = 0;
Node *newNode = malloc ( sizeof(Node) );
newNode->nextFirst = list->headFirstName;
newNode->nextLast = list->headLastName;
while (newNode->nextFirst!=NULL) {
count++;
}
// return the number of names in the list
return count;
}
If there is a specific name for traversing multiple lists like this then could someone just direct me to that?
You should use size_t for size
Your malloc() is useless
If you don't do somewhere something like x = x->next how do you want your loop finish ?
size_t size(MultiLinkedList *list) {
size_t count = 0;
for (Node *i = list->headFirstName; i; i = i->next) {
count++;
}
// return the number of names in the list
return count;
}

Filter linked list and return new linked list C

I am trying to filter a linked list. Since I don't want to change the original linked list, I want to create a sub linked list and return it instead.
I am having troubles with this because I only know how to get 1 node from the filtering process, but I don't know how to move around and add nodes from the original linked list to the sub linked list.
I have a struct like this (This represents an entry in a hash table):
typedef struct Entry {
char *word;
int len;
struct Entry *next;
} Entry;
My filter function will receive the word length and the original linked list as arguments, then find nodes that have the same value of len. Whenever it finds a node that has the same value of len, it adds the node to another linked list. Finally it returns the new linked list.
struct Entry* filterLen(int len, struct Entry *en) {
struct Entry *temp = (struct Entry *)malloc(sizeof(struct Entry));
while(en->next != NULL) {
if (en->len == len) {
// assign values to temp list
temp->word = en->word;
temp->len = en->len;
temp->next = en;
}
en = en->next; // move through list
}
return temp;
}
Entry* filterLen(int len, Entry *en) {
Entry result = { NULL, 0, NULL };
Entry *curr = &result;
while(en != NULL){
if(en->len == len){
Entry *temp = malloc(sizeof(*temp));
*temp = *en;
temp->next = NULL;
curr = curr->next = temp;
}
en = en->next;
}
return result.next;
}
Entry* filterLen(int len, Entry *en) {
Entry *result = NULL, **temp = &result;
while(en != NULL) {
if (en->len == len) {
// assign values to temp list
*temp = malloc(sizeof(Entry));
(*temp)->word = en->word;
(*temp)->len = en->len;
(*temp)->next = NULL;
temp = &((*temp)->next);
}
en = en->next; // move through list
}
return result;
}
EDIT
Seems to be a competition here, so:
Entry* filterLen(int len, Entry *en) {
Entry *result, **temp = &result;
for ( ; en; en = en->next) { // Move through list
if (en->len == len) { // Then assign values to temp list
*temp = malloc(sizeof(Entry));
(*temp)->word = en->word; // WARNING str shared with en list!!!
(*temp)->len = en->len;
temp = &((*temp)->next);
}
}
*temp = NULL;
return result;
}
Right now, your filtering function is copying the contents of the last node it found (including the next pointer) into the temp node. This results in the function returning the last matching node plus whatever comes after it in the list.
What you need to do is create a new node each time you find a matching node and copy the contents to that node. That includes duplicating the string so you don't have to worry about potentially double-freeing anything.
struct Entry* filterLen(int len, struct Entry *en) {
struct Entry *result = NULL, *temp = NULL;
while(en != NULL) {
if (en->len == len) {
// copy node to end of temp list
if (temp == NULL) {
result = malloc(sizeof(struct Entry));
temp = result;
} else {
temp->next = malloc(sizeof(struct Entry));
temp = temp->next;
}
temp->word = strdup(en->word); // Perform a deep copy
temp->len = en->len;
temp->next = NULL;
}
en = en->next; // move through list
}
return result;
}
From what I understood in you question, you want to return a linked list of entries with a len field equal to the input parameter. Currently, your code is only storing a single 'temp' and you need to rebuild a new list.
struct Entry* filterLen(int len, struct Entry *en) {
struct Entry *first = NULL;
struct Entry *last = NULL;
while(en != NULL) {
if (en->len == len) {
if(last){
last->next = (struct Entry *)malloc(sizeof(struct Entry));
last = last->next;
} else {
last = (struct Entry *)malloc(sizeof(struct Entry));
first = last;
}
// assign values to temp list
last->word = en->word;
last->len = en->len;
last->next = NULL;
}
en = en->next; // move through list
}
return first;
}

Resources