Linking head and tail in a self-implemented queue C++ - c++

Doing a self-impl queue in C++. The question is about adding the first element. I know there's an obvious way of ckecking if head is NULL then we also change head, if no then we don't touch it. But I was told there's another way which I didn't understand. The example was like this:
first = (QueueNode*)&last;
then I should assign last element and no if-check required. But it actually doesn't work, so is there a way to implement what I'm talking about and what did I get wrong?
struct QueueNode
{
T data;
QueueNode* next;
} *first, *last;
edit:
The usual way we implement Enqueue operation is
void Enqueue(T data)
{
QueueNode* node = new QueueNode();
node->data = data;
node->next = last;
last = node;
if (first == NULL) first = last; // <- THIS is what I want to get rid off
}

The error is here:
first = (QueueNode*)&last;
where :
struct QueueNode
{
T data;
QueueNode* next;
} *first, *last;
you already declare last as pointer, then when you assign it to first you dereference again this pointer.
So you have a pointer to pointer to the QueueNode struct.

Related

Passing a linked list without memory leak in C++

In many occasions, we need to modify a linked list drastically so we will sometimes create another linked list and pass it to the old one. For example,
struct node { //let's say we have a linked list storing integers
int data;
node* next;
};
and suppose we already have a linked list storing integers 1,2,3.
node* head; //suppose we already store 1,2,3 in this linked list
node* new_head ; //suppose we make a temporary linked list storing 4,5,6,7
head = new_head; //modifying the original linked list
My Question
If I delete head (the old linked list) before the assignment then the whole program will crash.
Conversely, if I do not delete it, then there will be a memory leak.
Therefore, I am looking for a way to modify the linked list without memory leak.
My attempt
I tried to make a helper function similar to strcpy to do my work.
void passing_node(node*& head1, node* head2){ //copy head2 and paste to head1
node* ptr1 = head1;
for (node* ptr2 = head; ptr2 != nullptr; ptr2 = ptr2->next)
{
if (ptr1 == nullptr){
ptr1 = new node;
}
ptr1->data = ptr2->data;
ptr1 = ptr1->next;
}
}
// note that we assume that the linked list head2 is always longer than head1.
However, I still got a crash in the program and I cannot think of any other way to modify this. Any help would be appreciated.
Easier way to avoid memory leak is to avoid raw owning pointers.
You might use std::unique_ptr (or rewrite your own version):
struct node {
int data = 0;
std::unique_ptr<node> next;
};
You can move nodes.
You can no longer copy nodes (with possible double free issue).
so deep_copy might look like:
std::unique_ptr<Node> deep_copy(const Node* node)
{
if (node == nullptr) return nullptr;
auto res = std::make_unique<Node>();
res->data = node->data;
res->next = deep_copy(node->next.get());
return res;
}
I would suggest preallocating the linked list so it's easy to delete every node in one call. The nodes would then just reference somewhere inside this preallocated memory. For example:
struct Node
{
int value;
Node* next;
};
struct LinkedList
{
Node* elements;
Node* first;
Node* last;
Node* free_list;
LinkedList(size_t size)
{
first = nullptr;
last = nullptr;
elements = new Node[size]{0};
free_list = elements;
for (size_t i = 0; i < size-1; ++i)
free_list[i].next = &free_list[i+1];
free_list[count-1].next = nullptr;
}
~LinkedList()
{
delete[] elements;
}
void Add(int value)
{
if (free_list == nullptr)
// Reallocate or raise error.
// Take node from free_list and update free_list to
// point to the next node in its list.
// Update last node to the new node.
// Update the first node if it's the first to be added.
}
void Free(Node* node)
{
// Search for the node and update the previous and
// next's pointers.
// Update first or last if the node is either of them.
// Add the node to the last place in the free_list
}
};
From here you'll have many strategies to add or remove nodes. As long as you make sure to only add nodes to the allocated elements array, you'll never have any memory leak. Before adding, you must check if the array have the capacity to add one more node. If it doesn't, you either have to raise an error, or reallocate a new the LinkedList, copy over all values, and delete the old one.
It becomes a bit more complicated when the array becomes fragmented. You can use a 'free list' to keep track of the deleted nodes. Basically, a LinkedList of all nodes that are deleted.
Just take notice that my code is incomplete. The basic approach is to create an allocator of some sort from which you can allocate a bulk, use segments of it, and then delete in bulk.

double linked list head dereferenced is null

my head pointer is supposed to be null, because I don't want
it to have any value when I make my linked list.
I know that you can't dereference something that is null,
but I just want to point it's next node to something new.
can someone explain how I could point the head node pointer?
void dlist::push_front(int value) {
node *p = new node();
node *tempH = head();
tempH->next = p; //break
/***********************************************************
my head pointer is suposed to be null, because I don't want
it to have any value when I make my linked list.
I know that you can't dereference something that is null,
but I just want to point it's next node to something new.
can someone explane how I could point the head node pointer?
************************************************************/
p->value = value;
p->next = tempH->next;
p->prev = tempH;
p->next->prev = p;
p->prev->next = p;
}
#pragma once
#include <ostream>
class dlist {
public:
dlist() {}
// Implement the destructor, to delete all the nodes
//~dlist();
struct node {
int value;
node* next;
node* prev;
};
node* head() const { return _head; }
node* tail() const { return _tail; }
void push_front(int value);
private:
node* _head = nullptr;
node* _tail = nullptr;
};
in your list constructor, simply set the head pointer to null.
dlist::dlist() {
_head = nullptr;
}
Further, if you end up removing the LAST item in your list, you will need to also make _head = nullptr;
Be sure to check if the head is null before dereferencing.
if(_head == nullptr){
_head = new node(...);
}
Your insert function will be responsible for assigning the first node to the head, in the event that you're adding to an uninitialized list.
If your list needs to be sorted, you will need to account for the head changing in the event that the new node should precede the head node.
The most practical solution here is to just use sentinel nodes for your head and tail. Or, just one sentinel node, that stands in for both. The sentinel nodes' elements can just be left uninitialised, you only need those nodes for the next and prev pointers they contain. To test if you've reached the end of the list, instead of testing for a null pointer, you test whether the pointer points to the sentinel node.
You can just use normal nodes as your sentinels if you expect your list elements to be small, or your lists to be very large. You waste a bit of memory on space for elements that won't be used, but it's probably not a big deal. If you really care about memory efficiency (say, you're writing a library), you can have something like this:
template<typename T> class dlist {
struct node_header {
node_header* next;
node_header* prev;
};
struct node : public node_header {
T element;
};
// Convert a node_header pointer to a node pointer
node* node_from_header(node_header* p) {
return static_cast<node*>(p);
}
};
With this approach, your sentinel node is a node_header and all your actual, element-containing nodes are nodes. Your internal algorithms all work on node_headers, until you need to actually retrieve the element of a node, at which point you use node_from_header() to retrieve the full, element-containing node.
If you absolutely want to not use sentinel nodes, you'll have to rewrite your code to directly use the head pointer, rather than retrieving it through a function, and add special-case code for handling a null head pointer. It's not a pretty option.

Having a little trouble with pointers

The below is meant to reverse a linked list. It seems to work till it gets to the last line. When I debug, both "current" and "result" are of the same type (Node*) and "result" is the list reversed. But when the function completes, current only has the first value of the "result" list. Anyone know why "current" is not the full list when the function completes?
struct Node {
int data;
Node* next;
};
void reverseList(Node** head)
{
Node* current = *head;
Node* result = NULL;
while (current != NULL)
{
Node* temp = current;
current = temp->next;
temp->next = result;
result = temp;
}
current = result;
}
There are multiple problems with the shown logic.
We can start with the obvious observation that the goal of reverseList is, apparently, to reverse a singly-linked list.
The second observation is that the function takes a single parameter, a pointer to the head node, and it returns a void.
From, that we conclude that the function should update the head node, but there's nothing in the code that does that.
Additionally, there's really no reason why this function should take a double pointer like that, a pointer to the head node, and update it. It's much simpler for the function to take an ordinary pointer to the first element of the list, the existing head pointer, and then return the head pointer of the reversed list.
With this simple change, the resulting logic becomes much, much shorter and simpler:
Node *reverseList(Node *head)
{
Node *current=NULL;
while (head)
{
Node *next=head->next;
head->next=current;
current=head;
head=next;
}
return current;
}
That's it.
you need to update the head at the end of your algorithm:
current = result;
*head = current;

C++ linked list stack using pointers

So I have a stack with the typical Push and Pop functions that it allows. I'm having a hard time wrapping my head around how it all actually works code-wise. I saw this post here,
Picture/Diagram in the best answer that shows how the list is "pushed" down and you point at the newest element. I have a
node* stack;
which is hooked to a struct "node"
struct node
{
ItemType data;
node* next;
};
How do I incorporate a push and pull with a "node* next;" ? The hard part to wrap my head around is how I'm going to actually do it. I know it initially points at null, and then if I were to push a 2,4,6 it would be 6,4,2,#. Grasping how to actually do it with pointers in a linked list throws me for a loop. I can do it without pointers but the pointers are what get me. Thank you for any help, I really wanna work through this. I'm here to comment back too quickly. Thanks!
EDIT 1:
solved - my push is working
EDIT 2:
I'm trying to pop now. Would that mean I have to just aim my pointer at the next value? What do I do to the old top node? delete it since I new'd it?
It looks like a C question.
Functions push can be defined in C++ the following way
void push( node * &stack, const ItemType &item )
{
node *tmp = new node { item. stack };
stack = tmp;
}
in C it can look like
int push( struct node * *stack, const ItemType *item )
{
node *tmp = malloc( sizeof( struct node ) );
if ( tmp )
{
tmp->data = *item;
tmp->next = *stack;
*stack = tmp;
}
return tmp != NULL;
}
EDIT: After you edited your post I also edited my post.
It seems that pointer stack is a data member of class StackClass. In this case the member function can look like
void StackClass::Push( ItemType newItem )
// I would declare the parameter as const ItemType &newItem
{
node* temp = new node;
temp->data = newItem;
temp->next = stack;
stack = temp;
}

C++ Classes - What is wrong with my program?

Insert is a method which appends an item to the end of my linked list.
Can't figure out how to code for the case where Node is null, and I just want to add to it.
struct Node{
int data;
Node *next;
Node(int data):data(data),next(NULL){}
void insert(int data){
if (this==NULL){
this=new Node(data); // compiler is complaining here.
// how would I go about setting the value of this (which is presently NULL) to a new Node?
}
}
}
you can not assign a value to this pointer which is a special keyword and should always point to a valid block of memory. by looking at your usage, could you be trying to mean this:
void insert(int data){
if (!next){
next = new Node(data);
}
Something like this:
void insert(int data)
{
Node* newNode = new Node(data);
if (next!=NULL)
newNode->next = next;
next = newNode;
}
You cannot assign directly to 'this'; what you need to consider is how to represent an empty list, most likely by:
Node* head = 0;
So you add the first node by
head = new Node(data);