inserting node function confusing - c++

I'm trying to understand this function to insert an element into a linked list of sorted integers in ascending order, however, there are parts of the code that are confusing me...
Node* insert (int x, Node *p) {
if (p==nullptr)
return cons(x,nullptr); //inserts the new node at front of list,before node with nullptr?
if (x < = p-> val)
return cons(x,p); //this also inserts node at front of the list?
//now the rest of the function is where I get confused...
Node *prev=p; //so this is not allocating new memory, so what exactly does it mean?
Node * after=prev->next;
//prev->next is pointing at whatever after is pointing to but after has no address?
while (after!=nullptr && x > after->val) { //whats going on here?
prev=after;
after=after-> next;
}
prev->next=cons(x,after);
return p;
}

Node* insert (int x, Node *p) {
if (p==nullptr)
return cons(x,nullptr);
//inserts the new node at front of list,before node with nullptr?
if (x < = p-> val)
return cons(x,p); //this also inserts node at front of the list?
The code above takes care of inserting the new element at the beginning of the linked list. There are two instances for this to happen:
if the head, which is p in this case, is NULL.
if the element that p is pointing to has a value greater than the current element to be inserted.
Now going forward...
//now the rest of the function is where I get confused...
Node *prev=p;
//so this is not allocating new memory, so what exactly does it mean?
This is just like a temporary pointer which can be used to traverse the linked list. So you store the head 'p' in the prev pointer.
Node * after=prev->next;
//prev->next is pointing at whatever
//after is pointing to but after has no address?
This is a pointer that would store the next element of head.
while (after!=nullptr && x > after->val) { //whats going on here?
prev=after;
after=after-> next;
}
prev->next=cons(x,after);
return p;
}
Here, this looks a little buggy. You might want to do something like this, instead:
While(prev->data >= inputdata && (after->data < inputdata || after == NULL)
{
//insert your inputdata here because it is greater than the previous but less than after
// or after is NULL.
}
I hope this clarifies your confusion. Let me know if you have any questions.

Related

Indexed singly linked list

I want to create a singly linked list with. I already have an implementation that does not permit indexing on it.
I would like to add this feature but I am not sure how to do that.
So basically the head should have index "1". But I can't figure it out myself what am I supposed to do in If statement to increase the index by 1 each step.
void AddNode (int addData)
{
nodePtr NewNode = new node;
NewNode->next = NULL;
NewNode->data = addData;
if (head != NULL)
{
curr = head;
while(curr->next != NULL)
{
curr = curr->next;
}
curr->next = NewNode;
NewNode->index;
}
else
{
head = NewNode;
NewNode->index = 1;
}
}
You mean for the ability to do something like get a linked list node via a get(index)?
Also, your head should not have index 1, it should be 0. This does not comply with standard practice of zero-based indexing.
A linked list does not technically have indexes nor should it store them. It seems like a linked list might not be the right data structure for what you are doing, however you can treat it like so with a loop like this (excuse if my c++ syntax is rusty)
int get(int index) {
Node current = head;
for (int x = 0; x < index; x++) {
if (current->next == null) {
//some sort of error handling for index out of bounds
} else {
current = current->next;
}
}
return current->data
}
get(2) would return the 3rd element of the list.
Graph for the structure
Why do you want to add it to the end of the list? Just simply add the new node to the front.
I don't think it is necessary to follow the order of 1,2,3.... Instead, you can do it reversely
Before you add a new node, you visit the head and find the index(i)of it. When you add the new one, the index of this one will be i+1.
Two advantages:
- It doses not change anything when you loop through this list.
- You know how many you have added into this list.
So what you really want to do is to add the ability to index elements of a linked list.
There is no need to actually store the index anywhere (as you don't really store the index of an array/vector element as the type and the address of the first element of the array is everything you need to retrieve the i-th element).
The only information you want to keep is the length of the list since computing it is costly because you have to traverse the list from head to tail every time you need it. Once you have this information the addNode should only update the size of the list.
As you already know accessing the i-th elements of a linked list is also costly (compared to a vector), but it is easy to code.
Something like the following should work:
void get(Node* head, size_t pos) {
while (head && pos--)
head = head->next;
return pos<=0 ? head : nullptr ;
}
It traverses the list from the head until it either reaches the end (head is nullptr) or pos is <=0.
Once you are out of the loop if pos>0 means that the list is shorter than pos otherwise you can return head (which will point to the pos-th element)

Using an array of pointers-to-pointers to manipulate the pointers it points to (C++)

I've been doing this as an exercise on my own to get better at C++ (messing around with a linked list I wrote). What I want to do is to reverse the list by twisting the pointers around, rather than just 'printing' the data out in reverse (which is relatively straightforward).
I have an array of pointers-to-pointers, each pointing to a node in a linked list. But this is less a question about linked-list dynamics (which I understand), and more about pointer magick.
A node looks like this,
template<class T>
struct node {
T data;
node *next;
node(T value) : data(value), next(nullptr) {}
};
And the code in question,
node<T> **reverseArr[listLength];
node<T> *parser = root;
for (auto i : reverseArr) {
i = &parser;
parser = parser->next;
}
root = *(reverseArr[listLength - 1]);
for (int ppi = listLength - 1; ppi >= 0; --ppi) {
if (ppi == 0) {
(*reverseArr[ppi])->next = nullptr;
//std::cout << "ppi is zero!" << "\t";
}
else {
(*reverseArr[ppi])->next = (*reverseArr[ppi - 1]);
//std::cout << "ppi, 'tis not zero!" << "\t";
}
}
My logic:
The new root is the last element of the list,
Iterate through the array in reverse,
Set the current node's next pointer to the previous one by setting the current node's nextNode to the next node in the loop.
What's happening:
If I leave the debug print statements commented, nothing. The function's called but the linked list remains unchanged (not reversed)
If I uncomment the debug prints, the program seg-faults (which doesn't make a whole lot of sense to me but seems to indicate a flaw in my code)
I suspect there's something I'm missing that a fresh pair of eyes might catch. Am I, perhaps, mishandling the array (not accounting for the decay to a pointer or something)?
You're overthinking the problem. The correct way to reverse a single-linked list is much simpler than you think, and does not involve arrays at all.
All you need to do is walk through the list setting each node's next pointer to the head of the list, then set the head of the list to that node. Essentially, you are unlinking each node and inserting it at the start of the list. Once you reach the end, your list is reversed.
It just requires a bit of care, because the order that you do things is important. Something like this should do it:
template <class T>
node<T> * reverse( node<T> * head )
{
node<T> *current = head;
head = NULL;
while( current != NULL )
{
// store remainder of list
node<T> *remain = current->next;
// re-link current node at the head
current->next = head;
head = current;
// continue iterating remainder of list
current = remain;
}
return head;
}
The operation has a linear time complexity. You would invoke it by passing your list's head node as follows:
root = reverse( root );
It should go without saying that it would be a bad idea to call this function with any node that is not the head of a list, or to pass in a list that contains cycles.

Deleting elements from doubly bounded pointer list

I am working on a project where I create a double bounded pointer list, delete several elements, and still be able to read off the list. I have a double bounded pointer list, but am having trouble deleting elements and keeping the list double bounded. This then causes issues when trying to print the list.
Below is the IF statement I've placed in a while loop to help delete unwanted elements. I keep getting a segmentation fault (core dumped).
if ((black2 != black)||(white2 != white)) {
dump = help;
help = help ->next;
dump -> before = temp;
temp -> next = help;
help ->before = temp;
delete dump;
}//if
else { temp = help;
help = help->next;
help ->before = temp; }//else
To maintain properly the doubly linked list you should do something like :
void remove(X *elt) {
X* before = elt->before;
X* after = elt->next;
if (before != NULL) { // assuming first element points to NULL
before->next = after;
}
else {
first = after; // assuming first is a pointer to first element of list
}
if (after != NULL) { // assuming last element points to NULL
after->before = before;
}
else {
last = before; // assuming last is a pointer to last element
}
delete elt;
}
That way, you ensure that elements around current correctly point to each other dealing with special cases of removing first or last element.
But you already have a std::list template in Standard Template Library
One logical issue in your code is the line dump->before = temp.
What this does is that it sets the previous node pointer of dump to temp, as opposed to defining temp as the previous node.
The correct line should read temp = dump->before
PS: Your code is correct assuming that the node you are deleting isn't the first or last node (and you haven't padded with dummy nodes). You should introduce checks for these cases if required.

Get smallest value from a linked list?

I am currently writing a piece of code which loops through a linked list and retrieves the smallest, but is not working. Instead it seems to be returning the last value I enter into the list...
(list is the head being passed from main)
int i = 0;
Stock *node = list;
int tempSmallest = (list + 0)->itemStock;
while (node!=NULL)
{
if ((list+i)->itemStock < tempSmallest)
{
tempSmallest = node->itemStock;
node = node->nodeptr;
}
i++;
}
return list;
Thanks for any advice!
You are dereferencing (list+i) and incrementing i with every visited node for some reason. I don't know why you're doing this, but it's wrong. You basically traverse the linked list and also conceptually traverse an array (which doesn't exist at all). This is undefined behavior and cannot give meaningful results.
You must dereferece the currently valid node, not an array element that is a few indices after it somewhere in RAM, and advance by the list's next node pointer (I assume this is called nodeptr in your code?).
Something like...
Stock *node = list; // hopefully not NULL since I don't check in the next line
int smallest = node->itemStock;
while(node && node = node->nodeptr)
smallest = std::min(smallest, node->itemStock);
return smallest;
struct stock{
stock *next;
...
};
this will be the struct of your nodes.
then when you initialize them, you should refer the next pointer of the last node added, to the node you're adding currently.
then the code will be like this:
stock *node = head; // the head you passed from main
int min = node->price;
for(;node;node=node->next)
{
if(node->price < min)
min = node->price;
if(!node->next)
break();
}
return min;

Nodes in binary tree are null

void MultiMap::insert(string key, unsigned int value)
{
if(head == nullptr)
head = new Node(key, value);
else
{
Node* tempNode = head;
while(tempNode != nullptr)
{
if(key <= tempNode->m_key)
tempNode = tempNode->m_left;
else if(key > tempNode->m_key)
tempNode = tempNode->m_right;
}
/*line 1*/tempNode = new Node(key, value);
//*line 2*/head->m_left = new Node(key, value);
}
}
For an assignment, I have to make a binary tree class, "MultiMap" with nodes that contain a string and an int.
The above is code to insert a new node into the tree. The nodes are sorted by their strings. If the string of the node I am trying to insert is > the current node, the program should try to insert it on the right branch of the tree, and if it is <=, the program should try to insert it on the left branch of the tree.
I tested it by trying to insert two nodes: (Joe, 5) and (Bill, 1) in that order, so if the program works properly, "bill" should be on the left branch of "joe".
Line 2 is commented out.
If I use line 1, the program compiles and "inserts" the second node, but when I try to look for it with other code, it only finds a nullptr. If I replace line 1 with line 2, the program works as expected.
"tempNode" is what I'm using to trace through the tree to find the appropriate place to insert a new node. "head" is a pointer to the first node in the tree. "m_left" and "m_right" are pointers to nodes, representing the left and right branches of a node, respectively.
I don't know why the two lines don't do the same thing even though at that point, it seems like tempNode and head->m_left are pointing to the same location in memory: the left branch of the first node.
Pointers are variables that hold addresses. There is nothing magic about them. Line 1 does this:
tempNode = new Node(key, value);
This doesn't insert anything into your tree. In fact, it just leaks memory.
What tempNode pointed to prior to this statement is irrelevant. More importantly, how tempNode held that prior value is already lost because you're already descended down the tree one level. Two pointers holding the same address just means the address is reachable with two pointers. Assigning a new address to a pointer has no effect on the previously addressed entity (if there was any).
Your task should be finding the pointer that should be filled in with the address of a newly allocated object. You found it (sort of). Unfortunately you also lost it as soon as you walked into it with your step "down" the tree for the final null-detection. As soon as this:
while (tempNode != nullptr)
becomes false and breaks, you're already one node too far. There are a number of ways to handle this. Some people like using a "parent" pointer, but that just means you have to special-case an empty map condition. Consider this instead:
void MultiMap::insert(string key, unsigned int value)
{
// pp will always point to the pointer we're testing
// i.e. a pointer to pointer.
Node **pp = &head;
while (*pp) // while whatever pp points to is a non-null-pointer
{
if (key < (*pp)->m_key)
pp = &(*pp)->m_left; // put address of left-pointer into pp
else if ((*pp)->m_key < key)
pp = &(*pp)->m_right; // put address of right pointer into pp
else break; // strict weak order match
}
if (*pp)
{
// found matching key. NOTE: unclear if you wanted to just update or not
}
else
{
// allocate new node.
*pp = new Node(key,value);
}
}
And you'll notice other than initializing our pointer-to-pointer with the address of the head node pointer, head is never referenced again.
Finally, notice there is no special-case head-node test. If the map is empty and the head pointer is NULL, this will automatically create a new node and make it the root.
What is going on here:
Node* tempNode = head;
while(tempNode != nullptr)
{
if(key <= tempNode->m_key)
tempNode = tempNode->m_left;
else if(key > tempNode->m_key)
tempNode = tempNode->m_right;
}
OK, now tempNode == nullptr, and it does not point to any node of the tree. As it is the variable on the stack, the next line:
/*line 1*/tempNode = new Node(key, value);
just initializes this local pointer and does not affect the tree itself. (Really here will be a memory leak.)
In your second line you initialize the node in the tree:
head->m_left = new Node(key, value);
But only for head->m_left.
So you can write:
if (key <= tempNode->m_key) {
if (tempNode->m_left == nullptr) {
tempNode->m_left = new Node(key, value);
break; // traverse tree loop
} else {
tempNode = tempNode->m_left;
}
}