Struct linking to linked list - c++

I am new to c++, and am trying to port a program i have made in python to c++. I have a struct that is a linked list with a list of parts. Each of these parts contains one or more components. So i have tried to create two structs, where one struct links to the other struct.
But i dont seem to get the list_part to link to component_list.
struct list_part {
char partname[100];
int parttype;
component_list * comp;
list_part * next;
};
struct component_list {
char compname[100];
component_list * next;
};
I use the following function to add the part to the bottom of the list.
void addpart(char partname[], int parttype, component_list *newcomp) {
struct list_part *temppart;
struct list_part *currentpart;
temppart = (struct list_part *)malloc(sizeof(struct list_part));
strcpy_s(temppart->partname,partname);
temppart->parttype = parttype;
temppart->comp = newcomp;
currentpart = head;
if (head == NULL) {
head = temppart;
head->next = NULL;
} else {
while (currentpart->next != NULL) {
currentpart = currentpart->next;
}
temppart->next = NULL;
currentpart->next = temppart;
}
}
And a similar function to add the component to a list.
void addcomp(char compname[]) {
struct component_list *tempcomp;
struct component_list *currentcomp;
tempcomp = (struct component_list *)malloc(sizeof(struct list_part));
strcpy_s(tempcomp->compname,compname);
currentcomp = newcomp;
if (currentcomp == NULL) {
currentcomp = tempcomp;
currentcomp->next = NULL;
} else {
while (currentcomp->next != NULL) {
currentcomp = currentcomp->next;
}
tempcomp->next = NULL;
currentcomp->next = tempcomp;
}
}
When the first component in a part is present i try to add it with.
struct component_list *newcomp = NULL;
strcpy_s(compname,temp.c_str());
addcomp(compname);
and the rest of the components i was planing to add with these commands
strcpy_s(compname,temp.c_str());
addcomp(compname);
And finally this is added as a part with
addpart(partname,fluidname, parttype, newcomp);
When i do it this way the newcomp only returns 00000000, but i need it to return a pointer to the list with components for this part. I have no idea how to do this really, i am used to dynamic languages, and this is not an issue there. I have figured this is the best way to go about this, but am very open to suggestions for other solutions. As data structures is something i am very fresh at.

Since you are open for suggestions, I think the best suggestion is You should be using std::list. instead of your own linked list implementaion.
std::list is a ready to use STL container provided by the C++ Standard library and it is always going to be more efficient that any list implementation you write.

You have 2 big mistakes in addcomp function, this should work: (also moved some things)
void addcomp(char compname[]) {
struct component_list *tempcomp;
struct component_list *currentcomp;
tempcomp = (struct component_list *)malloc(sizeof(struct component_list/*FIX 1*/));
strcpy_s(tempcomp->compname,compname);
tempcomp->next = NULL; /*Better do it here*/
if (newcomp == NULL) {
newcomp = tempcomp;/*FIX 2*/
} else {
currentcomp = newcomp; /*Better do it here*/
while (currentcomp->next != NULL) {
currentcomp = currentcomp->next;
}
currentcomp->next = tempcomp;
}
}

Related

Duplicating linked list to be sorted is deleting the original linked list

I am trying to sort my linked list based on salary so that it displays the highest salary at the top and so on. It parses through my original linked list and duplicates each node to be inserted into a new sorted linked list, in this case "head" is the head of my original and "sorthead" is the head of the duplicate.
static void sortingRecords2() {
EmployeeRecords * q = head;
while (q != NULL) {
EmployeeRecords * sortnode = NULL;
sortnode = q;
sortnode->next = NULL;
sortnode->prev = NULL;
if (sorthead == NULL) {
sorthead = sorttail = sortnode;
}
else if (sortnode->Salary >= sorthead->Salary) {
sortnode->next = sorthead;
sorthead->prev = sortnode;
sorthead = sortnode;
}
else {
temp2 = sorthead;
EmployeeRecords * previous = NULL;
while (temp2 != NULL) {
if (sortnode->Salary <= temp2->Salary) {
previous = temp2;
}
temp2 = temp2->next;
}
if (previous->next == NULL) {
sortnode->prev = sorttail;
sorttail->next = sortnode;
sorttail = sortnode;
}
else {
sortnode->next = previous->next;
sortnode->prev = previous;
previous->next = sortnode;
sortnode->next->prev = sortnode;
}
}
q = q->next;
}
displayRecords(head);
}
After testing out different methods to try and figure out where exactly is the problem, I've determined that the sorting algorithm works fine but after it is done executing and I call my display function it only displays the head of my original list. After executing this function, all other calls to my display function also only displays the head of my original list where previously it properly displays the whole list.
I'm not sure why exactly my main "head" is affected during execution when at the start I already used a temp value "q" to copy the head.
The immediate bug that jumps out at me is
sortnode = q;
is an assignment of addresses. sortnode and q now point at the same node. That means
sortnode->next = NULL;
sortnode->prev = NULL;
changes this shared node and blows the stuffing out of the source list, leaking all of the following nodes.
You will need to create a new node that is a copy of *q for sortnode to point at and build the sorted list with copies of the source nodes.
sortnode = new EmployeeRecords(*q);
is the start of a possible solution.

Trouble inserting BST node into a List node

I'm creating a customer loyalty program type code using a Linked list and BST's. It uses a list of loyalty programs, each node containing a BST of customer ID's. Currently I am attempting to create a function that searches the list for a loyalty program, once found (creates if not) adds the customer ID into the BST of that node. However when testing, im running into a reading violation on the insert new list node (insert_at_front) function.
Any help would be greatly appreciated!
Ive tried altering the function type of the find_list function and creating wrapper functions for it as I have previously done with similar functions for BST's, but I keep getting lost in the code and it seems to break it more.
list.h header file:
typedef struct listNode {
char* name; //Name of company
BST *customer; //Tree of customer ID's
struct listNode *next; //Pointer for next compnay
} *ListNodePtr;
void option_insert(List *self) {
char* input_loyalty;
int input_ID;
printf("What loyalty program do you wish to add a customer to? \n");
scanf("%s", &input_loyalty);
printf("What is the customer ID \n");
scanf("%d", &input_ID);
find_list(self, input_loyalty, input_ID);
}
void find_list(List *self, char* data, int ID) {
ListNodePtr current = self->head;
if (current != NULL) {
if (current->name == data) {
insert_bst(self->head->customer, ID);
}
else {
current = current->next;
}
}
else {
insert_at_front(self, data);
insert_bst(self->head->customer, ID);
}
}
void insert_at_front(List *self, char* data) {
int n = strlen(data);
ListNodePtr new_node = malloc(n * sizeof(char*));
strcpy(new_node->name, data);
new_node->next = self->head;
self->head = new_node;
}
I have included the functions being utilised in the problem but note that they are separated in different .c files. (however this should cause no difference) and I can certainly provide more code if needed
The answer is probably in your use of malloc(). You are creating memory based off the size of data, and not the size of a struct.
I should also mention that if you are using C++ (and not C) it is probably better to learn how to use the new keyword instead.
Anyway, if you still decide to use malloc, try this instead:
void insert_at_front(List *self, char* data) {
int n = strlen(data);
ListNodePtr new_node = malloc(sizeof(listNode)); // note, we're using the size of a node instead
new_node->name = malloc(n * sizeof(char)); // now, we need to allocate the string too.
strlcpy(new_node->name, data, n); // if you want to use a "secure" copy
new_node->next = self->head;
self->head = new_node;
}

C++ get error after trying to check if pointer is null

I'm writing a program using single linked list. I'm adding element from the end of linked list, and to do that i need to do null check. But after i try to check if element is NULL or nullptr, i get error. Is problem in !*head check method? P.S Also would like to hear if there is better way to create/insert new node in the linked list.
#include <iostream>
typedef struct vertex vertex;
typedef struct edge edge;
typedef struct vertex {
int vertex;
struct vertex * next;
edge ** head;
}vertex;
typedef struct edge {
int vertex1, vertex2;
struct edge * next;
}edge;
void add_vertex(vertex ** head, int vertex_value) {
vertex * new_vertex = new(vertex);
new_vertex->vertex = vertex_value;
if (!*head) {
new_vertex->next = NULL;
*head = new_vertex;
return;
}
vertex * tracer = *head;
while (tracer->next != NULL) {
tracer = tracer->next;
}
tracer->next = new_vertex;
new_vertex->next = NULL;
}
int main() {
vertex ** head = nullptr;
add_vertex(head, 1);
}
I get read access violation error in add_vertex functions on if(!*head) moment.
You are trying to dereference head which is it self NULL.
That is illegal in C++.
The way your add_vertex function is built, you must never send it NULL parameter as head.
Allocate a head in main and that problem will be solved.
In main
vertex *head = nullptr;
add_vertex(&head, 1);
This fixes your problem, but it would be better to pass head by reference.

Linked list sorting function in C++ doesn't stop properly

Many thanks in advance!
So, I've made attempts to make this function work. There are mistakes in the function but cannot catch them.
It seems to me, that I've missed the logic of sorting.
Could you point me 'where to go'?
/* node*/
typedef struct client {
int number; /* */
int balance;/* */
char lastName[20]; /* */
char firstName [20];/* */
char phone[11]; /* */
char email[20];
struct client *prev;/* */
struct client *next;
struct client *tmp; /* */
} Client;
Client *firstc,*currentc,*newc, *a, *b,*tmp; /*pointers*/
/* *"firstc' firstc element in list
*'currentc' current node
*'newc' new node
*'a' temporary pointer to Sort function
*'b' temporary pointer to Sort function
*'tmp' temporary pointer to Sort function
*/
int counter = 0;
int cnum = 0; /*cnum gives unique account numbers avoiding misentering*/
/*---Sort function------*/
void Sort()
{
/* */
int a = 0;/*variables to store balance*/
int b = 0;/*variables to store balance*/
if(firstc==NULL)
printf("Database is empty"); /*message*/
else
currentc = firstc;
currentc->prev = NULL;
tmp = NULL;
while((currentc=currentc->next)!= NULL)
{ /* 1) compare two nodes;
2) IF balance >*/
int a = currentc->balance;
int b = currentc->next->balance;/* debugger stopped here... */
if (a>b)
//if(currentc->balance >currentc->next->balance)
{ /*swap nodes*/
/*code using three pointers*/
tmp = currentc->next;
currentc->next->next = currentc->next;
currentc->next->next = tmp;
}
/*3)move along the list*/
else
currentc = currentc->next;
/*4) repeat to the end of list*/
}
currentc = firstc;
listAll();
return;
}
int b = currentc->next->balance;/* debugger stopped here... */
When currentc is pointing to the last item in the list currentc->next will be null. So currentc->next->balance is an access through a null pointer.
Also, practices like making assignments in conditions like while((currentc=currentc->next)!= NULL) will eventually come back to hurt you. In this case it seems you are skipping the first item in the list.
You probably meant:
if(firstc == NULL)
printf("Database is empty"); /*message*/
else
{ /* missing braces spotted by others */
currentc = firstc;
currentc->prev = NULL;
tmp = NULL;
for( ; currentc != NULL; currentc = currentc->next)
{
if(currentc->next == NUL)
/* nothing to compare */
break;
...
}
}
Furthermore the swapping code is swapping the wrong nodes:
tmp = currentc->next;
currentc->next->next = currentc->next;
currentc->next->next = tmp;
will almost (but not quite) swap the next node (b), with the one after it instead of with (a). You need to use the prev pointer (However since this looks like homework I had better not tell you exactly how to do it). Also, you are initialising prev but you need to keep it up to date in the loop. Actually, your 3 lines above are equivalent to:
tmp = currentc->next;
currentc->next->next = tmp;
so I think you meant something else.
the problem is when currentc is the last node, currectc->next is null, thus currentc->next->balance make it crash.
add some validation like
if (currentc->next == null)
and set b to a default/predefined value or put some logic whether you swap the nodes or not.

Interview Coding - Take a pointer to a Node structure as a parameter and return a complete copy of the passed-in data structure

This is an interview question that I found interesting.
Write a method that takes a pointer to a Node structure as a parameter and returns a complete copy of the passed-in data structure.
The Node structure contains two pointers to other Node structures.
For example, the method signature could look like so:
Node* Copy(Node* root);
Note - Do not make any assumptions about the data structure – it could be a tree, linked list, graph, etc.
How can this be done for any data structure ?
In the generic graph case, you need a mapping from nodes in the original graph to nodes in the new graph, so that when a cycle is encountered, the proper link gets created. If you happen to have extra temporary space in each node, large enough to hold a pointer, then you can store the mapping directly in the nodes; otherwise, you'll need to use an external map, such as an associative array or hash table.
Then it's just a matter of traversing the graph, copying nodes, and looking up the corresponding edges. Something like this:
struct Node
{
Node(int _data) : data(_data) { memset(links, 0, sizeof(links)); }
int data;
Node *links[2];
}
Node *Copy(Node *root)
{
typedef std::map<Node*, Node*> NodeMap;
NodeMap nodeMap;
std::deque<Node*> nodesToVisit;
// Set up initial new root and mapping for the root
Node *newRoot = new Node(root->data);
nodeMap[root] = newRoot;
// Breadth-first search the graph
nodesToVisit.push_back(root);
while(!nodesToVisit.empty())
{
Node *cur = nodesToVisit.front();
nodesToVisit.pop_front();
Node *newCur = nodeMap[cur];
for(int i = 0; i < 2; i++)
{
Node *link = cur->links[i];
if(link)
{
// If we've already created the corresponding node for this
// link, use that. Otherwise, create it and add it to the map.
NodeMap::iterator mappedLink = nodeMap.find(link);
if(mappedLink != nodeMap.end())
{
newCur->links[i] = mappedLink->second;
}
else
{
Node *newLink = new Node(link->data);
nodeMap[link] = newLink;
newCur->links[i] = newLink;
nodesToVisit.push_back(link);
}
}
}
}
return newRoot;
}
The problem as stated is impossible. You have to assume that the entire data structure is stored entirely within the content of nodes that are accessible from that initial one. But that is not an assumption you are allowed to make. Even your standard basic double linked list might not fit that description.
class Copier {
std::map <Node*, Node*> copies;
Node* Copy(Node* n) {
if (!n) return 0;
Node*& copy = copies[n];
if (!copy) {
copy = new Node();
copy.node1 = Copy(n.node1);
copy.node2 = Copy(n.node2);
}
return copy;
}
}
Node* Copy(Node* root) {
if (root == NULL)
return root;
std::unordered_map<Node*, Node*> completed;
std::deque<Node*> todo;
Node *ret = new Node(*scur);
completed.push_back(std::make_pair(root, ret));
todo.push_pack(root);
//while there's more nodes to duplicate
do {
//duplicate the node
Node* oldNode = todo.back();
Node* newNode = completed[cur];
todo.pop_back();
if(oldNode->left) {
auto iter = completed.find(oldNode->left);
//if it has a left child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->left = new Node(*(oldNode->left));
completed.push_back(std::make_pair(oldNode->left, newNode->left));
todo.push_back(oldNode->left);
} else {
newNode->left = completed[oldNode->left];
}
}
if(oldNode->right) {
auto iter = completed.find(oldNode->right);
//if it has a right child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->right = new Node(*(oldNode->right));
completed.push_back(std::make_pair(oldNode->right, newNode->right));
todo.push_back(oldNode->right);
} else {
newNode->right= completed[oldNode->right];
}
}
} while(todo.empty() == false)
//return the translation of the root
return ret;
}
Doesn't have stack overflow, root can be NULL, doesn't fail if left or right are NULL.
[Edit]Adam Rosenfield made me realize this was incorrect if there was loops in the network. Had to rewrite almost from scratch. Due to the large amount of code required, I prefer his code's for loop.
return new Node(*node);
Trick question?
You should write it recursively;
Node * Copy( Node * root )
{
Node * node_copy;
node_copy = new Node; // Assume Node1 and Node2 are initialized to 0
node_copy->content = root->content;
if( root->Node1 ) node_copy->Node1 = Copy( root->Node1 );
if( root->Node2 ) node_copy->Node2 = Copy( root->Node2 );
return node_copy;
}
So, this does not make any assumption on the data type
Given that a copy constructor exists that copies only the contents of a node and not its children:
Node* Copy(Node* root)
{
Node* copy = new Node(*root);
copy->left = Copy(root->left);
copy->right = Copy(root->right);
return copy;
}
In a more general sense, I would use copy-constructors that fully copy the entire data structure:
Node* Copy(Node* root)
{
return new Node(*root);
}