C++ Linked List assignment: trouble with insertion and deletion - c++

I am working on a linked list implementation in C++. I am making progress but am having trouble getting the insertion functionality and deletion functionality to work correctly. Below is list object in the C++ header file:
#ifndef linkList_H
#define linkList_h
//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
Node() : sentinel(0) {}
int number;
Node* next;
Node* prev;
Node* sentinel;
};
//
// Create an object to keep track of all parts in the list
//
class List
{
public:
//
// Contstructor intializes all member data
//
List() : m_listSize(0), m_listHead(0) {}
//
// methods to return size of list and list head
//
Node* getListHead() const { return m_listHead; }
unsigned getListSize() const { return m_listSize; }
//
// method for adding and inserting a new node to the linked list,
// retrieving and deleting a specified node in the list
//
void addNode(int num);
void insertNode(Node* current);
void deleteNode(Node* current);
Node* retrieveNode(unsigned position);
private:
//
// member data consists of an unsigned integer representing
// the list size and a pointer to a Node object representing head
//
Node* m_listHead;
unsigned m_listSize;
};
#endif
And here is the implementation (.cpp) file:
#include "linkList.h"
#include <iostream>
using namespace std;
//
// Adds a new node to the linked list
//
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
m_listHead = newNode;
++m_listSize;
}
//
// NOTWORKING: Inserts a node which has already been set to front
// of the list
//
void List::insertNode(Node* current)
{
// check to see if current node already at
// head of list
if(current == m_listHead)
return;
current->next = m_listHead;
if(m_listHead != 0)
m_listHead->prev = current;
m_listHead = current;
current->prev = 0;
}
//
// NOTWORKING: Deletes a node from a specified position in linked list
//
void List::deleteNode(Node* current)
{
current->prev->next = current->next;
current->next->prev = current->prev;
}
//
// Retrieves a specified node from the list
//
Node* List::retrieveNode(unsigned position)
{
if(position > (m_listSize-1) || position < 0)
{
cout << "Can't access node; out of list bounds";
cout << endl;
cout << endl;
exit(EXIT_FAILURE);
}
Node* current = m_listHead;
unsigned pos = 0;
while(current != 0 && pos != position)
{
current = current->next;
++pos;
}
return current;
}
After running a brief test program in the client C++ code, here is the resulting output:
Number of nodes: 10
Elements in each node:
9 8 7 6 5 4 3 2 1 0
Insertion of node 5 at the list head:
4 9 8 7 6 5 4 9 8 7
Deletion of node 5 from the linked list
As you can see, the insertion is not simply moving node 5 to head of list, but is overwriting other nodes beginning at the third position. The pseudo code I tried to implement came from the MIT algorithms book:
LIST-INSERT(L, x)
next[x] <- head[L]
if head[L] != NIL
then prev[head[L]] <- x
head[L] <- x
prev[x] <- NIL
Also the deletion implementation is just crashing when the method is called. Not sure why; but here is the corresponding pseudo-code:
LIST-DELET'
next[prev[x]] <- next[x]
prev[next[x]] <- prev[x]
To be honest, I am not sure how the previous, next and sentinel pointers are actually working in memory. I know what they should be doing in a practical sense, but looking at the debugger it appears these pointers are not pointing to anything in the case of deletion:
(*current).prev 0xcdcdcdcd {number=??? next=??? prev=??? ...} Node *
number CXX0030: Error: expression cannot be evaluated
next CXX0030: Error: expression cannot be evaluated
prev CXX0030: Error: expression cannot be evaluated
sentinel CXX0030: Error: expression cannot be evaluated
Any help would be greatly appreciated!!

You have got an error in addNode(). Until you fix that, you can't expect insertNode to work.
Also, I think your design is quite silly. For example a method named "insertNode" should insert a new item at arbitrary position, but your method insertNode does a pretty different thing, so you should rename it. Also addNode should be renamed. Also as glowcoder wrote, why are there so many sentinels? I am affraid your class design is bad as a whole.
The actual error is that you forgot to set prev attribute of the old head. It should point to the new head.
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
if(m_listHead) m_listHead->prev = newNode;
m_listHead = newNode;
++m_listSize;
}
Similarly, you have got another error in deleteNode(). It doesn't work when deleting last item from list.
void List::deleteNode(Node* current)
{
m_listSize--;
if(current == m_listHead) m_listHead = current->next;
if(current->prev) current->prev->next = current->next;
if(current->next) current->next->prev = current->prev;
}
Now you can fix your so-called insertNode:
void List::insertNode(Node* current)
{
int value = current->number;
deleteNode(current);
addNode(value);
}
Please note that I wrote everything here without compiling and testing in C++ compiler. Maybe there are some bugs, but still I hope it helps you at least a little bit.

In deleteNode, you are not handling the cases where current->next and/or current->prev is null. Also, you are not updating the list head if current happens to be the head.
You should do something like this:
node* next=current->next;
node* prev=current->prev;
if (next!=null) next->prev=prev;
if (prev!=null) prev->next=next;
if (m_listhead==current) m_list_head=next;
(Warning: I have not actually tested the code above - but I think it illustrates my idea well enough)
I am not sure what exactly your InsertNode method does, so I can't offer any help there.

OK.
As #Al Kepp points out, your "add node" is buggy. Look at Al's code and fix that.
The "insert" that you are doing does not appear to be a normal list insert. Rather it seems to be a "move to the front" operation.
Notwithstanding that, you need to delete the node from its current place in the list before you add it to the beginning of the list.
Update
I think you have misunderstood how insert should work. It should insert a new node, not one that is already in the list.
See below for a bare-bones example.
#include <iostream>
// List Node Object
//
struct Node
{
Node(int n=0);
int nData;
Node* pPrev;
Node* pNext;
};
Node::Node(int n)
: nData(n)
, pPrev(NULL)
, pNext(NULL)
{
}
//
// List object
//
class CList
{
public:
//
// Contstructor
//
CList();
//
// methods to inspect list
//
Node* Head() const;
unsigned Size() const;
Node* Get(unsigned nPos) const;
void Print(std::ostream &os=std::cout) const;
//
// methods to modify list
//
void Insert(int nData);
void Insert(Node *pNew);
void Delete(unsigned nPos);
void Delete(Node *pDel);
private:
//
// Internal data
//
Node* m_pHead;
unsigned m_nSize;
};
/////////////////////////////////////////////////////////////////////////////////
CList::CList()
: m_pHead(NULL)
, m_nSize(0)
{
}
Node *CList::Head() const
{
return m_pHead;
}
unsigned CList::Size() const
{
return m_nSize;
}
void CList::Insert(int nData)
{
Insert(new Node(nData));
}
void CList::Insert(Node *pNew)
{
pNew->pNext = m_pHead;
if (m_pHead)
m_pHead->pPrev = pNew;
pNew->pPrev = NULL;
m_pHead = pNew;
++m_nSize;
}
void CList::Delete(unsigned nPos)
{
Delete(Get(nPos));
}
void CList::Delete(Node *pDel)
{
if (pDel == m_pHead)
{
// delete first
m_pHead = pDel->pNext;
if (m_pHead)
m_pHead->pPrev = NULL;
}
else
{
// delete subsequent
pDel->pPrev->pNext = pDel->pNext;
if (pDel->pNext)
pDel->pNext->pPrev = pDel->pPrev;
}
delete pDel;
--m_nSize;
}
Node* CList::Get(unsigned nPos) const
{
unsigned nCount(0);
for (Node *p=m_pHead; p; p = p->pNext)
if (nCount++ == nPos)
return p;
throw std::out_of_range("No such node");
}
void CList::Print(std::ostream &os) const
{
const char szArrow[] = " --> ";
os << szArrow;
for (Node *p=m_pHead; p; p = p->pNext)
os << p->nData << szArrow;
os << "NIL\n";
}
int main()
{
CList l;
l.Print();
for (int i=0; i<10; i++)
l.Insert((i+1)*10);
l.Print();
l.Delete(3);
l.Delete(7);
l.Print();
try
{
l.Delete(33);
}
catch(std::exception &e)
{
std::cerr << "Failed to delete 33: " << e.what() << '\n';
}
l.Print();
return 0;
}

Related

Try tree inplementation

Try to make tree , have a some troubles, first it's print function - it's print not integers that i put, but print random numbers;
Another trouble its append child - its works only one times;
Will be happy if you will help me with this task.
And also give some good articles about linked lists, trees on c and c++;
#include <iostream>
#include <stdio.h>
using namespace std;
struct Node
{
void* m_pPayload;
Node* m_pParent;
Node* m_Children;
};
struct Person
{
int m_Id;
};
//typedef bool (*NodeComparator)(void* pValue, void* pPayload);
/*bool Comp(void* pValue, void* pPayload)
{
Person* pVal = (Person*)pValue;
Person* pPay = (Person*)pPayload;
if (pVal->m_Id == pPay->m_Id)
return true;
else
return false;
}
*/
Node* NewNode(void* pPayload)
{
Node* pNode = new Node;
pNode->m_pParent = nullptr;
pNode->m_Children = 0;
pNode->m_pPayload = pPayload;
return pNode;
}
Person* NewPerson(int id)
{
Person* p = new Person;
p->m_Id = id;
return p;
}
//Node* FindNode(Node* pParent, Node* m_pPayload, NodeComparator comparator);
void AppendChild(Node* pParent, Node* pNode)
{
if (pParent->m_Children == NULL)
pParent->m_Children = pNode;
}
void print(Node* head)
{
Node* current_node = head;
while (current_node != NULL)
{
printf("%d\n ", current_node->m_pPayload);
current_node = current_node->m_Children;
}
}
int main()
{
Node* T = new Node;
T = NewNode(NewPerson(5));
AppendChild(T, NewNode(NewPerson(11)));
AppendChild(T, NewNode(NewPerson(15)));
print(T);
}
printf("%d\n ", current_node->m_pPayload)
is incorrect. %d wants an integer and it's being given a pointer. The results will be unusual, and likely appear to be random garbage.
printf("%d\n ", ((Person*)current_node->m_pPayload)->m_Id);
^ ^
| Get id from Person
treat payload pointer as pointer to Person
will solve the immediate problem.
Your code actually seems to be pretty messed up with a lot of things going on, here sharing my own commented code from few years back, hope it helps
#include <bits/stdc++.h>
using namespace std;
// Single node representation
struct node {
int data;
node *left, *right;
};
// Declaring temp for refference and root to hold root node
node *root, *temp;
// This function only generates a node and return it to the calling function with data stored in it
node* generateNode(int data){
temp = new node();
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
// This function actually adds node to the tree
node* addNode(int data, node *ptr = root){
// If the node passed as ptr is NULL
if(ptr == NULL){
ptr = generateNode(data);
return ptr;
}
// Condition to check in which side the data will fit in the tree
else if(ptr->data < data)
//if its in right, calling this function recursively, with the right part of the tree as the root tree
ptr->right = addNode(data, ptr->right);
else
//In case the data fits in left
ptr->left = addNode(data, ptr->left);
//Note: if there is no data in left or roght depending on the data's valid position, this function will get called with NULL as second argument and then the first condition will get triggered
//returning the tree after appending the child
return ptr;
}
//Driver function
int main ()
{
int c, data;
for (;;){
cin >> c;
switch(c){
case 1:
cout << "enter data: ";
cin >> data;
//Updating root as the tree returned by the addNode function after adding a node
root = addNode(data);
break;
default:
exit(0);
break;
}
}
return 0;
}
Please find below a piece of code that should easily get you started. It compiles and it traverse the tree using recursion.
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
struct Node
{
int m_Id;
vector<Node*> m_Children;
Node(const int& id){
m_Id = id;
}
void AppendChild(Node* pNode) {
m_Children.push_back(pNode);
}
void Print() {
printf("%d\n ", m_Id);
}
};
void traverse(Node* head)
{
Node* current_node = head;
current_node->Print();
for(int i = 0; i<current_node->m_Children.size(); i++) {
traverse(current_node->m_Children[i]);
}
}
int main()
{
Node* T0 = new Node(0);
Node* T10 = new Node(10);
T10->AppendChild(new Node(20));
Node* T11 = new Node(11);
Node* T12 = new Node(12);
Node* T22 = new Node(22);
T22->AppendChild(new Node(33));
T12->AppendChild(T22);
T0->AppendChild(T10);
T0->AppendChild(T11);
T0->AppendChild(T12);
traverse(T0);
}
First for printing the node value
Talking about the current mistake that you had committed is in the above code is:
You have not mentioned its pointer to its child (specifically right or left). Due to which it is showing garbage value every time.
For e.g.: print( node->left);
Since you need to type caste it properly to show the data of data.
For e.g.: printf("%d\n ", ((Person*)current_node->m_pPayload)->m_Id);
There is a specific direction in which you want to print data. For trees, there are three directions in which you can print the data of the node and they are as follow:
Left order or Inorder traversal
Preorder traversal
Postorder traversal
This can give you better information about traversal.
Secondly for adding the node to a tree
This might help explain it better.

How to remove duplicate entries in a linked list input?

I am tasked with removing all duplicate entries in the linked list. Assuming the list is ordered from smallest to largest, therefore all I need to do is remove the duplicates next to each other.
For example: If the list contains {1,2,2,2,3,3,4,5,5,5,5,5,6} before calling remove_duplicates(), it should contain{1,2,3,4,5,6} after.
My problem is that my code will print the duplicates as well whenever remove_duplicates() is called.
Here is my code:
list.cpp:
#include <iostream>
using namespace std;
#include "list.h"
// on some machines member variables are not automatically initialized to 0
List::List()
{
m_head = NULL;
m_length = 0;
}
// delete all Nodes in the list
// since they are dynamically allocated using new, they won't go away
// automatically when the list is deleted
// Rule of thumb: destructor deletes all memory created by member functions
List::~List()
{
while (m_head)
{
Node *tmp = m_head;
m_head = m_head->m_next;
delete tmp;
}
}
// always insert at the front of the list
// Note: this works even in the SPECIAL CASE that the list is empty
void List::insert(int value)
{
if (!m_head || value < m_head->m_value)
{
m_head = new Node(value, m_head);
}
else
{
Node *ptr = m_head;
while (ptr->m_next != NULL && value > ptr->m_next->m_value)
{
ptr = ptr->m_next;
}
ptr->m_next = new Node(value, ptr->m_next);
}
m_length++;
}
// iterate through all the Nodes in the list and print each Node
void List::print()
{
for (Node *ptr = m_head; ptr; ptr = ptr->m_next)
{
cout << ptr->m_value << endl;
}
}
void List::remove_duplicates()
{
Node *curr = m_head;
Node *temp = m_head;
Node *delPtr = NULL;
if(curr == NULL)
{
return;
}
if(curr != NULL)
{
if(curr -> m_value == curr ->m_next ->m_value)
{
delPtr = curr;
curr = curr -> m_next;
temp ->m_next = curr;
delete delPtr;
}
else
{
curr = curr -> m_next;
}
}
}
list.h:
class List
{
public:
List();
~List();
void insert(int value); // insert at beginning of list
void print(); // print all values in the list
int length() {return m_length;}
void remove_duplicates();
int *convert_to_array(int &size);
private:
class Node
{
public:
Node(int value, Node *next)
{m_value = value; m_next = next;}
int m_value;
Node *m_next;
};
Node *m_head;
int m_length;
};
main.cpp:
#include <assert.h>
#include <iostream>
using namespace std;
#include "list.h"
int main()
{
List list;
int value;
// read values and insert them into list
while (cin >> value)
{
list.insert(value);
}
cout << "printing original list: \n";
list.print();
list.remove_duplicates();
cout << "printing list after removing duplicates: \n";
list.print();
}
Note: Everything has been given to me by my instructor, the only code that I am supposed to write is void List::remove_duplicates()
I have looked up other examples on stackoverflow, but none seem to help me with my situation.
Also, I do want to mention that I am still very new to Linked Lists and how they function. Therefore I am not exactly sure where to go from here. Any help would be appreciated
You need to iterate over your list using both the Address of the current pointer, and the current pointer. See Linus on Understanding Pointers. Since you don't just want to delete a node with a certain value, but you want to scan forward in the list deleting ALL nodes with that value, you want to loop over each node, and within the loop scan-forward deleting ALL nodes with the value of the current node.
You do that by checking the m_next->m_value and if it the same as the current node value, you REPLACE the node at the current pointer ADDRESS with the next node content. Since you still have a pointer to the node you have replaced, you can simply delete that node and then update the pointer from the address of the current node.
This presumes your list is in SORT-ORDER as you show in your question. If it isn't, you would need to scan the list multiple times. In sort-order as shown, you could do:
/* list must be in sort order */
void List::remove_duplicates()
{
Node **pp = &m_head, /* current address of head (pointer-to-pointer) */
*p = m_head; /* pointer to head */
/* loop over each node */
for (; p; pp = &p->m_next, p = p->m_next) {
/* while m_next and current value == next value */
while (p->m_next && (*pp)->m_value == p->m_next->m_value)
{
*pp = p->m_next; /* set node at current address to next node */
delete p; /* delete original node at that address */
p = *pp; /* update pointer to current node address */
}
}
}
(essentially if the current node and next have the same m_value you are throwing away the current node (and properly deleting the memory) and replacing it with the next)
Then for example, if your list originally contained:
0 0 1 1 1 2 3 4 4 5 6 6 6 7 8 9 9 9
calling list.remove_duplicates() would result in:
0 1 2 3 4 5 6 7 8 9
Look things over and let me know if you have further questions.

Search and protecting singly linked list in C++

I have one questions regarding searching elements on a Singly Linked List of ints, in this case, using C++. I'm creating my own version of list for exercising. This is the code
Let's suppose I have two search functions. I know we need to traverse the entire list until find the element because we don't have direct access like arrays.
The two functions are:
bool search(int n); // Traverse the list till find n.
bool search(Node* node, int n); Traverse the list till find n only after *node (included)
1 case: My list has the following elements: [0, 1, 2, 3]
If I search for 3 I easily find at the end of the list. Nice.
QUESTIONS:
2 case: My list has the following elements: [0, 1, 2, 3, 3, 3, 4, 5, 6]
If I search for 3 with:
bool search(int n);
I'm going to get the first 3 element always, except if I have a reference to the second or third 3 element to pass to that function:
bool search(Node* node, int n);
My questions is if that is the correct search algorithm in a singly linked list. The two types of functions or if I should have other types.
Bellow is the code for my actual code (I didn't put the code for searching):
SingleLinkedList.h
struct Node {
int data;
Node* next;
Node(int d = 0)
: data {d}, next {nullptr}
{}
};
class SinglyLinkedList {
public:
SinglyLinkedList();
~SinglyLinkedList();
void display();
bool addFirst(const int); // Add a node to the beginning of the list.
bool addFirst(Node*); // Add a node to the beginning of the list.
bool addLast(const int); // Add a node to the end of the list.
bool addLast(Node*); // Add a node to the end of the list.
private:
Node* head;
Node* tail;
};
SinglyLinkedList.h
#include "SinglyLinkedList.h"
#include <iostream>
SinglyLinkedList::SinglyLinkedList()
: head {nullptr}, tail {nullptr}
{}
SinglyLinkedList::~SinglyLinkedList() {
Node* iterationNode = head;
Node* actualNode {nullptr};
while (iterationNode != nullptr) {
actualNode = iterationNode;
iterationNode = iterationNode->next;
delete actualNode;
}
}
void SinglyLinkedList::display() {
std::cout << "################### Displaying Linked List ###################" << std::endl;
if (head == nullptr) {
std::cout << "Linked List is empty!" << std::endl;
}
else {
Node* iterationNode = head;
std::cout << "[ ";
while (iterationNode != nullptr) {
std::cout << iterationNode->data << " ";
iterationNode = iterationNode->next;
}
iterationNode = nullptr;
std::cout << "]" << std::endl;
}
std::cout << "##############################################################" << std::endl;
}
bool SinglyLinkedList::addFirst(const int n) {
Node* element = new Node {n};
if (head == nullptr) {
head = element;
tail = element;
}
else {
element->next = head;
head = element;
}
return true;
}
bool SinglyLinkedList::addFirst(Node* element) {
if (head == nullptr) {
head = element;
tail = element;
}
else {
element->next = head;
head = element;
}
return true;
}
bool SinglyLinkedList::addLast(const int n) {
Node* element = new Node {n};
if (head == nullptr) {
head = element;
tail = element;
}
else {
tail->next = element;
tail = element;
}
return true;
}
bool SinglyLinkedList::addLast(Node* element) {
if (head == nullptr) {
head = element;
tail = element;
}
else {
tail->next = element;
tail = element;
}
return true;
}
Program.cpp
#include <iostream>
#include "SinglyLinkedList.h"
int main() {
{
SinglyLinkedList list;
list.display();
list.addFirst(5);
list.addFirst(4);
list.addFirst(3);
Node* secondNode = new Node {2};
list.addFirst(secondNode);
Node* firstNode = new Node {1};
list.addFirst(firstNode);
Node* zeroNode = new Node;
list.addFirst(zeroNode);
list.addLast(6);
list.display();
}
system("pause");
}
Another question is, how can I protect my struct in a way the user of the program can not mess up changing the links/references directly. For example, in the Program.cpp, any programmer could simply do this:
secondNode->next = zeroNode
The answer to your first question depends on what you need. If you are doing this as a learning project, implement whatever you see fit. What you have described is appropriate for search by value.
The best way to prevent users from directly accessing your Node members in cases like this is to completely abstract the Node type away. You can do this simply by declaring and defining Node in your source file and use forward declarations of Node* in your header. Users who include your header will then not have any notion of your Node type whatsoever.
// SinglyLinkedList.h
class SinglyLinkedList {
//...//
struct Node* head; // head node is forward declared
//...//
}
// SinglyLinkedList.cc
struct Node {
//...
};
// define ll methods
If you do want the user to know about the Node type, one solution is to make its members private, create a public value accessor method, and make the Node a friend of the SinglyLinkedList class.

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;
}

"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.