Problem with my doubly linked list insert function - c++

I am trying to finish up a assignment for my data structures c++ class. I have to define a double linked list of functions(like insert() size() remove() ) that was provided by my instructor. The instructor also includes the main file which runs tests on my code to see if it works.
I'm receiving his error message:
* Starting dlist tests *
Checking empty list...
FAILED: size of empty list is != 0.
I tried to rewrite the definition of the size() and insert() function and Im not understanding why im getting his error.
my instructors test code:
bool test_empty() {
std::cout << "Checking empty list...\n";
dlist e;
if(!verify(e))
return false;
if(e.size() != 0) {
std::cout << "FAILED: size of empty list is != 0.\n";
return false;
}
if(!e.empty()) {
std::cout << "FAILED: empty list is not .empty().\n";
return false;
}
return true;
}
my code for implementations:
void insert(node *previous, int value){
if(previous == nullptr){
node* n = new node;
n->value = value;
n->prev = previous;
n->next = nullptr;
return;
}
node* n = _head; //made a pointer to start at the head
while( n!= previous )//make n go down the list until it hits previous
{n = n->next;}
node* store_next = n->next; //store the address of the prev pointer of the next node
node* a = new node;//create the node that will be inserted
a->value = value;
n->next = a;// the pointer n points to the new node
a->prev = n; //the prev in the new node points to the previous
a->next = store_next; //the next in the new node points to the next node
store_next->prev = a; //the next node's prev points to the new inserted node
}
int size() const{
node* n = _head;
int size = 0;
while(n != nullptr){
size++;
n = n -> next;
}
return size;
}
Heres my default constructor and double linked list struct that my professor requires I use
class dlist {
public:
dlist() {
}
struct node {
int value;
node* next;
node* prev;
};

Related

Counting occurrence in singly linked list by nodes

I am writing a simple app that gets a list and saves the objects as nodes in a singly linked list and we can add(), remove(), copy(), etc. each node depending on the given data set. each node has a char value which is our data and an int count which counts the occurrence of the related char.
e.g. for a list like
a, a, b, b, c, a
there would be three nodes (since there are three different characters) which are:
[a,3,*next] -> [b,2,*next] -> [c,1,*next] -> nullptr
bool isAvailable() checks if the data is already in the list or not.
Q: When inserting a data there are two options:
The data has not been entered: so we have to create a newNodewith the given data, count=1and *next=NULL.
The data is already entered: so we have to count++ the node that has the same data.
I know if the given data is available or not, but how can I point to the node with same data?
Here's the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Snode
{
public:
char data;
int count;
Snode *next;
Snode(char d, int c)
{
data = d;
count = c;
next = NULL;
}
};
class set
{
private:
Snode *head;
public:
set()
{
head = NULL;
tail = NULL;
}
~set();
void insert(char value);
bool isAvailable(char value);
};
set::~set()
{
Snode *t = head;
while (t != NULL)
{
head = head->next;
delete t;
}
}
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
void set::insert(char value)
{
Snode *newNode = new Snode(char d, int c);
data = value;
if (head == NULL)
{
newNode->next = NULL;
head = newNode;
newNode->count++;
}
else
{
if(isAvailable)
{
//IDK what should i do here +_+
}
else
{
tail->next= newNode;
newNode->next = NULL;
tail = newNode;
}
}
}
I know if the given data is available or not, but how can I point to the node with same data?
You'll need to start at the head of the list and iterate along the list by following the next pointers until you find the node with the same data value. Once you've done that, you have your pointer to the node with the same data.
Some other notes for you:
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
Why is this function allocating a new Snode? There's no reason for it to do that, just initialize the floatingNode pointer to point to head instead.
This function always returns after looking at only the first node in the linked list -- which is not the behavior you want. Instead, it should return true only if (value == floatingNode); otherwise it should stay inside the while-loop so that it can go on to look at the subsequent nodes as well. Only after it drops out of the while-loop (because floatingNode finally becomes NULL) should it return false.
If you were to modify isAvailable() slightly so that instead of returning true or false, it returned either floatingPointer or NULL, you'd have your mechanism for finding a pointer to the node with the matching data.
e.g.:
// Should return either a pointer to the Snode with data==value,
// or NULL if no such Snode is present in the list
Snode * set::getNodeWithValueOrNullIfNotFound(char value) const
{
[...]
}
void set::insert(char value)
{
Snode * theNode = getNodeWithValueOrNullIfNotFound(value);
if (theNode != NULL)
{
theNode->count++;
}
else
{
[create a new Snode and insert it]
}
}
You had a lot of problems in your code, lets see what are they:
First of all, Snode doesn't need to be a class, rather you can go with a simple strcut; since we need everything public.(not a mistake, but good practice)
You could simple initialize count = 1 and next = nullptr, so that no need of initializing them throw constructor. The only element that need to be initialized through constructor is Snod's data.
Since c++11 you can use keyword nullptr instead of NULL, which denotes the pointer literal.
Member function bool set::isAvailable(char value) will not work as you think. Here you have unnecessarily created a new Snode and cheacking whether it points to nullptr which doesn't allow you to even enter the loop. BTW what you have written in the loop also wrong. What do you mean by return (value == floatingNode); ? floatingNode is a Snode by type; not a char.
Hear is the correct implementation. Since we don't wanna overwrite the head, will create a Node* pointer and assign head to it. Then iterate through list until you find a match. If not found, we will reach the end of the isAvailable() and return false.
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
In void set::insert(char value), your logic is correct, but implementation is wrong. Following is the correct implementation.(Hope the comments will help you to understand.
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value); // create a node and assign there
}
}
Your destructor will not delete all what you created. It will be UB, since your are deleting newly created Snode t ( i.e, Snode *t = head;). The correct implementation is as bellow.(un-comment the debugging msg to understand.)
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
Last but not least, the naming (set) what you have here and what the code exactly doing are both different. This looks more like a simple linked list with no duplicates. This is however okay, in order to play around with pointers and list.
To make the code or iteration more efficient, you could do something like follows. In the isAvailable(), in case of value match/ if you found a node, you could simply increment its count as well. Then in insert(), you can think of, if node is not available part.
Hope this was helpful. See a DEMO
#include <iostream>
// since you wanna have all of Node in public, declare as struct
struct Node
{
char data;
int count = 1;
Node* next_node = nullptr;
Node(const char& a) // create a constrcor which will initilize data
: data(a) {} // at the time of Node creation
};
class set
{
private:
Node *head; // need only head, if it's a simple list
public:
set() :head(nullptr) {} // constructor set it to nullptr
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value);
}
}
void print() const // just to print
{
Node *temp = head;
while(temp != nullptr)
{
std::cout << temp->data << " " << temp->count << "\n";
temp = temp->next_node;
}
}
};
int main()
{
::set mySet;
mySet.insert('a');
mySet.insert('a');
mySet.insert('b');
mySet.insert('b');
mySet.insert('c');
mySet.insert('a');
mySet.print();
return 0;
}

Linked list search function modifying list

I am trying to implement a doubly linked list in C++ and the add function is working properly but the find node function is modifying the list.
All other function like insertAfter, delete depend on this find function and hence they are also not working as expected.
I am new to C++, so I don't completely understand pointers. I simply tried to replicate my Java program in C++. I know for sure that in the find function the pointer to the head node is causing the problem but I don't completely understand how.
Below is my code :
struct Node{
int data;
Node* next;
Node* prev;
Node(int d) {
data = d;
};
};
struct DLL {
Node* head;
Node* tail;
int size;
//Adding a Node to the Doubly LL
void addNode(Node* n) {
//If LL is empty add the first Node
if (tail == NULL) {
tail = n;
head = n;
}
//Else add add node to the tail. Connect n to the tails next and make n the tail
else {
tail->next = n;
n->prev = tail;
tail = n;
tail->next = NULL;
}
size++;
};
//Finding a random Node in the linked List
//It will return the Node with the FIRST occurrence where data = d
Node* findNode(int d) {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
//While next pointer is not null, traverse to search for a match.s
while (start->next != NULL) {
start = start->next;
if (start->data == d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
}
cout << "No node found with matching data = " << d <<endl;
return NULL;
};
};
start->data = d
This line in your second if block is assigning d to start->data rather than comparing the two.
This is a good time to learn about constness.
Node* findNode(int d) {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
This function has write access to the list, and you don't want that. Unfortunately, you abuse this access in the last if statement:
if (start->data = d) {
this code assigns the value of d to start->data and then tests if the value assigned to it was not null.
We can mark this function as const easily:
//////////////////////vvvvv/////////////////
Node* findNode(int d) const {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
and now the if will generate a compiler error.
A cleaned up version of your code might look something like the following:
#include <iostream>
struct Node {
int data_;
Node* next_ { nullptr };
Node* prev_ { nullptr };
Node(int data) : data_(data) {}
};
struct DLL {
Node* head_ { nullptr };
Node* tail_ { nullptr };
int size_ { 0 };
//Adding a Node to the Doubly LL
void addNode(Node* node) {
//If LL is empty add the first Node
if (tail_ == nullptr) {
tail_ = node;
head_ = node;
node->prev_ = node->next_ = nullptr;
}
//Else add add node to the tail. Connect n to the tails next and make n the tail
else {
tail_->next_ = node;
node->prev_ = tail_;
tail_ = node;
node->next_ = nullptr;
}
size_++;
}
//Finding a random Node in the linked List
//It will return the Node with the FIRST occurrence where data = d
Node* findNode(int data) const {
//We will start at the head and then traverse through the entire list to find a Node where data = d
//While next pointer is not null, traverse to search for a match.s
for (Node* start = head_; start != nullptr; start = start->next_) {
if (start->data_ == data) {
std::cout << "Node found with matching data : " << start << '\n';
return start;
}
}
std::cout << "No node found with matching data = " << data << '\n';
return nullptr;
}
};
int main()
{
DLL dll;
Node n1(1), n3(3), n5(5);
dll.addNode(&n1);
dll.addNode(&n3);
dll.addNode(&n5);
if (dll.findNode(1) != &n1)
std::cerr << "wrong result for findNode(1)\n";
if (dll.findNode(2) != nullptr)
std::cerr << "wrong result for findNode(2)\n";
if (dll.findNode(3) != &n3)
std::cerr << "wrong result for findNode(3)\n";
if (dll.findNode(4) != nullptr)
std::cerr << "wrong result for findNode(4)\n";
if (dll.findNode(5) != &n5)
std::cerr << "wrong result for findNode(5)\n";
}
Live demo: http://ideone.com/X34EgY

"lvalue required as left operand of assignment" error writing a linked list

I am currently learning some C++ for a course I am taking in school. I have basic understanding of lvalues and rvalues, but I am unable to determine why I am receiving a compiler error.
I am creating a singly linked list and need to be able to reverse it. As per my assignment I have two classes. The first is the node and just holds an int as well as a pointer.
class Node {
int data;
Node *next;
public:
//Constructor
Node(int d) {
data = d;
next = NULL;}
//Set to next Node
void SetNext(Node *nextOne) {
next = nextOne;}
//Returns data value
int Data(){return data;}
//Returns next Node
Node *Next() {return next;}
};
Then I have a linked list class that has a header pointer and then a number of functions for adding, printing etc. the list.
class LinkedList {
Node *head;
public:
//Constructor
LinkedList(){head = NULL;}
void AddNode(int d) {
//Create a new Node
Node *newNode = new Node(d);
//Create a temporary pointer
Node *temp = head;
//If there are already nodes in the list
if(temp != NULL) {
//Parse through to the end of the list
while(temp->Next() != NULL) {
temp = temp->Next();}
//Point the last Node in the list to the new Node
temp->SetNext(newNode);
}
//If adding as the first Node
else{
head = newNode;}
}
void PrintList() {
//Temporary pointer
Node *temp = head;
//If there are no nodes in the list
if(temp == NULL) {
std::cout << "The list is empty" << std::endl;}
//If there is only one node in the list
if(temp->Next() == NULL) {
std::cout << temp->Data() << std::endl;}
//Parse through the list and print
else {
do {
std::cout << temp->Data();
temp = temp->Next();
}
while(temp != NULL);
}
}
//Returns the number of nodes in the list
int CountList() {
//Temporary pointer
Node *temp = head;
//Counter variable
int counter = 0;
//If the list is empty
if(temp == NULL) {
return counter;}
//Parse through Nodes counting them
else {
do {counter++;
temp = temp->Next();
}
while(temp != NULL);
}
return counter;
}
//Reverses the list
Node *ReverseList() {
//Initially set to NULL then tracks the new head
Node *marker = NULL;
//Tracks the next one in the list
Node *nextOne;
//Sets the first Node to NULL and then sets the last Node to point to
//the first one and rotates through the list pointing the last to the
//first
while(head != NULL) {
nextOne = head->Next();
head->Next() = marker;
marker = head;
head = nextOne;
}
//Setting the head back to the start again
head = marker;
}
};
One of those functions is supposed to reverse the list. The line "head->Next() = marker;" in the ReverseList function is causing a "lvalue required as left operand of assignment" error when compiling.
Any insight as to why this is occurring and how I can correct the problem?
Thank you in advance!
The return from the call to Next() is an rvalue. As you are in a class function, you don't need to call the Next function to get at the private next pointer, you can just use it directly.
head->next = marker;
Your Next() function returns a pointer, and you then do this:
head->Next() = marker;
You're changing the pointer to marker and not what it's pointing at. To solve this you need to dereference that pointer:
*head->Next() = marker;
your signature for next is:
Node *Next() {return next;}
This makes a copy of next pointer at return and hence it is treated as r-value and not l-value.
One way of overcoming this would be to use a pointer-to-pointer:.
Node **Next() {return &next;}
And then use it as:
int main()
{
Node* marker=new Node(89);
Node* nod=new Node(9);
*(nod->Next())= marker;
cout<<(nod->next)->data<<endl;
cout << "Hello World" << endl;
return 0;
}
This makes it more complicated to use.

Vector elements inserted into a linked list?

I'm trying to create a function which take in a Vector of Tokens, which is a type defined by my professor, and enter each element of the vector into the linked list, I return the head of the first element. The cout statement in the last part of new_list shows that I am indeed inserting the elements of the vector into the linked list. So when I type in:
new a 9 2 3
9 2 3 are being inserted
The print_list_cmd is defined by my professor and is supposed out the list that I created by calling new a,
so,
print a should return
9 2 3
but when I type print I only get the last element of the linked list which is 3.
I have two questions my code is not very elegant is there a better way to insert a vector of tokens into a linked list? Two why is the print command only returning the last element in the linked list? Also there is a lexer class that tokenizes the input but it's alot of code so I didn't insert it, if it's helpful or you need me to insert it I will.
struct Node {
int key;
Node* next;
Node(int k=0, Node* n=NULL) : key(k), next(n) {};
};
Node* new_list(const vector<Token>& tok_vec){
//int key;
Node *head;
Node *newHead;
Node *headPointer = NULL;
newHead = new Node;
newHead -> next = NULL;
head = NULL;
for(unsigned int i = 0 ; i < tok_vec.size() ; i++){
// newHead -> key = tok_vec.at(i).value;
string myStream = tok_vec.at(i).value;
istringstream buffer(myStream);
int value;
buffer >> value;
newHead -> key = value;
if(!head){
head = newHead;
}else{
headPointer = newHead;
while(headPointer -> next){
headPointer = headPointer -> next;
headPointer -> next = newHead;
}
}
cout << head->key << endl;
}
return head->key;
}
void print_list_cmd(Lexer lex){
Token tok = lex.next_token();
if (tok.type != IDENT || lex.has_more_token())
throw runtime_error("SYNTAX: print listname");
if (list_table.find(tok.value) == list_table.end())
throw runtime_error(tok.value + " not defined or already destroyed");
print_list(list_table[tok.value]);
}
Looking at your code, you don't return the head of the list, you return the value from the head Node:
return head->key;
instead of:
return head;
Also, most effective way to insert new items into the list would be inserting them at the head:
/// inserts node at the head of the list and returns the new head;
Node* insertNode(int key, Node* head) {
Node* newHead = new Node;
newHead->key = key;
newHead->next = head;
return newHead;
}
you could use that as:
Node* new_list(const vector<Token>& tok_vec){
Node* head = NULL;
for(unsigned int i = 0 ; i < tok_vec.size() ; i++){
string myStream = tok_vec.at(i).value;
istringstream buffer(myStream);
int value;
buffer >> value;
head = insertNode(value, head);
///
}
return head;
}
UPDATE. the resulting list will be backwards with regard to the input, so you would have to reverse it. One of the possibilities would be to create another list from the original one, so that at the end the last element of the old list will be the head of the new one:
Node* reverse(Node* list) {
Node* reversed = NULL;
while (list!=NULL) {
Node* nextNode = list;
list = list->next;
nextNode->next = reversed;
reversed = nextNode;
}
return reversed;
}

LinkedList/Stack/Queue - Help with Dequeuing

I had to write a linked list, then turn it into a dynamic Stack, then turn that into a dynamic Queue. Well everything seems to work except the "dequeuing", right as the programs about to finish, it gives me an error: "An unhandled win32 exception occured in LinkedList_Stack_BNS11.exe [4972].".
I'm only assuming it's the dequeuing, because as I step through and/or run the program, it runs smoothly up till that part, so maybe I sent one of the pointers wrong or something?
Output:
Enquing 5 items....
// Finsihes
The values in the queue were (Dequeuing):
0
1
2
// Correct number in que but...
//Program gives that error right here. When it should finish and close.
If I included too much code let me know and I'll chop it down to just the "Dequeuing" (Which is in the very middle of all the stuff below)
Thanks in advance for the help!! I'm just not seeing what I did wrong. Thinking it maybe has something to do with where "head" is pointing? Idk.
Header File:
class NumberList
{
private:
//
struct ListNode
{
int value; // Value in this node
struct ListNode *next; // Pointer to the next node
};
ListNode *head; // List head pointer
ListNode *rear;
public:
//Constructor
NumberList()
{ head = NULL; rear = NULL; }
//Destructor
~NumberList();
//Stack operations
bool isEmpty();
//Queue operations
void enqueue(int);
void dequeue(int &);
};
#endif
List_Stack_Queue.cpp:
bool NumberList::isEmpty()
{
bool status;
if(!head)
status = true;
else
status = false;
return status;
}
void NumberList::enqueue(int num)
{
ListNode *newNode; // Point to a new node
// Allocate a new node and store num there.
newNode = new ListNode;
newNode->value = num;
//If there are no nodes in the list
// make newNode the first node.
if(isEmpty())
{
head = newNode;
rear = head;
//newNode->next = NULL;
}
else
{
rear->next = newNode;
rear = rear->next;
//newNode->next = head;
//head = newNode;
}
}
void NumberList::dequeue(int &num)
{
ListNode *temp;
if(isEmpty())
cout << "The queue is empty.\n";
else
{
num = head->value;
temp = head;
head = head->next;
delete temp;
}
}
MAIN:
const int MAX_VALUES = 3;
// Create a DynIntQueue object.
NumberList iQueue;
// Enqueue a series of numbers.
cout << "Enqueuing " << MAX_VALUES << " items...\n";
for (int x = 0; x < MAX_VALUES; x++)
iQueue.enqueue(x);
cout << endl;
//Dequeue and retrieve all numbers in the queue
cout << "The values in the queue were (Dequeuing):\n";
while(!iQueue.isEmpty())
{
int value;
iQueue.dequeue(value);
cout << value << endl;
}
return 0;
Last nodes's next element should be set to NULL in a linked list. So,
void NumberList::enqueue(int num)
{
// ...
if(isEmpty())
{
head = newNode;
head->next = NULL;
rear = head;
}
else
{
rear->next = newNode;
rear = rear->next;
rear->next = NULL; // Pointing the next node element to null.
}
}
To, me it seems some thing is wrong with Numberlist::isEmpty(); member function. How you are deciding whether the list is empty or not ? Show the definition of it.