Adding elements to the front of a queue without using STL - c++

I am trying to add some elements to the front of an queue that already has other items.My code works fine but it adds the item in front everytime. How can I modify it to add the next item after the front added one. This is what i got:
void Queue::addtoFront(string first, string last){
Node *temp = new Node(first, last, NULL);
temp->next = head;
head = temp;
}

Note: I'm not sure what you are trying to achive, but you could write a 'insertAfter' member function. This function takes a new element and inserts it immediately after a given element in the linked list.
To do so you must first set up the 'next' link of the new element, then insert the new element immediately after the requested element.
void Queue::insert(Node *newElement, Node *insertAfter)
{
_ASSERT(insertAfter != nullptr);
_ASSERT(newElement != nullptr);
// set the 'next' of the new element to the 'next' of the insertAfter
newElement->next = insertAfter->next;
// now insert the new element immediately after the 'insertAfter'
insertAfter->next = newElement;
}
// Taken from the original post...
// Of course, "addToFront" is no longer the correct name for this function,
// since it does no longer add the element to the front
void Queue::addToFront(...)
{
if (head==nullptr) {
// see original post above
} else {
// insert new element at the 2nd position in the queue,
// immediately behind the head
insert(temp, head);
}
}
For further study you could read about linked lists and have a look at the std::list interface. And you might want to improve your code with shared_ptr/unique_ptr instead of using Node*. In modern C++ you would almost never use
Node *element=new Node();
This is just bad code most of the time. Managing pointers and object lifetime by yourself is an
invitation to all sorts of nasty problems (memory leaks, access violations,
shallow vs. deep copy problems, failure to free objects esp. after exceptions etc...). Using managed or smart pointers make your life a lot easier:
shared_ptr<Node> element(new Node());
// or even better
shared_ptr<Node> element=std::make_shared<Node>();
Note: "managed/smart pointers" have nothing to do with C#/C++ managed code. The name simply says that there is a class (shared_ptr) that does some kind of automatic management and takes some of the burdon of you.

Related

Reverse a linked list, is my idea correct?

I was reading this: https://www.geeksforgeeks.org/reverse-a-linked-list/
I think I found an easier answer but since it wasn't written their and they used more complicated one I think something is wrong with mine and can't figure it out.
We start from the first node which we will copy and insert it into a new list.
then we go one step to the right, copy the value, create a new list with that value and setting its right the previous list and so on.
What's wrong with my algorithm?
If I interpret your idea correctly, it is something like this:
void forward_list::reverse() {
forward_list new_list;
for(auto& v : *this)
new_list.emplace_front(std::move(v));
std::swap(new_list, *this); // or *this = std::move(new_list);
}
... and this would work. It even looks pretty nice I'd say.
What's wrong with my algorithm?
It's creates a new node for every old node and then has to copy/move the data from the old node to the new node. The old nodes will then be destroyed.
Some types aren't even copyable or moveable so this reverse algorithm couldn't be used with such types.
It invalidates references and iterators.
Consider the alternative, reversing the links. It's a bit more complex but gets the job done without any of the drawbacks mentioned above.
Here's my take on reversing the links, which is not implemented exactly the same way as in the link you shared but it works pretty much in the same way. I think this one has fewer assignments though.
curr will point one step ahead of head and next is used to save the next pointer when the relinking is being done.
void forward_list::reverse() {
if(head) { // must have at least one node
node* curr = head->next; // head + 1
head->next = nullptr; // this will be the new last node
node* next; // for saving next while relinking
while(curr) { // while curr != nullptr
next = curr->next; // save the next pointer
curr->next = head; // relink backwards
head = curr; // move head forward
curr = next; // move curr forward
}
// head now points at the new start of the list automatically
}
}
Your algorithm is functionally correct, but since you are creating an entirely new list instead of reversing the existing nodes in-place, you are using twice the memory. You also have to deal with the cleanup of deleting the old nodes once you have your new list.

Exception thrown when writing an insert function for sLinkedList

I am writing a "insertBefore" function. I am checking to see if it is firstly the start of the function (This works). I then am trying to have my previous iterator point to the desired location by going through the entire list until its next is equal to the iterator passed into the function (i.e the place I want to insert in front of).
Now previous is where I want it I am trying to make its next point to the new node (the one I passed into the function) and the new node point to the old iterator after it.
Ive tried swaping the iterators instead.
template <typename T, typename InputIterator>
void SLinkedList<T, InputIterator>::insertBefore(InputIterator & t_position, T t_element)
{
//Q1
SListNode<T>* temp = t_position.get();
SListNode<T>* previous = m_head.get();
std::unique_ptr<SListNode<T>> newNode = std::make_unique<SListNode<T>>(t_element, this);
//If position is the head node
if (t_position.get() == m_head.get())
{
insertFirst(t_element);
}
else
{
while (previous != temp)
{
previous = previous->next().get();
}
if (previous == temp)
{
previous->setNext(newNode);
newNode->setNext(temp->next());
}
}
This should insert the new number I passed to insert itself into the list before the iterated position.
I suspect
previous->setNext(newNode);
is causing the issue. unique_ptr<> is moveable but not copyable. So, assuming your function setNext() did move the newNode, calling newNode->setNext() is ill formed.
And if you didn't move it (e,g - const unique_ptr<> &), then the address is being deleted once the unique_ptr goes out of scope (accessing invalid address).
You use a local variable
std::unique_ptr<SListNode<T>> newNode;
as soon as you go out of scope of void insertBefore (end of the function), this newNode will get deleted. As such, the whole list will become in an inconsistent state, and if setNext moved the value, then newNode is invalid after the first line:
previous->setNext(newNode);
newNode->setNext(temp->next());

Why can't a node in a linked list be responsible for deleting itself? (C++)

My idea is that once the first node is deleted from the linked list class then the rest will follow. My implementation does not work in practice. Is there solution to deleting a whole list node by node instead of the linked list deleting all of them? Should my nodeT have a destructor?
Linked list implementation:
#include <iostream>
#include <cassert>
#include "nodeT.h"
class linkedListSort
{
public:
int print();
//Function to output the elements of the list
//Postcondition: Elements of the list are output on the
// standard output device. Member current is reset to beginning node
// and currentIndex is reset to 0
//Returns: number of items printed in the list
// also outputs error if number of items printed
// does not equal the length of the list
void insertAt(int location, elemType& insertItem);
//Function to insert an item in the list at the
//position specified by location. The item to be inserted
//is passed as a parameter to the function.
//Postcondition: Starting at location, the elements of the
// list are shifted down, list[location] = insertItem;,
// and length++;. If the list is full or location is
// out of range, an appropriate message is displayed.
linkedListSort(int size = 100);
~linkedListSort();
protected:
//consider making const
nodeT<elemType> *beginningNode; // handle to the beginning of the list
nodeT<elemType> *current; // pointer to current node
int currentIndex; //int representing which node in the list current is pointing to
int length; //to store the length of the list
int maxSize; //to store the maximum size of the list
};
template <class elemType>
linkedListSort<elemType>::linkedListSort(int size)
{
if (size < 0)
{
cerr << "The array size must be positive. Creating "
<< "an array of size 100. " << endl;
maxSize = 100;
}
else
maxSize = size;
beginningNode = NULL;
current = NULL; // initialize to empty linked list
length = 0;
currentIndex = -1; // there is no item that current points to
}
template <class elemType>
linkedListSort<elemType>::~linkedListSort()
{
delete beginningNode; // this should delete all linked list items ( see nodeT destructor )
}
linked list node implementation:
template <class elemType>
class nodeT {
public:
nodeT(elemType& infoParam, nodeT<elemType> *linkParam); //standard
nodeT(elemType& infoParam); //if unlinked node (ex. last item)
nodeT();
//copy constructor
nodeT(nodeT<elemType>& node);
~nodeT();
elemType *info;
nodeT *link;
};
template<class elemType>
nodeT<elemType>::nodeT(elemType& infoParam, nodeT<elemType> *linkParam) {
info = &infoParam;
link = linkParam;
}
//when link is null (last item and uncircular)
template<class elemType>
nodeT<elemType>::nodeT(elemType& infoParam) {
info = &infoParam;
link = NULL;
}
//in case node is needed before info or link is known (default)
template<class elemType>
nodeT<elemType>::nodeT() {
info = NULL;
link = NULL;
}
template<class elemType>
nodeT<elemType>::nodeT(nodeT<elemType>& node) {
info = new elemType();
if (node.link != NULL)
link = new nodeT();
*info = *(node.info); // copy by value
if (node.link != NULL)
*link = *(node.link);
else
link = NULL;
}
template<class elemType>
nodeT<elemType>::~nodeT() {
delete info;
if (link != NULL)
delete link;
}
The last part of the node implementation is the node destructor. If the member of nodeT link is of type nodeT then the code delete link will call the same destructor but just on another instance. Therefore each node should destroy itself once the first node is destroyed. The first node is destroyed in the linked list implementation as such: delete beginningNode where beginningNode always points to the first node in the linked list.
Am I close to a solution? Or am I just going down a rabbit hole that C++ doesn't want you to go down?
The actual error has to do with an assertion failing. Then eventually I can copy this to my clipboard: "Unhandled exception at 0x553056E8 (msvcr120d.dll) in chap10Ex1.exe: 0xC0000005: Access violation reading location 0x00000002."
Technically your nodes aren't responsible for deleting themselves, they're responsible for deleting the next node in the list.
This may seem attractive, but there are some implications here that you may not have considered. First, what #WhozCraig said in a comment that you're going to end up building quite a deep call stack of destructors for a big list.
Secondly, if you managed to build yourself a circular link chain you're going to go all the way round it and then hit undefined behaviour when you try to delete the first node for the second time. Nothing in your code prevents that kind of misuse - these kinds of guarantees are one of the advantages of using a container class for the list which hides the operation of the nodes themselves from the clients.
I think there's also an issue here about ownership. Nodes don't allocate each other, but they are responsible for deleting each other, which means that each node owns the next node in the list. This may not be obvious from the API you provide, which requires the user of the list to create new nodes, but then when you add them to the list the list takes responsibility for deleting them. This means in client code there's no balance between new and delete, which is going to look a bit odd.
However, much worse in ownership terms is that the list node destructor calls delete info, which is created in one of the constructors as the address of a reference passed in which might not even be on the heap. You can't tell, nobody's made any promises there. At the very least you need to accept a pointer instead of a reference, as that's a hint that an ownership transfer is happening. Even better would be to accept a std::unique_ptr<elemType>, which makes the transfer of ownership very explicit (you can still provide access to the contents via a raw pointer).
In general I would advise that if a data structure is going to take responsibility for deleting something that data structure should also be responsible for creating it. Otherwise, you should leave it alone. STL containers don't delete contained pointers - if you delete a std::vector<int *> you have to delete all the int * members yourself first. This gives the user flexibility - they don't have to store pointers to things which are on the heap - and it means it's consistent - those responsible for creating something should, in general, also be responsible for disposing of it. It also means the std::list<T> can contain any T - including pointers. What happens if you try to instantiate a nodeT<int *>? What happens when its destructor runs?
So I'd say if you're going to have nodes deleting each other you should also have nodes creating each other (and don't let the user do it). And if you're going to have nodes deleting their data items you should most definitely also be creating those data items. Or better, just leave that alone and don't touch the lifecycle of something passed to you by reference.

Linked ArrayList Implementation

I am trying to implement a Linked ArrayList in C++ for instruction purposes, I've hit a snag though and I'm unsure how to unsnag it. My pointer array doesn't seem to be composed of pointers, but of actual objects.
Keeping my code as brief as possible.
//arraylist.h//
class classArrayList {
private:
class Node {
Node();
//accessors
};
Node* classArray;
public:
classArrayList();
};
//arraylist.cpp//
classArrayList::classArrayList() {
Node* node = new Node();
this->setHead(node);
this->setMaxSize(5);
classArray = new Node[5];
this->classArray[0] = *node;
this->setSize(1);
}
void classArrayList::deleteNode( int index ) {
Node* my_current = &this->classArray[index];
//blahblah
}
But when I go to delete a node, "my_current" doesn't link to whatever would be next or prev in this list. Trying to delete at position zero, no next.
So there's definately a node with data but it doesn't have its links, but checking the debugger my linked list is fine and works, so its whatever the array is pointing to that's screwing up.
So instead of pointing to the list, its pointing to unique instances, how can I fix this?
My code to add something new to the array is: this->classArray[some_index] = *new_node;
To clarify, I wanna be able to have an array that points sequencially to each object in my linked list. And then when I ask for one at any n in my arraylist, reference it to a pointer and then do thins to the object in my list through its position in the array, rather than increment through the list until I find the nth one I want.
Make your classArray a double pointer and create a Node pointer array. Node* classArray; Copy the address of head of your list to each array.
classArray = new Node*[5];
In your code by your statement this->classArray[0] = *node; you are not storing the address of the newly created, instead content of newly created node. And by deleting you are not removing the dynamically created list head.
For copying the address of newly created list you should use
this->classArray[0] = node;
The code works as it should. When you delete a node from your linked list, you delete the data under the pointer. As you set my_current to the address of the deleted node, you actually don't point to anything. The problem doesn't lie in the code, but in your understanding of the subject.
In order to really make a working linked list, every node should consist of a pointer to the next node. That way, when you delete a node, you'll first be able to retrieve the next node from the pointer, and set your my_current to a valid address.
In order to solve your problem, you should actually read a bit about the subject.
If you want to access the elements in "array style", overload the operator [].
Node& classArrayList::operator [](unsigned int index)
{
Node *node = head;
for(unsigned int i=0;i<index;i++)
if(node->next()) node = node->next();
else break;
return *node;
}

Inserting Before/After Node in Linked List

I am trying to insert nodes in a list based on the value of a data member. Basically, if the member isVip evaluates to true, that node gets precedence, and should be inserted ahead of any regular node (but behind any existing VIP nodes). Regular nodes simply get added at the end of the list.
I'm pretty sure I have a good idea of how to use two pointers to step through the list and insert elements for n > 2 where n is the number of current list members, but I'm sort of conceptually stuck for the case when there's only one node.
Here is my working version of code below:
void SelfStorageList::rentLocker(Locker e) {
int count = 0;
LockerNode *p = head;
if (isEmpty()) {
head = new LockerNode(e);
tail = head;
}
for(;p!=0;count++, p=p->next) {
if(count == 1) {
if (e.isVip) {
if(p->objLocker.isVip) {
LockerNode*p = new LockerNode(e, p->next);
}
}
}
}
As you can see, I'm checking to see if the passed in object is VIP, and then whether the current one is. Here, I've hit some trouble. Assuming both are VIP, will this line:
LockerNode*p = new LockerNode(e, p->next);
put the passed in locker object in the correct place (i.e. after the current VIP one). If so, would:
LockerNode*p = new LockerNode(e, p);
equivalently place it before? Is the use or absence of the 'next' member of the node what defines the placement location, or is it something entirely different?
Hope someone can clear my doubts, and sorry if it seem a foolish question! Thanks!
Simply iterate over the list while the next node have isVip set (current->next->isVip). After the iteration, the last node visited will be the last with isVip set, and you should insert the new node after that one.
It can be implemented in fewer lines, without the explicit isEmpty check, and without any counter. Even less than that if you use a standard container instead.