I am trying to teach myself linked-lists with node structs and was hoping someone could help me with this. I would take input from the command line and it would make me a nested list and I could output it.
Example:
Input: "1 2 3 4 5"
Output:"1 2 3 4 5"
There are two things I am having trouble with:
1) When I run the program I keep getting warning: ‘typedef’ was ignored in this declaration [enabled by default]
How can I get rid of this?
EDIT: I have changed this to typedef struct Node* NodePtr;
2) My code is not working properly. How can I fix this? I am trying to teach myself linked lists in C++.
typedef struct Node;
typedef Node* NodePtr;
struct Node{
int x;
NodePtr next;
};
int main ()
{
int n;
NodePtr head, ptr = NULL;
head = ptr;
while (cin >> n){
ptr = new Node;
ptr->x = n;
ptr->next = NULL;
ptr = ptr->next;
}
NodePtr bling = head;
while(bling != NULL){
cout << bling->x << endl;
bling = bling->next;
}
return 0;
}
Ideally what I want to do is to make a linked-list like the following.
1 -> 2 -> 3 -> NULL.
First, regarding the declaration of your structure and the pointer typedef you seem to want, there are a number of ways of doing this. The following will work in C or C++.
// declare NodePtr as a pointer to Node, currently an incomplete type
// C and C++ both allow you to declare a pointer to damn-near anything
// so long as there is an understanding of what it *will* be, in this
// case, a structure called Node.
typedef struct Node *NodePtr;
// Now declare the structure type itself
struct Node
{
int x;
NodePtr next;
};
That said, I honestly do not recommend doing this. Most engineers want a clear and syntax-visible definition that screams to them, "THIS IS A POINTER!" You may be different. I, personally would simply prefer this:
struct Node
{
int x;
struct Node *next; // omit the 'struct' for C++-only usage
};
So long as you, and equally important, other engineers reading your code, understand your usage of NodePtr as a pointer-to-node, then go with what works best in your situation. Pointer type declaration is near-religious to some, so just keep that in mind. Some prefer seeing those asterisks (I being one), some may not (sounds like you =P).
Note: there is one place that using a typedefed pointer-type can be beneficial in avoiding potential errors: multiple variable declarations. Consider this:
Node* a, b; // declares one Node* (a), and one Node (b)
Having a typedef struct Node *NodePtr; allows this:
NodePtr a, b; // declares two Node*; both (a) and (b)
If you spend enough time writing code in C the former of these will come back to bite you enough times you learn to not make that mistake, but it can still happen once in awhile.
The Load Loop
Regarding the load-loop for piecing together your list, you're not wiring up your list correctly, and frankly there are a million ways to do it, one being the one below. This does not require you to clean out "an extra node". Nor does it require any if (head){} else{} block structure to avoid said-same condition. Consider what we're really trying to do: create nodes and assign their addresses to the right pointers:
NodePtr head = NULL; // always the head of the list.
NodePtr* ptr = &head; // will always point to the next pointer to assign.
int n;
while (cin >> n)
{
*ptr = new Node;
(*ptr)->x = n;
ptr = &(*ptr)->next;
}
// note this always terminates the load with a NULL tail.
(*ptr)->next = NULL;
How It Works
Initialize the head pointer to NULL
Initializer a Node pointer-pointer (yes a pointer to a pointer) to point to the head pointer. This pointer-to-pointer will always hold the address of the target pointer that is to receive the address of the next dynamic-allocated node. Initially, that will be the head pointer. In the above code, this pointer-to-pointer is the variable: ptr.
Begin the while-loop. For each value read, allocate a new node, saving it in the pointer that is pointed-to by ptr (thus the *ptr). On the first iteration this holds the address of the head pointer, so the head variable will get our new node allocation. On all subsequent iterations, it contains the address of the next pointer of the last node inserted. Incidentally, saving the address of this new target pointer is the last thing that is done in the loop before we move to the next allocation cycle.
Once the loop is complete, the last node inserted needs to have its next pointer set to NULL to ensure a properly terminated linked list. This is mandatory. We conveniently have a pointer to that pointer (the same one we've been using all this time), and thus we set the pointer it "points to" to NULL. Our list is terminated and our load is complete. Brain Food: What pointer will it be pointing to if the load loop never loaded any nodes? Answer: &head, which is exactly what we want (a NULL head pointer) if our list is empty.
Design
I hope this will help better explain how it works through three full iterations of the loop.
Initial configuration
head ===> NULL;
ptr --^
After one iteration:
head ===> node(1)
next
ptr ------^
After two iterations
head ===> node(1)
next ===> node(2)
next
ptr ----------------^
After three iterations
head ===> node(1)
next ===> node(2)
next ===> node(3)
next
ptr --------------------------^
If we stopped at three iterations, the final termination assignment (*ptr = NULL;), gives:
head ===> node(1)
next ===> node(2)
next ===> node(3)
next ===> NULL;
ptr --------------------------^
Notice that head never changes once the first iteration is finished (it always points to the first node). Also notice that ptr always holds the address of the next pointer that is to be populated, which after the initial iteration (where it started as the address of our head pointer), will always be the address of the next pointer in the last node added.
I hope that gives you some ideas. It is worth noting that pairing these two pointers (the head pointer and the ptr pointer) into their own structure and having the appropriate management functions defines the textbook Queue; where one end is only for insertions (ptr) one is for extractions (head) and the container does not allow random access. There isn't much need for such a thing these days with the standard library container adapters like std::queue<>, but it does provide an interesting adventure into a good use of pointer-to-pointer concepts.
Complete Working Sample
This sample just loads our queue with 20 elements, prints them, then cleans out the queue and exits. Adapt to your usage as needed (hint: like change the source of the incoming data perhaps)
#include <iostream>
using namespace std;
// declare NodePtr as a pointer to Node, currently an incomplete type
// C and C++ both allow you to declare a pointer to damn-near anything
// so long as there is an understanding of what it *will* be, in this
// case, a structure called Node.
typedef struct Node *NodePtr;
// Now declare the structure type itself
struct Node
{
int x;
NodePtr next;
};
int main()
{
// load our list with 20 elements
NodePtr head = NULL;
NodePtr* ptr = &head;
for (int n=1;n<=20;++n)
{
*ptr = new Node;
(*ptr)->x = n;
ptr = &(*ptr)->next;
}
// terminate the list.
*ptr = NULL;
// walk the list, printing each element
NodePtr p = head;
while (p)
{
cout << p->x << ' ';
p = p->next;
}
cout << endl;
// free the list
while (head)
{
NodePtr victim = head;
head = head->next;
delete victim;
}
return 0;
}
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
You do not actually set the 'head' variable beyond NULL(head = ptr). You you actually lose your list from the get go. Try this:
int n;
NodePtr head, ptr;
ptr = new Node;
head = ptr;
while (cin >> n){
ptr->x = n;
ptr->next = new Node;
ptr = ptr->next;
}
You may then want to delete the last ptr->next and set it to 0 to save memory and avoid printing out an extra value.
First, your typedef : typedef struct Node; is not correct. You declare a struct with the sintaxe:
struct st_Name{
int field1;
double field2;
};
Typedef is like a name attribution function. You should (for easier reading/working) change the name of your struct, wich is possible, after declaring it, with:
typedef struct Node_st Node;
Or, all in one statement:
typedef struct node_st{
int x;
struct node_st *next;
}Node;
In the segment above, notice that I also changed the NodePtr to struct node_st *Next for a reason: If you do all in one segment, since c++ code is read linearly top->down(kinda), if you try to make NodePtr a pointer to Node before the struct declaration you'll get an error, and if you do it later and use NodePtr inside the struct you'll also have an error.
The compiler don't know yet that the struct exists so it will say that you're trying to name something that does not exist.
Then, your pointers manipulation is wrong.
...
while (cin >> n){
ptr = new Node;
ptr->x = n;
ptr->next = NULL; // You're making the next slot inexistent/NULL
ptr = ptr->next; // You're just setting ptr to NULL
}
...
What I think that you want is to keep adding to the end a keep the head in the first number. You can do this simply with an if/else statement for the first case:
while (cin >> n){
if(head == NULL){
ptr = new Node;
ptr->x = n;
ptr->next = NULL;
head = ptr;
}else{
ptr->next = new Node;
ptr = ptr->next;
ptr->x = n;
ptr->next = NULL;
}
}
This way, your insertion happens in the end so your print loop should work.
Hope this helps.
You aren't connecting the list. Every new item will have it's ->next NULL.
You say ptr = ptr->next (which is NULL) but then the next iteration overwrites ptr with the newly allocated node. You need to rearrange your code to string the nodes together...
One way of doing that is ptr->next = head makes your new node point to the old head.
Then head = ptr to move the head to the new node. e.g.:
To insert in the beginning (e.g. for a LIFO, last-in-first-out):
while (cin >> n){
ptr = new Node;
ptr->x = n;
ptr->next = head;
head = ptr;
}
To insert at the end (for a FIFO):
while (cin >> n){
if(!head) {
head = new Node;
ptr = head;
}
else
{
ptr->next = new Node;
ptr = ptr->next;
}
ptr->next = NULL;
ptr->x = n;
}
Related
guys I am desperately trying to learn how to manipulate linked lists and I am having a hard time. I can't understand most of the tutorials online and they all don't seem intuitive to me. I have successfully tried to append a node at the beginning of a linked list using a double pointer, but the nature of this double pointer isn't behaving like I thought it would. Please refer to my code below:
#include <iostream>
using namespace std;
class node{
public:
int value;
node* next;
};
void push2front(node** ptr, int n) //a node pointer is now equal to the address of the head node
{
cout<<"ptr: "<<ptr<<endl;
cout<<"*ptr: "<<*ptr<<endl;
node* new_node = new node(); //create a new head node
new_node->value = n;
new_node->next = *ptr;
*ptr = new_node;
return;
}
int main() {
node* head = new node();
node* second = new node();
node* third = new node();
int input = 54;
head->value = 1;
head -> next = second;
second->value = 2;
second->next = third;
third->value = 3;
third->next = NULL;
cout<<"head: "<<head<<endl;//address of the data member value of head
cout<<"&head->value: "<<&head->value<<endl;//address of the value data member of node head
cout<<"&head: "<<&head<<endl;//address of the head node itself
cout<<"head->next: "<<head->next<<endl;//address of the next node after head
cout<<second<<" "; //address of the data member of 2nd node
cout<<&second->value<<" ";//address of the data member of 2nd node
cout<<&second<<endl;//address of the 2nd node itself
push2front(&head, input); //pass the address of the actual head node as well as the user inputted integer
while (head!=NULL)
{
cout<<head->value<<" ";
head = head->next;
}
return 0;
}
the output of this program is as follows:
head: 0x921520
&head->value: 0x921520
&head: 0x7bfe08
head->next: 0x921540
0x921540 0x921540 0x7bfe00
ptr: 0x7bfe08
*ptr: 0x921520
54 1 2 3
I placed a lot of cout in the program to see what happens as the program runs. Everything is fine and DANDY until the moment the I call the push2front() function. Here are my questions:
1.) Am I correct when I think that &head->value or simply head is the address of the value data member of the head node? Because based on what my cout shows, this seems to be the case.
2.) So does that mean that &head is the ACTUAL address of the node?
3.) I always thought that the next part of any node points to the ACTUAL address of the node next to it? So essentially I thought that
head->next == &second? But it seems that (according to the cout) nodes apparently point to the address of the value data member in
another node?
4.) If head: 0x91520 == ptr: 0x91520 why does head->value work and *ptr->value doesn't?
head contains the address of the first node. That is, the address of the beginning of the memory occupied by that node. That is also the address of the value member of that node, because that node and its value member start at the same place.
head is a pointer, which is a variable. &head is the address of that pointer. Pointing to a thing is not the same as pointing to a variable that contains the thing's address.
Yes, if the list is constructed correctly, the next part of any node points to the next node, which is to say it contains the actual address of the next node. So head->next == second, which is the address of the second node, and also of the second node's value member. It is not the case that head-next == &second, because second is a pointer that is not part of the list at all.
(*ptr)->value works; *ptr->value doesn't. The pointer operator (->) takes precedence over the dereference operator (*), so when you try to use *ptr->value, the compiler sees that as *(ptr->value) and complains "what do you mean, ptr->value? ptr is a pointer to a pointer, not a pointer to a thing that has members."
i need to insert a node at a given position in a linked list.
Is there any better way to do it?
Here is my code:
struct node
{
int data;
node* next;
};
void InsertNodeAtPosition(node *& first , int x , int position)
{
//0 based indexing
int i = 0;
node *q = new node;
q = first;
while (i != position - 1)
{
q = q->next;
i++;
}
node *t = new node;
t->data = x;
t->next = q->next;
q->next = t;
}
I tested it and it works.But i want to be really good at linked lists before moving to the next chapter.Thanks!
The written by you function is wrong has a memory leak and undefined behavior.
For example at first the pointer q is assigned with the address of the dynamically allocated memory and then it is reassigned with the value of the pointer first. So the address of the allocated memory is lost and the memory can not be freed.
node *q = new node;
q = first;
Moreover the pointer first passed to the function by reference is never changed within the function.
In the while loop you are not checking whether the pointer q is equal to nullptr
while (i != position - 1)
{
q = q->next;
i++;
}
So this statement
q = q->next;
invokes undefined behavior.
Also if position is equal to 0 then the condition
i != position - 1
will evaluate to true and again you will have undefined behavior.
The function can be written the following way
void InsertNodeAtPosition( node * &first , int x , size_t position )
{
node **current = &first;
while ( *current && position-- )
{
current = &( *current )->next;
}
*current = new node { x, *current };
}
Is there any better way to do it?
Certainly, it would be better to not leak memory:
node *q = new node;
q = first;
As for the algorithm itself: For a singly linked list, a better way to insert an element into specific position is to pass a pointer to the previous node as the argument rather than the head and the position. That way there is no need for linear search. But for given arguments, your attempted algorithm is optimal.
As for class design: A better way is to implement iterators for the list and use those instead of pointers to nodes so that standard algorithms can be used. And follow the rule of 5 in order to conform to the RAII pattern and container concept. And use templates to support different data types. And support the use of custom allocators so that user have control over how the nodes are allocated.
As for higher level design: A better way to use a singly linked list is to not do any of this since the standard library already provides an implementation of the data structure: std::forward_list.
Isn't this a way to store a node in an array? When I try to run it I get a segmentation fault. I know that happens if you try to access memory that you do not have permission for.
In this code am I not assigning a node in an array and printing its data?
struct Node{
int data;
struct Node* next;
};
struct Node* head = NULL;
int main(){
struct Node* arr[10];
head->data = 2;
head->next = NULL;
arr[1] = head;
std::cout << arr[1]->data;
}
You are not dealing with Nodes's here, but Node pointers. They are not pointing to valid memory, unless you allocate it.
Also, don't use NULL, use nullptr instead.
head = nullptr;
head->data = 42; // this is UB, could be a segfault
If you want to do that, you have to allocate it
head = new Node{};
head->data = 42; //ok
The same logic applies for arr
arr[1] = new Node{}; // now arr[1] is pointing to valid memory
I'm not sure why you want an array of Node pointers, though. Your Node struct looks like a conventional linked-list Node, and there's a linked-list tag, so I'm guessing you want to implement linked-lists.
In that case, you don't need an array of Node pointers at all. The entire linked-list should be connected through the head.
If you just want an array of Nodes, then you can do that, and not worry about memory allocation at all.
Node arr[10] {};
arr[1].data = 42; // ok
The problem statement is the following:
Given a singly linked list, write a function to swap elements pairwise. For example, if the linked list is 1->2->3->4->5->6->7 then the function should change it to 2->1->4->3->6->5->7, and if the linked list is 1->2->3->4->5->6 then the function should change it to 2->1->4->3->6->5
Here is my solution:
void swapPairs(Node* head) {
if (!head->next || !head)return head;
Node* current = head->next;
Node*prev = head;
while (true) {
Node* next = current->next;
current->next = prev;
if (!next || !next->next) {
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
current = prev->next;
}
}
The issue with the solution is that when it gets to the end of the function, the head no longer points to the beginning of the list since both current and prev have been moved. I've seen other solutions online which do the same thing as I'm doing here, but maybe since they are implemented in C instead of C++, there is some aspect of their code that allows for the head to remain pointing to the start of the list.
I realize that this is probably a really simple issue to solve, but I'm just not currently seeing the solution. What would be the best way to maintain the beginning of the list throughout the algorithm?
The task at hand will be much simpler once you undergo a slight paradigm shift. This might seem more complicated at first, but after pondering it a bit, its simplicity should be obvious.
Simply said: instead of carrying a pointer around -- to the first of each pair of list elements -- as you walk through the list, carry a pointer to the pointer to the first of each pair of list elements. This sounds complicated, on its face value; but once the dust settles, this simplifies the task at hand greatly.
You must have a head pointer stored separately, and you're passing it to swapPairs():
Node *head;
// The list gets populated here, then ...
swapPairs(head);
That's what you're doing now. But rather than doing this, pass a pointer to the head node, instead:
swapPairs(&head);
// ...
void swapPairs(Node **ptr)
{
while ( (*ptr) && (*ptr)->next)
{
// swap the next two elements in the list
// ...
// Now, advance by two elements, after swapping them.
ptr= &(*ptr)->next->next;
}
}
The body of the while loop is going to swap the next two elements in the list, and let's skip over that part for now, and just focus on this bit of logic that iterates through this linked list, a pair of elements at a time. What's going on here?
Well, you are trying to walk through the list, two elements at a time.
Remember, ptr is no longer the pointer to the first element of the pair. It's a pointer to wherever the pointer to the first element of the pair happens to live. So the initial ptr is pointing to your original head pointer.
Once you understand that, the next mental leap is to understand that you want to cycle through your iteration as long as there are at least two elements left in the list:
while ( (*ptr) && (*ptr)->next)
*ptr is the next element to the list, the first of the pair, and (*ptr)->next would therefore be the pointer to the second in the pair. Because of how we're iterating, ptr can be proven, by contract to never be NULL. So, if *ptr is NULL, you reached the end of the list. But if *ptr is not NULL, there's at least one element left, and (*ptr)->next is the "next 2nd element". If (*ptr)->next is NULL, the original list had an odd number of elements in it, so on the last iteration you ended up with *ptr pointing to the odd duck. And you're done in that case too, no need to go any further.
Finally:
ptr= &(*ptr)->next->next;
This simply advances ptr by two elements of the list. Remember, ptr is a pointer to wherever the pointer to the first of the next two elements in the list "happens to live", and this now sets ptr to point the where the pointer to the first of the ***next**** two elements in the list happens to live. Take a piece of paper, draw some diagrams, and figure this out yourself. Do not pass "Go", do not collect $200, until this sinks in.
Once you wrapped your brain around that, the only thing that's left is to swap the pairs. That's it. The body of the loop can simply be:
Node *first=*ptr;
Node *second=first->next;
Node *next=second->next;
*ptr=second;
second->next=first;
first->next=next;
That's it. You're done. And, guess what? Your original head is now automatically pointing to the right head node of the swapped list.
Now, wasn't that easy?
Change the signature of the function to
Node* swapPairs(Node* head)
and save the new head after the first swap, then at the end after your while loop's closing }, return that new head, to replace the old list head held by the caller, which would use this something like:
list = swapPairs(list);
You can keep a pointer to the new head at the beginning of the function and update the head at the end of the function with that. Note that I changed the argument from Node* to Node ** because we want to update the pointer value so that when we update head, we write to the same memory location that passed to this function. As a result, the correct value of head will be available in the caller of this function when we return from it.
void swapPairs(Node **head) {
if (!(*head)->next || !(*head))
return;
Node *new_head = (*head)->next; // the new_head
Node *current = (*head)->next;
Node *prev = (*head);
while (true) {
Node *next = current->next;
current->next = prev;
if (!next || !next->next) {
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
current = prev->next;
}
*head = new_head; // now update the head
}
I tried asking my question but I don't appear to be asking it correctly and I have been stuck for 2 months now. (which is sad)
For reference only: I built a linked list from nodes:
struct node {
int number;
node *next; };
To link these in main I used -> to assign values
void insertAsFirstElement(node *&head, node *&tail, int number){
node *temp = new node;
temp->number = number;
temp->next = NULL;
head = temp;
tail = temp; }
Now I am trying to make a skiplist, which should have the same structure as my original node except the node* next should be an array of pointers of type node.
struct node {
int number;
node *next[3];
};
I am getting confused on how to have an array of node pointers. I notice they tend to look like this: node **next and then declared to have memory allocated dynamically. I just want my arrays to be of size 4. So [3].
My problem is how can I create new nodes with the array of node pointers in main() and put something in the first slot of the nodes array?
This does not work for putting things in the array but it does work for putting in the number.
void insertAsFirstElement(node *&head, node *&tail, int number){
node *temp = new node;
temp->number = number;
cout<<temp->number<<endl;
temp->next[0] = tail;
cout<<temp->next[0]<<endl;
head->next[0] = temp;
cout<<head->next[0]<<endl;
}
Please help me.
The -> operator is a shorthand.
Without the -> operator, you would write
(*var).prop;
With the -> operator, you write:
var->prop;
Thus, to store a node in the first position of the list, you write:
void StoreNode(node *node){
node *temp = new node;
temp->next[0]=node;
}
And to retrieve data from a node in the list, you can write:
temp->next[0]->number
which is the same as writing
(*temp).next[0]->number
which is the same as writing
( *((*temp).next[0]) ).number
This line of your code seems a little confused:
void insertAsFirstElement(node *&head, node *&tail, int number){
Remember, you are just passing your function the address of a node. Therefore, all you need is
void insertAsFirstElement(node *head, node *tail, int number){
Inside the function itself, you will have to find the correct location in the list, that is when you get into the ** notations.
The code at a first look seems ok. An array of pointers is just that, an array of elements where each one is a pointer, and you use it exactly with the syntax your code shows.
Note however that when declaring an array of pointers inside a class the elements are not automatically initialized so you probably want to fix the elements that are not used yet to NULL. Moreover in a skip list you're probably going to need to know at which "level" the node has been inserted.
Are you sure your problem is in that part? Often with C++ a mistake doesn't appear right in the point it's done, but much later. This happens because of the "undefined behavior" rule of the language (aka "programmers never make mistakes").