C++ Linked List isEmpty Function - c++

I want to check, whether a linked list in C++ is empty or not. I have following class:
class IntLinkedList
{
private:
struct LinkedListNode // Structure for linked list
{
int value;
struct LinkedListNode *next;
};
LinkedListNode *head; // List head pointer
public:
IntLinkedList(void) // Constructor
{ head = NULL; }
~IntLinkedList(void); // Destructor
void AppendNode(int);
void InsertNode(int);
void DeleteNode(int);
void DisplayList(void);
bool isEmpty(LinkedListNode*);
};
// isEmpty function
bool IntLinkedList::isEmpty(LinkedListNode *node)
{
bool status;
node = head;
if ( node->next == NULL )
status = true;
else
status = false;
return status;
}
But I can't use this function in other class via an object of the same class.
How can I check the empty list using a function that would be accessible in another class through the object of the same class?

The error you are getting is caused by the fact that you declared your function as bool isEmpty(LinkedListNode) but you are trying to define it as bool isEmpty(LinkedListNode*). The difference is that in the definition you have a pointer, while in the declaration there is just an object. You have to pick one, as these are completely different things.
That said, I don't see why you need the argument at all to check whether your list is empty. Just drop the argument altogether and use if ( head->next == NULL ) - non-static member functions are always called through an instance of the class.
Just for completeness, first item in your list is pointed to by head, so in order to check if there is anything in the list, you should check if it is a null pointer:
bool IntLinkedList::isEmpty() const
{ //added const for const-correctness, should be added to declaration as well
return head == nullptr;
}

Following list.empty(),
Returns whether the list container is empty (i.e. whether its size is
0).
Two suggestions:
Have a size variable that checks for the number of nodes in your list, this way your isEmpty() is just return size == 0;
Or in your current implementation, just modify to:
bool isEmpty() {
return head == null; // if head is null, there's no node in list
}

Related

How to I switch this into using completely smart pointers?

I'm having trouble switching this linked stack file into using only smart pointers. I've tried some things and I just get loads of errors. Any help is appreciated. This is in C++ by the way.
There is supposed to be no raw pointers, no constructors not needed, and use of the auto keyword whenever possible.
Here's the code:
#include <new>
#include <string>
#include "PrecondViolatedExcep.h"
template <typename ItemType>
LinkedStack<ItemType>::LinkedStack(const LinkedStack<ItemType>& aStack) {
if (!aStack.topPtr) {
topPtr = nullptr;
}
else {
NodePtr origStackPtr(aStack.topPtr);
try {
topPtr = new Node<ItemType>(origStackPtr->getItem() );
NodePtr newStackPtr(topPtr);
origStackPtr = origStackPtr->getNext();
while (origStackPtr) {
newStackPtr->setNext(
new Node<ItemType>(origStackPtr->getItem())
);
newStackPtr = newStackPtr->getNext();
origStackPtr = origStackPtr->getNext();
}
}
catch (const std::bad_alloc&) {
while (!isEmpty() ) {
pop();
}
throw;
}
}
}
template <typename ItemType>
LinkedStack<ItemType>::~LinkedStack() {
while (!isEmpty() ) {
pop();
}
}
template <typename ItemType>
bool LinkedStack<ItemType>::isEmpty() const {
return !topPtr;
}
template <typename ItemType>
bool LinkedStack<ItemType>::push(const ItemType& newItem) {
try {
topPtr = new Node<ItemType>(newItem,
topPtr);
}
catch (const std::bad_alloc&) {
return false;
}
return true;
}
template <typename ItemType>
bool LinkedStack<ItemType>::pop() {
if(!isEmpty() ) {
NodePtr nodeToDeletePtr(topPtr);
topPtr = topPtr->getNext();
delete nodeToDeletePtr;
return true;
}
return false;
}
template <typename ItemType>
ItemType LinkedStack<ItemType>::peek() const {
// throw(PrecondViolatedExcep) {
if (isEmpty() ) {
std::string message("LinkedStack::peek() ");
message += "called on an empty stack.";
throw PrecondViolatedExcep(message);
}
return topPtr->getItem();
}
I hope the commentary on each piece of the answer demonstrates the principles well enough you can learn more than just these specific solutions.
Though you don't show the definitions of the class templates, it looks like LinkedStack<ItemType> has a private member topPtr, and you'd like to change its type from Node<ItemType>* to std::unique_ptr<Node<ItemType>>. Also, class template Node has member functions something like:
template <class ItemType>
class Node
{
// ...
// Either public, or Node befriends LinkedStack in some way.
explicit Node(const ItemType& value, Node* next = nullptr);
Node* getNext() const { return nextPtr; }
void setNext(Node* ptr) { nextPtr = ptr; }
// ...
// Probably private:
Node* nextPtr;
};
Changes to this Node template could look like:
template <class ItemType>
class Node
{
// ...
// Either public, or Node befriends LinkedStack in some way.
explicit Node(const ItemType& value)
Node(const ItemType& value, std::unique_ptr<Node> next)
: Node(value) { nextPtr = std::move(next); }
Node* getNext() const { return nextPtr.get(); }
void setNext(std::unique_ptr<Node> ptr) { nextPtr = std::move(ptr); }
void resetNext() { nextPtr = nullptr; }
[[nodiscard]] std::unique_ptr<Node> releaseNext()
{ return std::move(nextPtr); }
// ...
// Probably private:
std::unique_ptr<Node> nextPtr;
};
The member becomes a smart pointer because the Node "owns" the responsibility for cleaning up its "next" node, if any.
The pointer parameters of the two-argument constructor and setNext become smart pointers because calling each means the Node will take over responsibility for cleaning up that next Node. They need to use std::move to allow the member to actually take that responsibility from the parameter.
You might ask, shouldn't getNext return a smart pointer? No, because that would mean that calling getNext transfers responsibility for cleaning up the next node to the caller, and that's usually not what getNext is for. A raw pointer can still have its place, meaning a pointer to an object whose ownership is handled by something else, or possibly a null pointer. (When null isn't a possibility, we'd often consider changing from a raw pointer to a reference, which also implies ownership is handled by something else.)
Though for cases where we do want to take ownership back from a Node, I've added releaseNext(). It returns a unique_ptr to "give away" its responsibility, and in the process its own unique_ptr member becomes empty.
Finally, I've added resetNext as a way to reset the nextPtr back to null, more straightforward than passing an empty smart pointer to setNext. (And/or, we could overload a setNext(std::nullptr_t).)
Then Node can follow the Rule of Zero: It does not need to declare a destructor, copy constructor, move constructor, or any sort of assignment operator. Since it has a member of type std::unique_ptr<Node>, its implicitly-declared copy constructor and copy assignment members will be defined as deleted, meaning the compiler will complain about any code that tries to use them. But it will have working move constructor and move assignment operator, which are probably not needed but harmless.
Now to class template LinkedStack. It can't use the Rule of Zero since copying it should be allowed despite the unique_ptr member and should do a deep copy. So we'll go with the Rule of Five, as modified by the Copy and Swap Idiom:
template <class ItemType>
class LinkedStack
{
public:
LinkedStack() = default;
LinkedStack(const LinkedStack&);
LinkedStack(LinkedStack&&) = default;
LinkedStack& operator=(LinkedStack) noexcept;
~LinkedStack() = default;
friend void swap(LinkedStack& s1, LinkedStack& s2) {
using std::swap;
swap(s1.topPtr, s2.topPtr);
}
// ...
private:
std::unique_ptr<Node<ItemType>> topPtr;
};
The destructor is okay to default, so with the = default; above, you can delete your custom definition.
Assignment is defined per Copy And Swap:
template <class ItemType>
LinkedStack<ItemType>& LinkedStack<ItemType>::operator=(
LinkedStack rhs) noexcept
{
swap(*this, rhs);
return *this;
}
The copy constructor gets simpler:
template <typename ItemType>
LinkedStack<ItemType>::LinkedStack(const LinkedStack<ItemType>& aStack)
: topPtr() // initially null
{
if (aStack.topPtr) {
Node* origStackPtr = aStack.get();
topPtr = std::make_unique<ItemType>(origStackPtr->getItem());
Node* newStackPtr(topPtr.get());
origStackPtr = origStackPtr->getNext();
while (origStackPtr) {
newStackPtr->setNext(
std::make_unique<ItemType>(origStackPtr->getItem())
);
newStackPtr = newStackPtr->getNext();
origStackPtr = origStackPtr->getNext();
}
}
}
The loop uses raw Node* pointers because once the nodes are safely stored in the topPtr or in another Node, the constructor code no longer needs to worry about deleting them. But it does need to reassign the variables as the loop executes, so references won't do, and it also needs to detect when origStackPtr->getNext() returns a null pointer.
Your original needed the try-catch-rethrow because in case of an exception in a constructor body, the destructor for that class is not called. But destructors of its members and base classes are called. So now if an exception happens in the copy constructor body, the destructor for the unique_ptr member topPtr executes, which will take care of deleting the top Node. Destruction of that Node's unique_ptr member will likewise delete its next node if any, and so on recursively - all with zero lines of (your) code.
isEmpty does not need any change: the expression !topPtr also works with a unique_ptr, meaning "is not null".
A straightforward update of push just changes the new to a make_unique:
template <typename ItemType>
bool LinkedStack<ItemType>::push(const ItemType& newItem) {
try {
topPtr = std::make_unique<Node<ItemType>>(
newItem, topPtr);
}
catch (const std::bad_alloc&) {
return false;
}
return true;
}
However, I'd recommend getting rid of the try/catch and return value. A memory error is rare, so most code shouldn't be checking to see whether this push called one. Something that really does care ought to do a try/catch itself around whatever amount of code is most appropriate. This would reduce the body to just one statement.
And pop gets simpler:
template <typename ItemType>
bool LinkedStack<ItemType>::pop() {
if (!isEmpty()) {
topPtr = topPtr->releaseNext();
return true;
}
return false;
}
Notice in the topPtr reassignment statement, first releaseNext() is used to take responsibility for the second Node (if any) away from the top Node. Then that responsibility is immediately given to the topPtr variable by the assignment. This also means topPtr will delete what it previously pointed at, the top node being popped off. Since that top node no longer has a next node, nothing else gets deleted, and the stack ends up in the correct state just like in the old version.
peek() does not require any change. The topPtr->getItem() expression will work via the unique_ptr<T>::operator-> function. (But I'd suggest changing the return types of Node<ItemType>::getItem() and LinkedStack<ItemType>::peek() to const ItemType&, to avoid useless copies when ItemType is a class type.)

Modifying private pointer of object within same type (but different object) public method

I've been attempting to create a node class which mimics a node on a graph. Currently, storage of the predecessor and successor nodes are stored via a node pointer vector: std::vector<Node*> previous. The vectors for the predecessor/successor nodes are private variables and are accessible via setters/getters.
Currently, I am dealing with updating the pointer values when adding a new node. My current method to update the predecessor/successor nodes is through this method (the method is the same for successor/previous nodes, just name changes):
void set_next(std::vector<Node*> new_next) {
this->next.clear();
for (Node* node : new_next) {
this->next.push_back(node);
}
}
This works for the current node but I was wondering the best way to update the new_next nodes that are passed in, especially the most 'C++'-esque way to accomplish this. I have previously written a method which adds individual nodes to the successor/predecessor vector:
void add_next(Node* new_node, bool one_way = false) {
this->next.pushback(new_node);
if (!one_way) {
new_node->add_prev(this, one_way = true);
}
}
The one_way variable was used to determine the depth(?) of the add_next() call. If it is true, it will add to the successor set and then add to the predecessor set of new_node. Since the boolean value is set to false when the new_node->add_next() method call occurs, it will only add to the predecessor set and not attempt to call add_next()/add_prev() again. This solution does work, but I'd rather not have the one_way variable and would prefer that the method would be private.
Here is the structure of the class currently:
class Node {
private:
std::vector<Node*> previous;
std::vector<Node*> next;
boost::any data;
public:
std::vector<Node*> get_previous()
void set_previous(std::vector<Node*> new_previous)
std::vector<Node*> get_next()
void set_next(std::vector<Node*> new_next)
void add_prev(Node* new_node, bool one_way = false)
void add_next(Node* new_node, bool one_way = false)
}
Avoiding the one_way parameter, it seems my best solution would be to just create an add_next/add_prev method that only updates the current node, not the passed node, unlike the solution above. With this solution, when adding new nodes, I could call the inverse of the add_next/add_prev on the new node. However, I have an inkling there may be a better solution for this.
Thank you!
I think this should get you going (edge-cases left to you to figure out, if any):
template<typename T>
class Node {
// Everything made public for debugging purposes, change this to fit your needs
public:
std::vector<Node<T>*> previous;
std::vector<Node<T>*> next;
T data;
Node(T val) {
data = val;
}
void set_next(std::vector<Node<T>*>& new_next);
};
template<typename T>
void Node<T>::set_next(std::vector<Node<T>*>& new_next) {
next = new_next;
for (Node<T>* node : new_next)
node->previous.push_back(this);
}
int main() {
// Little proof of concept where 0 is parent to 1, 2, 3
Node<int> one = 1;
Node<int> two = 2;
Node<int> three = 3;
Node<int> zero = 0;
std::vector<Node<int>*> new_next = { &one , &two, &three };
zero.set_next(new_next);
return 0;
}
To sum up the differences:
Use templates, boost::any is non standard and is all around terrible for this task.
Leverage operators (= makes a copy of std::vectors).
Leverage reference types (this way you can modify the argument passed to your function).

Linked Lists Append To Tail

I am trying to create an appendToTail function which will add a node to the end of a singly linked list.
I am having trouble in adding a node if the head is NULL(the linked list is empty)
class Node {
private:
Node* next;
int data;
public:
Node(int d, Node* n = NULL)
: data(d)
, next(n)
{
}
void appendToTail(int);
//other trivial functions(getters and setters etc. ) defined and
//declared
};
void Node::appendToTail(int d)
{
Node* end = new Node(d);
Node* n = this;
if (n == NULL)
n = end;
else {
while (n->next != NULL)
n = n->next;
n->next = end;
n->next->next = NULL;
}
end = NULL;
delete end;
}
int main()
{
Node* n = NULL;
n->appendToTail(5);
std::cout << n->getData(); //getData() is a function which
//retrieves the Data member variable
}
I am expecting to get 5 but I am getting an error which appears to be caused because my node remains null.
Now with modern C++ idioms we use smart pointers instead of raw pointers, it gives you the benefit of RAII (Resource acquisition is initialization) mechanism. In addition if you want an elegant solution to your problem you should introduce a List class with which you can express more clearly the concept of an empty list. It would give something like this:
#include <memory>
#include <iostream>
class List
{
public:
class Node
{
private:
std::shared_ptr<Node> next;
int data;
public:
Node(int d):next(nullptr),data(d){}
inline int getData() const {return data;}
inline std::shared_ptr<Node> getNext() const {return next;}
friend List;
};
List():head(nullptr),tail(nullptr){}
void appendToTail(int );
inline std::shared_ptr<Node> getHead() const {return head;}
inline std::shared_ptr<Node> getTail() const {return tail;}
private:
std::shared_ptr<Node> head;
std::shared_ptr<Node> tail;
};
void List::appendToTail(int d)
{
auto newTail = std::make_shared<Node>(d);
if (head == nullptr)
{
head = tail = newTail;
}
else
{
tail->next = newTail;
tail = newTail;
}
}
int main()
{
List l;
l.appendToTail(5);
std::cout<<l.getHead()->getData();
}
But you should definitely prefer std::list<T> or std::vector<T>.
Unfortunately there several errors with your approach. Semantic errors and a logical error with your interpretation of a linked list. Let's start with your initial misunderstanding. You cannot add a new tail to an empty list. Because it is emtpy. Meaning, not yet existing. Only if some object is existing/instantiated you can add a tail. You cannot add something to not existing stuff. So your idea to start with a Node* n = nullptr cannot work logically.
Additionally you are dereferencing a nullptr (major bug). That is also the main problem of your code. Nothing works. You need an instantiated object, before you can call it's member functions.
So before you can populate the list, you need to create/instantiate it initially. So you need to explicitly create the first node in your main function with
Node* n = new Node (5)
Then the list is existing and from now on you can add new members with calling appendToTail.
There are more semantic errors in your code which have luckily no side effects.
You must not delete the 'end' variable in your function. You want to keep the newly allocated memory for the new tail. But you introduced an additional sematic error by setting 'end' to nullptr and then call delete. Deleting a nullptr is a noOp and will do nothing. So, although you have a semantic error, this will not cause any trouble.
There is more:
For a pointer to Null you should always use nullptr.
And, your
if (n == NULL)
is always false. Before that, you assigned this to n. This is never NULL. You can delete the if else. Keep the statements from the else, except the
n->next->next = NULL;
That's not necessary. The constructor did that already for you. As explained, the next 2 statements should also be elimanted.
Additionally you may want to read a little more on the concept of linked lists.
I hope I could help a little

Deleting an element from an empty queue?

I'm writing abstract data type of priority queue as a task for an university, which others are going to use. I have a function in my class dequeue, which deletes the first element in the queue and returns the data of this element. However when I try to delete an element from an empty queue, the program crashes. What should I do here ?
Here's the code if it helps:
#ifndef PRIORITYQUEUE_H
#define PRIORITYQUEUE_H
#include <iostream>
using namespace std;
const int max_queue_items = 1000;
template<class T>
struct node{
T data;
int priority;
node *next;
};
template<class T>
class PriorityQueue
{
public:
/*
Constructor that creates an empty queue.
*/
PriorityQueue(){
head = NULL;
size = 0;
}
/*
Adds an element to the queue.
Params:
data - data of the element
priority - priority of the element
*/
bool is_empty(){
if (size == 0){
return true;
}
return false;
}
bool is_full(){
if (size == max_queue_items){
return true;
}
return false;
}
/*
Adds an element to thq queue.
It gets inserted before the first element with
lower priority.
*/
void enqueue(T data, int priority){
node<T> * previous = NULL;
node<T> * now = head;
while (now != NULL && now->priority >= priority){
previous = now;
now = now->next;
}
node<T> * new_element = new node<T>;
new_element->data = data;
new_element->priority = priority;
new_element->next = now;
if (previous == NULL){
head = new_element;
} else {
previous->next = new_element;
}
size++;
}
/*
Removes the first element in the queue
*/
T dequeue(){
T data;
if (!is_empty()){
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
}
return data;
}
/*
Returns the priority of the first element.
It's always the highest priority in the queue.
*/
int get_first_priority(){
return head->priority;
}
/*
Returns the data of the first element in the queue.
*/
T get_first_value(){
if (is_empty())
throw 0;
return head->data;
}
/*
Returns the number of elements in the queue.
*/
int get_size(){
return size;
}
/*
Deletes the whole queue from the memory.
*/
void flush(){
node<T> * now;
while (head != NULL){
now = head;
head = head->next;
delete now;
size--;
}
}
/*
Prints the whole queue following this format:
data(priority)
*/
void print(){
node<T> * now = head;
while (now != NULL){
cout << now->data << "(" << now->priority << ")" << endl;
now = now->next;
}
}
private:
node<T> * head; // Pointer to the head of the queue
int size; // Number of elements in the queue
};
#endif // PRIORITYQUEUE_H
This may or may not be the source of your problem, but I would definitely consider it an issue. In function dequeue() you are potentially returning an uninitialized variable (if T is not a class type) when is_empty() returns true:
T dequeue()
{
T data; // Uninitialized if T is not a class type
if (!is_empty())
{
node<T> * now = head;
//--------------------------------------------------------------
// This initialization is skipped when `is_empty()` returns true
data = now->data;
//--------------------------------------------------------------
head = head->next;
delete now;
size--;
}
return data;
}
Depending on what you do with the value returned by this function and on the type of T, your program might have Undefined Behavior (I can imagine T being a pointer type that you later dereference).
You may want to change the first line of the function into:
T data = T();
Which enforces value-initialization of your data object. If T is a class type, the default constructor will be invoked. Otherwise, data will be zero-initialized.
The function which calls dequeue() should then check the returned value before using it (or better, call is_empty() on the queue to check it is not empty before trying to pop a value from it).
You may even consider throwing an exception when dequeue() is invoked and the queue is empty:
T dequeue()
{
if (is_empty())
{
// Requires including the <stdexcept> standard header
throw std::logic_error("Queue is empty");
}
node<T> * now = head;
T data = now->data;
head = head->next;
delete now;
size--;
return data;
}
Clients are now responsible for making sure that dequeue() is never called on an empty queue (or they shall wrap calls to dequeue() into a try/catch block to handle the possibly thrown exception.
Another possibility is returning a bool to your client indicating whether the value was successfully popped, possibly assigning the popped element to an argument passed by reference:
bool dequeue(T& data)
{
if (is_empty())
{
return false;
}
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
return true;
}
This way, the client is responsible for checking the result of the function. If the function returns false, the data variable will be initialized to whatever the client initialized it to. Responsibilities for handling error situations is again transferred to the client.
I think there are some issues.
First and most important, there is no destructor for the class. And if not all elements are dequeued in your program there will be a memory leak. Write the destructor or use smart pointer instead of the raw one.
Second, as #Andy Prowl(btw who knows how to # people in post like twitter?) said, uninitialized local variable should be considered. And T data = T() works well both for built-in and custom types.
Third, I think there is a capacity restriction max_queue_items for the queue but there is no corresponding code for the enqueue part.
Even though, I don't think all these flaws could cause a serious crash in normal case. Maybe the problem occurs in your code invokes the class and the incorrect processing for uninitalized return value leads to a crash.
The only potential problem I see in you dequeue is that you are creating a temporary variable of the unknown type T. If you are storing data of a type with no default constructor in your priority queue, you are going to have a problem when your dequeue calls and tries to default construct that variable.
If this is the case, I would suggest that you re-work your priority queue to hold pointers to the template type rather than the data itself.

Couple of Things In Doubly Linked List Template

I have a code of doubly Linked list and there are few lines of that code which idea is not clear . I request for experts comments on the lines which have comment in the following .Its long since I last time used C++ . There are just two line which i indicated are not understandable for me.
template <typename T>
class double_linked
{
struct node
{
T data;
node* prev;
node* next;
node(T t, node* p, node* n) : data(t), prev(p), next(n) {}
};
node* head;
node* tail;
public:
double_linked() : head( NULL ), tail ( NULL ) {}
template<int N>
double_linked( T (&arr) [N]) : head( NULL ), tail ( NULL )
{
for( int i(0); i != N; ++i)
push_back(arr[i]);
}
bool empty() const { return ( !head || !tail ); } // this doing?
operator bool() const { return !empty(); } // this doing? i know operators need in C++ but dont know the use of it here
void push_back(T);
void push_front(T);
T pop_back();
T pop_front();
~double_linked()
{
while(head)
{
node* temp(head);
head=head->next;
delete temp;
}
}
};
operator bool() const is a conversion operator. If an instance of double_linked is used in a context where a bool is required, this function will be called to do the conversion. (And will evaluate to true if the list is not empty in your case.)
The other function is a plain old function, which will return true if either head or tail is null.
For more about conversion operators, see: How do conversion operators work in C++?
The first is a function to determine if the list is empty. In a doubly linked list, if you have at least one element then the head and tail pointers (which point to the start and the end of the list respectively) must point to a valid element. Therefore, you can test whether the list is empty by testing if both those pointers do not point to a valid element (i.e. are null). That is what the expression !head || !tail does - checks if either pointer is null, and if so the list is empty.
The operator bool() thing is a conversion operator. It basically means, whenever the list is cast to bool, that function is called and the result used as the value of the bool. The function returns whether the list is not empty, so an expression like bool result = myList; will make result be true if the list is not empty.
This is a predicate telling us if it is empty or not, it is checking if the pointers are 0 (null).
bool empty() const { return ( !head || !tail ); } // this doing?
This allows the user to treat a instantiation of the container as a boolean, which is true if it is not empty.
operator bool() const { return !empty(); } // this
Implemented a linked list is a good programming excercise but if you want to use a linked list in your actual code then you should really use std::list (in ).