C++Linked list non-member function to reverse print - c++

So I understood how to print a single linked list in reverse order using recursion. I'm having trouble with doing it non member functions.
For example in int print_reverse(IntSLList & list)) function how do you print reverse in an iterative way?
************************ .h file **************************
class IntSLLNode {
public:
IntSLLNode() {
next = 0;
}
IntSLLNode(int el, IntSLLNode *ptr = 0) {
info = el; next = ptr;
}
int info;
IntSLLNode *next;
};
class IntSLList {
public:
IntSLList() {
head = 0;
}
~IntSLList();
int isEmpty() {
return head == 0;
}
void addToHead(int);
void addToTail(int);
int deleteFromHead(); // delete the head and return its info;
int deleteFromTail(); // delete the tail and return its info;
bool isInList(int) const;
void printAll() const;
private:
IntSLLNode *head;
};
and here is the main
************************ main **************************
#include <iostream>
using namespace std;
#include "intSLList.h"
int print_reverse(IntSLList & list){
if (head == NULL)
return;
printReverse(head->next);
cout << head->data << " ";
//How to compelete this in an iterative(or recursive if iterative is too much work)way ?
//like this?
}
int main() {
IntSLList list;
list.print_reverse(list);
}
Added the functions

The header gives literally no way to access the contents of the list, other than by destroying it. So ... that's what we're going to do.
int deleteFromTail(); // delete the tail and return its info;
Except we need to go the extra step and rebuild it, because nobody expects printing the container to destory its contents. See https://en.wikipedia.org/wiki/Principle_of_least_astonishment
#include <iostream>
#include <stack>
#include <list>
class IntSLList {
public:
int isEmpty() { return m_list.empty(); }
void addToHead(int i) { m_list.push_front(i); }
void addToTail(int i) { m_list.push_back(i); }
int deleteFromHead() {
int temp = m_list.front();
m_list.pop_front();
return temp;
}
int deleteFromTail() {
int temp = m_list.back();
m_list.pop_back();
return temp;
}
private:
// no implementation given so I'm using std::list internally.
std::list<int> m_list;
};
int print_reverse(IntSLList& mylist) {
// store the data we are destroying in temp
IntSLList temp;
// literally the only way we can access the contents of the container is destructive so ... guess we're going there
while (!mylist.isEmpty()) {
int back = mylist.deleteFromTail();
std::cout << back << std::endl;
temp.addToHead(back);
}
// now rebuild the original list. I told you this would be bad.
while (!temp.isEmpty()) {
mylist.addToHead(temp.deleteFromTail());
}
// maybe this was supposed to be length, but not documented so I can return whatever I want.
return -1;
}
int main() {
IntSLList mylist;
mylist.addToTail(1);
mylist.addToTail(2);
mylist.addToTail(3);
print_reverse(mylist);
}
3
2
1

Related

How can I have a linked-list using class?

I'm trying to write a linked-list using class and I want it to have a specific format.
For example if I have three data called p1,p2 and p3 and a linked-list called list; I want to put them in order like blow.
list.insert(p1).insert(p2).insert(p3);
I tried to return the object, but didn't work.
Here's my code.
#include<iostream>
using namespace std;
class linked_list {
public:
int *head;
linked_list();
~linked_list();
linked_list insert(int data);
};
linked_list::linked_list()
{
head = NULL;
}
linked_list::~linked_list()
{
int *temp;
int *de;
for (temp = head;temp != NULL;) {
de = temp->next;
delete temp;
temp = de;
}
delete temp;
//delete de;
}
linked_list linked_list::insert(int data)
{
int *temp;
temp = new int;
*temp = data;
temp->next = NULL;
if (head == NULL) {
head = temp;
}
else {
int* node = head;
while (node->next != NULL) {
node = node->next;
}
node->next = temp;
// delete node;
}
//delete temp;
return *this;
}
int main(){
linked_list l1;
int p1,p2,p3;
l1.insert(p1).insert(p2).insert(p3);
return 0;}
#Jarod42 got your answer, despite all the buggy things around, what you want is something like this.
The function you want to chain must return a reference to your current object instance.
Here is a Foo class that change its _data member and chain multiple time.
#include <iostream>
class Foo
{
private:
int _data;
public:
Foo(int data) : _data(data) {}
~Foo()
{
}
// change the value of data then return a reference to the current Foo instance
Foo &changeData(int a)
{
_data = a;
return *this;
}
void printData()
{
std::cout << _data << std::endl;
}
};
int main()
{
Foo f(1);
f.changeData(2).changeData(3);
f.printData();
}
Note that I'm returning Foo& from the function I'm chaining, that's the little trick that is missing from yours.
Hope it helped you :)

Implementing a stack using an array

I just implemented a stack using an array and am curious as to why people start their tops at -1. Is it more inefficient to start at 0? I have a programming assignment to implement a stack that performs basic functions, and tried doing it on my own first.
After I got it to work I looked around to see other implementations. Most people start their tops at -1. Is there a benefit to that? Is it wrong to start at 0?
here's my working code:
header file:
#ifndef H_Stack
#define H_Stack
#include <iostream>
using namespace std;
struct nodeType
{
int info;
nodeType *link;
};
class arrayStack
{
private:
int stackSize;
int stackTop;
int *stackArray;
public:
arrayStack(const int &x);
void push(const int &x);
bool is_full();
bool is_empty();
int size();
int top();
void pop();
~arrayStack();
};
class linkedStack
{
private:
nodeType *stackTop;
public:
linkedStack();
void push(const int &x);
int size();
int top();
void pop();
bool is_empty();
~linkedStack();
};
#endif
Imp file:
#include "stack.h"
#include <iostream>
#include <cassert>
using namespace std;
arrayStack::arrayStack(const int &x)
{
if (x <= 0)
{
stackSize = 20;
stackArray = new int[stackSize];
}
else
{
stackTop = 0;
stackSize = x;
stackArray = new int[stackSize];
}
}
bool arrayStack::is_full()
{
return (stackTop == stackSize);
}
void arrayStack::push(const int &x)
{
if (!is_full())
{
stackArray[stackTop] = x;
stackTop++;
}
}
bool arrayStack::is_empty()
{
return (stackTop == 0);
}
int arrayStack::size()
{
return stackSize;
}
int arrayStack::top()
{
assert(stackTop != 0);
return stackArray[stackTop - 1];
}
void arrayStack::pop()
{
if (!is_empty())
stackTop--;
else
{
cout << "can't pop from an empty stack.";
}
}
arrayStack::~arrayStack()
{
delete[] stackArray;
}
linkedStack::linkedStack()
{
stackTop = nullptr;
}
void linkedStack::push(const int &x)
{
nodeType *newNode;
newNode = new nodeType;
newNode->info = x;
newNode->link = stackTop;
stackTop = newNode;
}
int linkedStack::size()
{
int count = 0;
nodeType *temp;
temp = stackTop;
while (temp != nullptr)
{
temp = temp->link;
count++;
}
return count;
}
int linkedStack::top()
{
assert(stackTop != nullptr);
return stackTop->info;
}
void linkedStack::pop()
{
assert(!is_empty());
nodeType *temp = stackTop;
stackTop = stackTop->link;
delete temp;
}
bool linkedStack::is_empty()
{
return (stackTop == nullptr);
}
linkedStack::~linkedStack()
{
while (stackTop != nullptr)
{
pop();
}
}
it successfully pops/pushes. It is not circular so its not efficient or very useful... but I had to write it for school.
Using an initial top of -1 allows you to implement push with just:
stackArray[++stackTop] = x;
That said, an initial top of 0 would just need an equally efficient, if slightly more verbose two-liner:
stackArray[stackTop] = x;
++stackTop;
or to keep it a one-liner:
stackArray[stackTop++] = x;
where the latter is perfectly fine as long as the top is a primitive type (for user-defined classes, post-increment is significantly less efficient, as it necessarily involves a complete copy of the state; some people avoid post-increment in C++ in general to develop habits that don't cause problems for user-defined classes).
Point is, there is no special benefit to -1 vs. 0; there may be conventions shared by the code you're looking at, but all of it works.

Vector returns negative size c++

For an exercize, I want to print out a tree data structure that is based on Node objects. This means, every object has a vector nodes that again holds other objects of type Node. But for some reason, when I let print out this->get_nr_children of the leaf nodes which basically just returns nodes.size(), I get completely random (negative) Integers where it should actually return 0. The even more interesting part: Every time I compile and execute, it prints out different Integers that alway are some low negative numbers. I do not have a clue what is happening!
Node.h
#include <string>
#include <vector>
using namespace std;
class Node
{
public:
virtual ~Node();
Node(string name = "");
string get_name() const;
void set_name(string& new_name);
int get_nr_children() const;
Node* get_child(int i) const;
void add_child(Node child);
void create_complete_tree(int nr_child_nodes, int tree_depth);
void print();
private:
string name;
static int node_id;
vector<Node> nodes = {};
};
Node.cpp
#include "node.h"
#include <sstream>
using namespace std;
Node::Node(string name) {
node_id++;
nodes = {};
if (name == "") {
stringstream str_sm;
str_sm << (node_id);
string node_id_str = str_sm.str();
this->name = "node_" + node_id_str;
} else {
this->name = name;
}
}
Node::~Node() {
nodes.clear();
// node_id = 0;
}
int Node::node_id = 0;
string Node::get_name() const {
return name;
}
void Node::set_name(string& new_name) {
this->name = new_name;
}
int Node::get_nr_children() const {
return nodes.size();
}
Node* Node::get_child(int i) const {
if (i >= nodes.size()) {
return NULL;
}
Node node = nodes[i];
Node *ptrNode = &node;
return ptrNode;
}
void Node::add_child(Node child) {
nodes.push_back(child);
}
void Node::create_complete_tree(int nr_child_nodes, int tree_depth) {
tree_depth--;
if (tree_depth <= 0) {
return;
}
for (int i = 0; i < nr_child_nodes; i++) {
Node* node = new Node();
this->add_child(*node);
node->create_complete_tree(nr_child_nodes, tree_depth);
}
}
void Node::print() {
cout << this->get_name() << "\n";
cout << "I got this many children " << this->get_nr_children();
for (int i = 0; i < this->get_nr_children(); i++) {
cout << "\t";
this->get_child(i)->print();
cout << "\n";
}
}
main.cpp
#include <iostream>
#include "node.cpp"
using namespace std;
int main() {
Node* root = new Node("root");
Node* left_child = new Node("left child");
Node* right_child = new Node("right child");
root->add_child(*left_child);
root->add_child(*right_child);
root->print();
return 0;
}
When I execute it I get:
root I got this many children 2 left child I got this many children
-62802357 right child I got this many children -62802357
Process finished with exit code 0
Your problem stems from
this->get_child(i)->print();
get_child returns a pointer to a local object. That object is destroyed when the function returns so the call to print on that returned Node is working with an already destroyed Node.
What you need to do is return a pointer directly to the vector element like
Node* Node::get_child(int i) /*const*/ { // cant be const for the return
if (i >= nodes.size()) {
return NULL;
}
return &nodes[i];
}
Node* Node::get_child(int i) const {
if (i >= nodes.size()) {
return NULL;
}
Node node = nodes[i];
Node *ptrNode = &node;
return ptrNode;
}
Above you return a pointer to destroyed local Node node after get_child(i) returned. Correct code is below, that returns a pointer to a child in the vector.
Node* Node::get_child(int i) const {
if (i >= nodes.size()) {
return NULL;
}
return &nodes[i];
}
main could be implemented much easier without pointers and memory leaks.
int main() {
Node root("root");
root.add_child(Node("left child"));
root.add_child(Node("right child"));
root.print();
return 0;
}
The problem is with the function Node* Node::get_child(int i) const. It returns a pointer to an object that is destroyed by the end of the function call.
Node* Node::get_child(int i) const {
if (i >= nodes.size()) {
return NULL;
}
Node node = nodes[i]; // <- node is a copy of nodes[i]
Node *ptrNode = &node;
return ptrNode; // <- returns a pointer to node
} // <- local objects are destroyed, including node
You must return a pointer to the actual element from the vector.
Node* Node::get_child(int i) const {
if (i >= nodes.size()) {
return NULL;
}
return &nodes[i]; // <- Returns the address of the actual node
}

Not able to output object in linked list

I have created a linked list and in each list consists a node that holds a CarPart object. I believe I have everything working, except outputting the cout. I get the following errors
'CarPart::getPartNumber': non-standard syntax; use '&' to create a pointer to member (carpart.cpp line 34)
'CarPart::getDescription': non-standard syntax; use '&' to create a pointer to member (carpart.cpp line 35)
'CarPart::getPrice': non-standard syntax; use '&' to create a pointer to member (carpart.cpp line 36)
I have tried changing the osstream operator and have not been able to figure out the issue.
Main.cpp
#include "stdafx.h"
#include "List.h"
int main()
{
List partsList;
partsList.push_front(new CarPart("FL2016", "Oil Filter", 18.95));
partsList.push_front(new CarPart("RS12YC", "Spark Plug", 4.15));
partsList.push_front(new CarPart("D5941", "Digital Tire Guage", 12.15));
partsList.push_back(new CarPart("G19216", "Car Wash Solution", 8.15));
partsList.display();
cout << "now we are going to remove the first item in the list" << endl;
system("PAUSE");
partsList.pop_front();
partsList.display();
system("PAUSE");
cout << "now we are going to remove the LAST item from the list" << endl;
partsList.pop_back();
partsList.display();
system("PAUSE");
return 0;
}
List.h
#pragma once
#include "node.h"
class List
{
private:
int listSize;
Node* n;
Node* temp;
Node* head;
Node* tail;
public:
List();
void push_front(CarPart*);
void push_back(CarPart*);
void pop_front();
void pop_back();
void display();
~List();
};
List.cpp
#include "stdafx.h"
#include "List.h"
List::List()
{
}
void List::push_front(CarPart* dat)
{
if (listSize == 0) {
n = new Node;
n->setData(dat);
listSize++;
temp = n;
head = n;
tail = n;
}
else {
n = new Node;
n->setData(dat);
listSize++;
temp = head;
head = n;
n->setNext(temp);
n->setPrevious(nullptr);
temp->setPrevious(n);
temp = n;
}
}
void List::push_back(CarPart* dat)
{
if (listSize == 0) {
n = new Node;
n->setData(dat);
listSize++;
temp = n;
head = n;
tail = n;
}
else {
n = new Node;
n->setData(dat);
listSize++;
temp = tail;
temp->setNext(n);
n->setPrevious(temp);
// SET NEXT TO NULL
temp = n;
tail = temp;
}
}
void List::pop_front()
{
temp = head->getNext();
delete head;
head = temp;
listSize--;
}
void List::pop_back()
{
temp = tail->getPrevious();
delete tail;
tail = temp;
tail->setNext(nullptr);
listSize--;
}
void List::display()
{
Node* test = head;
for (int i = 0; i < listSize; i++) {
cout << test;
}
}
List::~List()
{
}
Node.h
#pragma once
#include "CarPart.h"
class Node
{
private:
CarPart* data;
Node* next;
Node* previous;
public:
Node();
CarPart* getData();
void setData(CarPart*);
void setNext(Node*);
void setPrevious(Node*);
Node* getPrevious();
Node* getNext();
void display();
~Node();
};
Node.cpp
#include "stdafx.h"
#include "Node.h"
Node::Node()
{
}
CarPart* Node::getData()
{
return data;
}
void Node::setData(CarPart* dat)
{
data = dat;
}
void Node::setNext(Node* nextNode)
{
next = nextNode;
}
void Node::setPrevious(Node* prev)
{
previous = prev;
}
Node * Node::getPrevious()
{
return previous;
}
Node * Node::getNext()
{
return next;
}
void Node::display()
{
cout << data;
}
Node::~Node()
{
}
CarPart.h
#pragma once
#include <iostream>
using namespace std;
class CarPart
{
private:
string partNumber;
string description;
double price;
public:
CarPart();
CarPart(string, string, double);
string getPartNumber();
string getDescription();
double getPrice();
~CarPart();
friend ostream& operator<<(ostream& os, CarPart* dt);
};
CarPart.cpp
#include "stdafx.h"
#include "CarPart.h"
CarPart::CarPart()
{
}
CarPart::CarPart(string n, string d, double p)
{
partNumber = n;
description = d;
price = p;
}
string CarPart::getPartNumber()
{
return partNumber;
}
string CarPart::getDescription()
{
return description;
}
double CarPart::getPrice()
{
return price;
}
ostream& operator<<(ostream& os, CarPart* dt)
{
os << dt->getPartNumber;
os << dt->getDescription;
os << dt->getPrice;
return os;
}
CarPart::~CarPart()
{
}
Update
I fixed the error below, but it is not outputting the car parts, the console just shows 00820788008207880082078800820788. I assume it is just the pointer, but not sure what I am doing wrong.
You are calling your get functions incorrectly. You are using dt->getPartNumber; instead of using dt->getPartNumber();
To call a method/function, you always put brackets, even if there is no arguments (dt->getPartNumber()). This line
os << dt->getPartNumber()
means "pass to os the value returned by calling getPartNumber".
Otherwise, it interprets dt->getPartNumber as a pointer to the getPartNumber function, which is a very different beast.
NOTE: For future questions, try to post only the minimum code that causes the error instead of the entire program, and try to mark the line where the error is raised. Google for SSCCE.

Debug assertion failed

I get the "Debug assertion failed" error when my program ends. I've been trying to fix it for a long time and just can't find the cause. Even my prof in uni said he sees nothing wrong. So you are my last hope, stackoverllow. Please help.
The program finds the intersection of two lists and then checks if the third list is a subset of the intersection.
The screenshot of the error:
The code:
list.h:
#ifndef __LIST_H_INCLUDED__
#define __LIST_H_INCLUDED__
#include <string>
#include <iostream>
#include <fstream>
struct node
{
int value;
node *next;
};
class list
{
node* head;
public:
list();
~list();
void AddNodes(std::istream &input);
void PrintList(std::ostream &output = std::cout);
void AddOneNode(int AddVal);
node* RetHead();
list* Intersection(list* list2);
bool IsPresent(int val);
bool Subset(list subset);
};
#endif
list.cpp:
#include "stdafx.h"
#include "list.h"
#include <iostream>
#include <fstream>
list::list()
{
head=NULL;
}
list::~list()
{
node* current = head;
while( current != 0 )
{
node* next = current->next;
delete current;
current = next;
}
head = 0;
}
void list::AddNodes(std::istream &input)
{
int InVal;
while(input>>InVal)
AddOneNode(InVal);
}
void list::AddOneNode(int AddVal)
{
node *NewNode= new node;
NewNode->value=AddVal;
NewNode->next=NULL;
if(!head)
head=NewNode;
else
{
node *temp=head;
while(temp->next)
temp=temp->next;
temp->next=NewNode;
}
}
void list::PrintList(std::ostream &output)
{
node *temp=head;
while(temp)
{
output<<temp->value<<std::endl;
temp=temp->next;
}
}
list* list::Intersection(list *list2)
{
list* result=new list;
node* temp1=head;
while(temp1)
{
if(list2->IsPresent(temp1->value))
result->AddOneNode(temp1->value);
temp1=temp1->next;
}
return result;
}
bool list::IsPresent(int val)
{
node *temp=head;
while(temp)
{
if(temp->value==val)
return true;
temp=temp->next;
}
return false;
}
bool list::Subset(list subset) // head=set
{
bool flag;
node* tempset=head;
node* tempsub=subset.RetHead();
while(tempset)
{
if (tempsub->value==tempset->value)
{
flag=true;
break;
}
tempset=tempset->next;
}
if (!tempset)
return false;
while(tempsub)
{
tempsub=tempsub->next;
if(!tempsub)
return true;
while(tempsub->value!=tempset->value&&tempset)
tempset=tempset->next;
if(!tempset)
return false;
}
return flag;
}
node* list::RetHead()
{
return head;
}
main.cpp:
#include "stdafx.h"
#include "list.h"
#include <Windows.h>
#include <fstream>
list Cross (list list1, list list2);
bool Subset (list set, list subset);
int main()
{
setlocale (LC_ALL, "Russian");
list l1,l2,l3;
std::ifstream fl1 ("l1.txt");
std::ifstream fl2 ("l2.txt");
std::ifstream fl3 ("l3.txt");
l1.AddNodes(fl1);
std::cout<<"List 1:"<<std::endl;
l1.PrintList();
std::cout<<std::endl;
l2.AddNodes(fl2);
std::cout<<"List 2:"<<std::endl;
l2.PrintList();
std::cout<<std::endl;
l3.AddNodes(fl3);
std::cout<<"List 3:"<<std::endl;
l3.PrintList();
std::cout<<"Intersection of list 1 and list 2"<<std::endl;
list *intersec=l1.Intersection(&l2);
intersec->PrintList();
std::cout<<std::endl;
if(intersec->Subset(l3))
std::cout<<"Third set is a subset of the intersection"<<std::endl;
else
std::cout<<"Third set is not a subset of the intersection"<<std::endl;
system("pause");
return 0;
}
The problem is that the function list::Subset(list subset) takes its argument by value causing a copy of the list to be made. Since you did not follow the Rule of Three (as noted in Chris' comment) a shallow copy is made. This means that two instance of list "own" the pointers. When the Subset function returns the copy goes out of scope causing the nodes to be deleted. When the program exits the original copy of the list goes out of scope and it attempts to delete the same nodes again causing the assertion.
You can get around this by taking the argument by reference instead of by value. Change
class list
{
// ... snip ...
bool Subset(list subset);
// ... snip ...
};
to
class list
{
// ... snip ...
bool Subset(list& subset);
// ... snip ...
};
and
bool list::Subset(list subset)
{
// ... snip ...
}
to
bool list::Subset(list& subset)
{
// ... snip ...
}
Some other suggestions:
Either implement a proper copy constructor or declare one and make it private to prevent copies from being made
Learn const correctness. Since Subset does not modify the contents of the list passed to it you can declare it bool list::Subset(const list&) const instead. This will require list::RetHead() to be declared const as well.
bool flag in list::Subset is not initialized meaning that any value can be returned if your logic is not correct.