Counting occurrence in singly linked list by nodes - c++

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

Related

insertion at the end of linked list function not working

I don't know where I am wrong, when I debugged the code I found out that the 'new node' address is 'new node' address, basically the new node is referring to itself
void insertend(struct node *parent, int item)
{
while (parent->addr != NULL)
parent = parent->addr;
struct node new_node;
new_node.a = item;
parent->addr = &new_node;
parent->addr->addr = NULL;
}
void insertend(struct node *parent, int item)
{
while (parent->addr != NULL)
parent = parent->addr;
struct node new_node;
new_node.a = item;
parent->addr = &new_node;
parent->addr->addr = NULL;
}
The lifetime of new_node is limited to the function. Once that function returns, it is no longer valid.
In order to circumvent this, it is necessary to dynamically allocate memory for new_node. Of course, as already pointed out, this means explicitly deallocating the memory eventually.
Note: as this is C++ rather than C, we do not need to add struct to the front of the type in use, and NULL is better spelled nullptr.
void insertend(node *parent, int item)
{
while (parent->addr != nullptr)
parent = parent->addr;
node *new_node = new node;
new_node.a = item;
parent->addr = new_node;
parent->addr->addr = nullptr;
}
As C++ structs are just classes with default public access, it's also worth noting we could implement this as a member function. Something like:
template <typename T>
struct Node {
T value;
Node<T> *next;
void append(T val) {
Node<T> * temp = this;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = new Node<T>;
temp->next->value = val;
temp->next->next = nullptr;
}
};
int main() {
auto n = Node<int>();
n.value = 27;
n.append(42);
n.append(34);
for (Node<int> *t = &n; t != nullptr; t = t->next) {
std::cout << t->value << std::endl;
}
return 0;
}
The next step would be implementing a constructor and destructor.
One more thing to keep in mind is that getting to the end of a list this way is O(n) time complexity. Doing it over and over again is costly. If you have Node::append return a pointer to the new Node, then you can call append on that.
template <typename T>
struct Node {
T value;
Node<T> *next;
Node<T> *append(T val) {
Node<T> * temp = this;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = new Node<T>;
temp->next->value = val;
temp->next->next = nullptr;
return temp->next;
}
};
int main() {
auto n = Node<int>();
n.value = 27;
auto n2 = n.append(42);
n2 = n2->append(34);
n2 = n2->append(15);
for (Node<int> *t = &n; t != nullptr; t = t->next) {
std::cout << t->value << std::endl;
}
return 0;
}
I’m not sure what the addr refers to, but I would assume it points to the next node in the linked list. In your code, there needs to be another node to use as a temporary node, because the parent node keeps being reassigned, and the previous items are lost. We also need to check that the parent node is not NULL.
void insertend(struct node **parent, int item)
{
node *new_node = new node;
new_node->a = item;
new_node->addr = NULL;
if(*parent == NULL)
{
*parent = new_node;
}
else
{
node *temp = *parent;
while (temp->addr != NULL)
temp = temp->addr;
temp->addr = new_node;
}
}
The if statement checks whether the parent node is NULL. If true, then we assign parent node to new_node. If false, then we go to the end of the list and assign the next node in the list to new_node.
As Igor correctly pointed out, your new node gets destroyed when the function finishes. So, in this context you could just allocate memory. You can use the new operator for this. However, you would need to explicitly free the memory, eventually.
void insertend(struct node *parent, int item)
{
while (parent->addr != NULL)
parent = parent->addr;
struct * new_node = new node;
new_node->a = item;
parent->addr = new_node;
parent->addr->addr = NULL;
}

C++ Linked List HEAD keeps resetting to NULL

I need help in understanding why my Linked List approach doesn't work as expected.
#include <iostream>
using namespace std;
class Node {
public:
int Data;
Node* Next;
Node(int data) {
Data = data;
Next = NULL;
}
};
void insertNodeAtEnd(Node* HEAD, int data) {
Node* it = HEAD;
if (HEAD == NULL) { HEAD = new Node(data); }
else {
while (it->Next != NULL) { it = it -> Next; }
it -> Next = new Node(data);
}
}
void printLinkedList(Node* HEAD) {
Node* it = HEAD;
while (it != NULL) {
cout << it->Data << endl;
it = it -> Next;
}
}
int main() {
Node* HEAD = NULL;
// Node* HEAD = new Node(0);
insertNodeAtEnd(HEAD, 5);
insertNodeAtEnd(HEAD, 2);
insertNodeAtEnd(HEAD, 10);
printLinkedList(HEAD);
return 0;
}
The above main() function does NOT work (ie: no output, and the HEAD keeps resetting to NULL as soon as the control leaves insertNodeAtEnd()), and I've found similar questions here on SO which explain that this is because the pointer is being passed by value, and that makes partial sense to me.
Why does it work as expected when I replace Node* HEAD = NULL; with Node* HEAD = new Node(0); in the main() function, if the pointer is being passed as value?
How are nodes getting added if I initialise HEAD like Node* HEAD = new Node(0);, but not in the case where HEAD = NULL initially? I was able to get it to work properly by using pointer to pointer but I can't understand why this approach doesn't work. I am sorry if I haven't explained my question properly, please let me know if any clarification is required.
The underlying issue can be reduced to this code:
void insertNodeAtEnd(Node* HEAD, int data) {
//...
if (HEAD == NULL) { HEAD = new Node(data); }
//...
}
int main() {
Node* HEAD = NULL;
insertNodeAtEnd(HEAD, 5);
//...
You seem to assume that assigning to HEAD inside insertNodeAtEnd would change the HEAD variable inside of main. This is not true. Your pointer is passed by value, so the address is copied for the function. Changing this copied variable will not change the value of HEAD inside of main.
To fix this you could pass a pointer to a pointer instead, like this:
void insertNodeAtEnd(Node** HEAD, int data) {
//...
if (*HEAD == NULL) { *HEAD = new Node(data); }
//...
}
int main() {
Node* HEAD = NULL;
insertNodeAtEnd(&HEAD, 5);
//...
This pointer to a pointer is still passed by value, however the pointer that it points to will be the same as the on from main.
The problem come from your first insertion. You change the value of head which is reset when you quit the function. You can only change the value behind the pointer, not the pointer itself.
A solution for this would be to pass a pointer of pointer. Something like: (not tested)
void insertNodeAtEnd(Node** HEAD, int data) {
if (*HEAD == NULL) { *HEAD = new Node(data); }
else {
Node* it = *HEAD;
while (it->Next != NULL) { it = it -> Next; }
it -> Next = new Node(data);
}
}
int main() {
Node* HEAD = NULL;
// Node* HEAD = new Node(0);
insertNodeAtEnd(&HEAD, 5);
return 0;
}
As you don't change the pointer of pointer but only the value behind it (the actuual pointer to head) the change will be keep once you exit the function.
The answer has already been given by #Brotcrunsher. I am posting to help you implement a better solution, that separates the concept of a list and an element of a list, that incapsulates the methods used and that frees the resources it uses, when it goes out of scope:
#include <iostream>
using namespace std;
class Node {
public:
int Data;
Node* Next;
Node(int data = 0) {
Data = data;
Next = nullptr;
}
};
class List {
public:
Node* Head = nullptr;
void Insert(int data) {
if (Head == nullptr)
Head = new Node(data);
else {
Node* ptr;
for (ptr = Head; ptr->Next != nullptr; ptr = ptr->Next)
;
ptr->Next = new Node(data);
}
}
void Print() {
for (Node* ptr = Head; ptr != nullptr; ptr = ptr->Next)
cout << ptr->Data << endl;
}
~List() {
Node* ptr = Head;
while (ptr != nullptr) {
Node* tmp = ptr;
ptr = ptr->Next;
delete tmp;
}
}
};
int main() {
List list;
list.Insert(5);
list.Insert(2);
list.Insert(10);
list.Print();
return 0;
}

Problem with my doubly linked list insert function

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

Link list Adding CPP

I am implementing a link list with cpp,what is wrong with the following code?
Every time i step into the function---AddToTail, the "list" can't get correct value. It changes it value to the new constructed node.
#include <iostream>
using namespace std;
struct Node
{
int value;
Node * next;
};
void AddToTail(Node* &list, int value)
{
Node newnode;
newnode.value = value;
newnode.next = NULL;
if (list == NULL)
list = &newnode;
else
{
Node * list1 = list;
while (list1->next != NULL)
{
list1 = list1->next;
}
list1->next = &newnode;
int a = 1;
}
}
int main()
{
Node *list=NULL;
AddToTail(list, 1);
AddToTail(list, 2);
AddToTail(list, 3);
while (list->next != NULL)
{
cout << list->value << endl;
list = list->next;
}
system("pause");
}
void AddToTail(Node* &list, int value)
{
Node newnode;
// Set up fields of newnode.
// Store address of newnode into some other data structure.
}
This is your issue. You are creating a node on the stack and this node will go out of scope at the end of the function. The reason it seems to be interfering with later node creations is because re-entering the function will almost certainly create newnode at exactly the same address as in the previous call.
If you want objects to survive function scope, you're going to need to allocate them dynamically, something like:
void AddToTail (Node *&list, int value) {
Node *newnode = new Node(); // create on heap.
newnode->value = value; // set up node.
newnode->next = nullptr;
if (list == nullptr) { // list empty,
list = newnode; // just create.
return;
}
Node *lastNode = list; // find last item.
while (lastNode->next != nullptr)
lastNode = lastNode->next;
lastNode->next = newnode; // append to that.
}

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