Reversing a singly-linked list in C++ - c++

I am having an issue with my attempt at recursively reversing my implementation of a singly-linked list.
I have read other similar questions regarding this process, however, in my attempt at implementing this process in my own program, I've come up short.
This is my attempt below (which is slightly different than what is presented in the code that follows thereafter):
Note: My list uses a root pointer which holds no significant data, and serves only as an address with which to reference data in the list.
void IntList::reverse(Node* t_node) {
if(t_node == NULL) {
reverse(root);
} else
if(t_node->next == NULL) {
cout << "In (swapping): " << t_node->value << endl;
root->next = t_node;
} else {
cout << "In: " << t_node->value << endl;
Node* tmp = t_node->next;
reverse(t_node->next);
tmp->next = t_node;
}
return NULL;
}
I lose reference somewhere and print endlessly when trying to display the list. I am really at a loss as to what the error I've made is, but suspect it may have something to do with how I handle my root.
Here is the program in its entirety (all functioning apart from the reverse() methods) for completeness.
#ifndef INTLIST_H
#define INTLIST_H
#include<iostream>
using namespace std;
class IntList {
private:
struct Node {
int value;
Node* next;
};
int size;
Node* root;
void destroy();
public:
IntList() { root = new Node; root->next = 0; root-> value = 0; size = 0;}
IntList(const IntList& list) { this->root = list.root; this->size = list.size; }
~IntList() {}
void appendNode(int val);
void insertNode(int pos, int val);
void deleteNode(int pos);
int searchNode(int val);
int getSize() const;
void print() const;
Node* reverse(Node* t_node);
int &operator[](int element) const;
void pop_back();
void pop_front();
void push_back(int val);
void push_front(int val);
};
void IntList::appendNode(int val) {
push_back(val);
}
void IntList::insertNode(int pos, int val) {
Node* tmp;
Node* current = root;
for(int i = 0; i < pos && current->next != NULL; i++) {
current = current->next;
}
tmp = new Node;
tmp->value = val;
tmp->next = current->next;
current->next = tmp;
size++;
}
void IntList::deleteNode(int pos) {
Node* tmp;
Node* current = root;
if(pos <= size-1) {
for(int i = 0; i < pos; i++) {
current = current->next;
}
tmp = current->next;
current->next = tmp->next;
delete tmp;
size--;
} else {
cout << "ERROR: Out of range." << endl;
}
}
int IntList::searchNode(int val) {
int position = 0;
Node* current = root->next;
if(size != 0) {
for(position = 0; position < size && current->value != val; position++) {
current = current->next;
}
} else {
cout << "ERROR: List is empty." << endl;
position = -1;
}
return position;
}
int IntList::getSize() const {
return size;
}
void IntList::print() const {
Node* current = root->next;
cout << "List: ";
while(current != NULL) {
cout << current->value << " ";
current = current->next;
}
if(getSize() == 0) {
cout << "Empty.";
}
cout << endl;
}
IntList::Node* IntList::reverse(Node* t_node) {
#define REVERSE
#ifndef REVERSE
if(t_node == NULL) {
reverse(root);
} else
if(t_node->next == NULL) {
cout << "In (swapping): " << t_node->value << endl;
root->next = t_node;
} else {
cout << "In: " << t_node->value << endl;
Node* tmp = t_node->next;
reverse(t_node->next);
tmp->next = t_node;
}
#endif //reverses list, but causes infinite loop in display
return NULL;
}
int &IntList::operator[](int pos) const {
Node* current = root->next;
if(pos <= size-1) {
for(int i = 0; i < pos; i++) {
current = current->next;
}
} else {
cout << "ERROR: Out of bounds.";
current = NULL;
}
return current->value;
}
void IntList::pop_back() {
deleteNode(size-1);
}
void IntList::pop_front() {
deleteNode(0);
}
void IntList::push_back(int val) {
insertNode(size, val);
}
void IntList::push_front(int val) {
insertNode(0, val);
}
#endif
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include<iostream>
using namespace std;
template<typename T>
class LinkedList {
private:
struct Node {
T value;
Node* next;
};
int size;
Node* root;
void destroy();
public:
LinkedList() { root = new Node; root->next = 0; root-> value = 0; size = 0;}
LinkedList(const LinkedList &) {}
~LinkedList() {}
void appendNode(T val);
void insertNode(int pos, T val);
void deleteNode(int pos);
int searchNode(T val);
int getSize() const;
void print() const;
void reverse(Node* t_node);
int &operator[](int element) const;
void pop_back();
void pop_front();
void push_back(T val);
void push_front(T val);
};
template <typename T>
void LinkedList<T>::appendNode(T val) {
push_back(val);
}
template <typename T>
void LinkedList<T>::insertNode(int pos, T val) {
Node* tmp;
Node* current = root;
for(int i = 0; i < pos && current->next != NULL; i++) {
current = current->next;
}
tmp = new Node;
tmp->value = val;
tmp->next = current->next;
current->next = tmp;
size++;
}
template <typename T>
void LinkedList<T>::deleteNode(int pos) {
Node* tmp;
Node* current = root;
if(pos <= size-1) {
for(int i = 0; i < pos; i++) {
current = current->next;
}
tmp = current->next;
current->next = tmp->next;
delete tmp;
size--;
} else {
cout << "ERROR: Out of range." << endl;
}
}
template <typename T>
int LinkedList<T>::searchNode(T val) {
int position = 0;
Node* current = root->next;
if(size != 0) {
for(position = 0; position < size && current->value != val; position++) {
current = current->next;
}
} else {
cout << "ERROR: List is empty." << endl;
position = -1;
}
return position;
}
template <typename T>
int LinkedList<T>::getSize() const {
return size;
}
template <typename T>
void LinkedList<T>::print() const {
Node* current = root->next;
cout << "List: ";
while(current != NULL) {
cout << current->value << " ";
current = current->next;
}
if(getSize() == 0) {
cout << "Empty.";
}
cout << endl;
}
template <typename T>
void LinkedList<T>::reverse(Node* t_node) {
/*
if(t_node == NULL) {
reverse(root);
} else
if(t_node->next == NULL) {
cout << "In (swapping): " << t_node->value << endl;
root->next = t_node;
} else {
cout << "In: " << t_node->value << endl;
Node* tmp = t_node->next;
reverse(t_node->next);
tmp->next = t_node;
}
*/ //reverses list, but causes infinite loop in display
}
template <typename T>
int &LinkedList<T>::operator[](int pos) const {
Node* current = root->next;
if(pos <= size-1) {
for(int i = 0; i < pos; i++) {
current = current->next;
}
} else {
cout << "ERROR: Out of bounds.";
current = NULL;
}
return current->value;
}
template <typename T>
void LinkedList<T>::pop_back() {
deleteNode(size-1);
}
template <typename T>
void LinkedList<T>::pop_front() {
deleteNode(0);
}
template <typename T>
void LinkedList<T>::push_back(T val) {
insertNode(size, val);
}
template <typename T>
void LinkedList<T>::push_front(T val) {
insertNode(0, val);
}
#endif
//test driver
int main() {
IntList i_list;
int n;
cout << "Appending node: value = " << 0 << endl;
i_list.appendNode(0);
i_list.print();
cout << endl;
n = 5;
cout << "Inserting nodes (at their values). Node values = { ";
for(int i = 0; i < n; i++) {
cout << i << " ";
i_list.insertNode(i,i);
}
cout << "}" << endl;
i_list.print();
cout << endl;
cout << "Deleting node at position: " << i_list.getSize()-1 << endl;
i_list.deleteNode(i_list.getSize()-1);
i_list.print();
cout << endl;
cout << "Searching for value: " << 3 << endl;
cout << "Found at: " << i_list.searchNode(3) << endl;
cout << endl;
i_list.print();
cout << "List size: " << i_list.getSize() << endl;
cout << endl;
n = 3;
cout << "Calling node at list[" << n << "]: " << i_list[n] << endl;
cout << endl;
i_list.print();
cout << "Deleting node from back position." << endl;
i_list.pop_back();
i_list.print();
cout << endl;
i_list.print();
cout << "Deleting node from front position." << endl;
i_list.pop_front();
i_list.print();
cout << endl;
n = 9;
i_list.print();
cout << "Adding node (value = " << n << ") to back position." << endl;
i_list.push_back(n);
i_list.print();
cout << endl;
n = 8;
i_list.print();
cout << "Adding node (value = " << n << ") to front position." << endl;
i_list.push_front(n);
i_list.print();
cout << endl;
i_list.print();
cout << "Copying list to new list." << endl;
IntList t_list(i_list);
cout << endl;
cout << "List copy:" << endl;
t_list.print();
cout << endl;
/*
* Showing functionality transfers over to LinkedList template class
* generally, for primitive data types (lacks absolutely generality
* for data which can't be passed directly to cout).
*/
cout << "List functionality transfers generally to LinkedList class:" << endl;
LinkedList<int> int_list;
LinkedList<double> double_list;
LinkedList<char> char_list;
cout << "Appending nodes:" << endl;
n = 5;
for(int i = 0; i < n; i++){
int_list.appendNode(i);
}
int_list.print();
n = 5;
for(int i = 0; i < n; i++){
double_list.appendNode(i+0.1);
}
double_list.print();
n = 5;
for(int i = 0; i < n; i++){
char_list.appendNode('A' + i);
}
char_list.print();
cout << "Removing nodes:" << endl;
n = 5;
for(int i = 0; i < n; i++){
int_list.pop_back();
}
int_list.print();
n = 5;
for(int i = 0; i < n; i++){
double_list.pop_back();
}
double_list.print();
n = 5;
for(int i = 0; i < n; i++){
char_list.pop_back();
}
char_list.print();
return 0;
}
EDIT: I've revised my algorithm, and I believe it works algorithmically, but functionally it may be doing something which is causing a memory issue. I'm not sure as to why that may be, but here it is:
void IntList::reverse() {
IntList tmp(*this);
int list_size = size;
for(int i = 0; i < list_size; i++) {
this->insertNode(i, tmp[tmp.getSize()-1]);
this->pop_back();
tmp.pop_back();
}
}
In fact, if my [] operator overload were functioning within this method (which for some reason it is not?) I could do away with the tmp list and just reference the last value in the list directly as this[size-1].
What is the issue here?

Your problem is that after the reverse() the last element in your list will point to the root element instead of pointing to null. One solution could be an explicit check for that condition so you would get:
void IntList::reverse(Node* t_node) {
if(t_node == NULL) {
reverse(root);
return;
}
if(t_node->next == NULL) {
cout << "In (swapping): " << t_node->value << endl;
root->next = t_node;
} else {
cout << "In: " << t_node->value << endl;
Node* tmp = t_node->next;
reverse(t_node->next);
// If this node was the first node it will now be the last
if (t_node == root) {
tmp->next = NULL;
} else {
tmp->next = t_node;
}
}
}
That doesn't work if it should be possible to reverse a subpart of the list though. If that is something you need, then you probably need to use a helper function which handles all elements but the first one.

Suppose we have the IntList {1,2,3}, which actually has this form:
0 -> 1 -> 2 -> 3
Then we call reverse(root), so that t_node has the same value as root (and therefore points to (0)).
Node* tmp = t_node->next;
So tmp points to (1).
reverse(t_node->next);
Suppose this works, and the list is now 0->1->3->2
tmp->next = t_node;
So now 1->0. The list is now a loop, and the other nodes have been lost.
It is not clear what you intended this function to do, but you must have misunderstood something.
EDIT: You are attempting a high-level solution when you do not understand the low-level mechanics.
Your copy constructor:
IntList(const IntList& list) { this->root = list.root; this->size = list.size; }
performs what we call a "shallow copy"; it copies the pointer members, but not the things they point to. If you have a list A that looks like this:
0->1->2->3
and then call IntList B(A);, you'll get something that looks like this:
0
|
v
0->1->2->3
If you then call A.pop_back() and B.pop_back(), what do you think will happen?
And more to the point, what are you trying to do? Do you want to know how to write a recursive function, or is that no longer necessary?

Related

Program.exe has triggered a breakpoint in destructor of linked list class

When I run my program, everything works as expected until the destructor of the LList class. On the line that says delete current;, I get the following error:
BlankConsoleLab.exe has triggered a breakpoint.
I have been trying to solve this issue for a long time. I would appreciate it if perhaps someone could try to point out what I am doing wrong here.
Below is my code for the program. Thank you
Linked List Class
class LList
{
private:
Node* head;
Node* tail;
int size = 0;
public:
LList()
{
head = nullptr;
tail = nullptr;
size = 0;
}
LList(Node* h, Node* t)
{
this->head = h;
this->tail = t;
}
~LList()
{
Node* current = head;
while (current != nullptr) {
Node* next = current->m_next;
delete current;
current = next;
}
}
void print()
{
//temporary node pointer to traverse through the linked list
Node* temp = head;
cout << endl << "<MY LINKED LIST>\n";
while (temp != nullptr)
{
cout << temp->m_data.firstName << " ";
cout << temp->m_data.lastName << " ";
cout << temp->m_data.hrWage << " ";
cout << temp->m_data.hrWork << " " << endl;
temp = temp->m_next;
}
cout << endl;
}
void removeFirst()
{
//case 1: linked list is empty (never enters loop)
//case 2: linked list is not empty
if (head != nullptr)
{
Node* temp = head;
head = head->m_next;
delete temp;
//decrease size tracker of the linked list
size--;
}
}
void removeLast()
{
//case 1: linked list is empty (never enters loop)
//case 2: linked list has one node
if (head->m_next == nullptr)
{
removeFirst();
}
//case 3: linked list has more than one node
else if (head != nullptr)
{
Node* cur = head;
Node* prev = nullptr;
while (cur->m_next != nullptr)
{
prev = cur;
cur = cur->m_next;
}
tail = prev;
tail->m_next = nullptr;
delete cur;
//decrease size tracker of the linked list
size--;
}
}
//void removeAt(int pos)
//{
// //Case 1: input is invalid (less than 1 or greater than size)
// if (pos < 1 && pos > size)
// {
// return;
// }
// //Case 2: input is position 1
// else if (pos == 1)
// {
// removeFirst();
// }
// //Case 3: input is the last position (input equals size)
// else if (pos == size)
// {
// removeLast();
// }
// //Case 4: input is valid, and not 1 or last position (greater than 1 and less than size)
// else if (head != nullptr)
// {
// Node* cur = head;
// Node* prev = nullptr;
// for (int i = 1; i < pos; i++)
// {
// prev = cur;
// cur = cur->m_next;
// }
// prev->m_next = cur->m_next;
// delete cur;
// size--;
// }
//}
Node* swap(Node* lh, Node* rh)
{
Node* temp = rh->m_next;
rh->m_next = lh;
lh->m_next = temp;
return rh;
}
void readBin()
{
ifstream file;
file.open("C:\\Users\\there\\source\\repos\\cst126-lab9-JEmersonLawrance\\BlankConsoleLab\\Employee Data.bin", ios::binary);
if (file)
{
Node* cur = head;
Node* prev = nullptr;
for (int i = 0; i < 4; i++)
{
file.read((char*)&cur->m_data.firstName, sizeof(cur->m_data.firstName));
file.read((char*)&cur->m_data.lastName, sizeof(cur->m_data.lastName));
file.read((char*)&cur->m_data.hrWage, sizeof(cur->m_data.hrWage));
file.read((char*)&cur->m_data.hrWork, sizeof(cur->m_data.hrWork));
prev = cur;
cur = cur->m_next;
}
return;
}
else
{
cout << "File could not be opened..\n" << endl;
}
file.close();
}
void writeBin()
{
ofstream file;
file.open("Employee Data Output.bin", ios::binary);
if (file)
{
Node* cur = head;
Node* prev = nullptr;
while (cur != nullptr)
{
file.write((char*)&cur->m_data.firstName, sizeof(cur->m_data.firstName));
file.write((char*)&cur->m_data.lastName, sizeof(cur->m_data.lastName));
file.write((char*)&cur->m_data.hrWage, sizeof(cur->m_data.hrWage));
file.write((char*)&cur->m_data.hrWork, sizeof(cur->m_data.hrWork));
prev = cur;
cur = cur->m_next;
}
}
else
{
cout << "File could not be opened..\n" << endl;
}
file.close();
}
};
Node Class
class Node
{
public:
Employee m_data;
Node* m_next;
Node()
{
m_data.firstName = "";
m_data.lastName = "";
m_data.hrWage = 0;
m_data.hrWork = 0;
m_next = nullptr;
}
Node(Node* next)
{
m_data.firstName = "";
m_data.lastName = "";
m_data.hrWage = 0;
m_data.hrWork = 0;
m_next = next;
}
Node(const Node& copy)
{
m_data.firstName = copy.m_data.firstName;
m_data.lastName = copy.m_data.lastName;
m_data.hrWage = copy.m_data.hrWage;
m_data.hrWork = copy.m_data.hrWork;
}
Node operator = (const Node& copy)
{
m_data.firstName = copy.m_data.firstName;
m_data.lastName = copy.m_data.lastName;
m_data.hrWage = copy.m_data.hrWage;
m_data.hrWork = copy.m_data.hrWork;
return *this;
}
~Node()
{
}
};
Employee Class
struct Employee
{
public:
string firstName;
string lastName;
int hrWage;
int hrWork;
Employee()
{
firstName = "";
lastName = "";
hrWage = 0;
hrWork = 0;
}
Employee(string first, string last, int wage, int work)
{
firstName = first;
lastName = last;
hrWage = wage;
hrWork = work;
}
~Employee()
{
}
void getInput()
{
for (int i = 0; i < 4; i++)
{
cout << "EMPLOYEE # " << i+1 << ":\n" << endl;
cout << "First name: ";
cin >> this[i].firstName;
cout << "Last name: ";
cin >> this[i].lastName;
cout << "Hourly Wage: ";
cin >> this[i].hrWage;
cout << "Hours Worked: ";
cin >> this[i].hrWork;
}
}
void writeBin()
{
ofstream file;
file.open("C:\\Users\\there\\source\\repos\\cst126-lab9-JEmersonLawrance\\BlankConsoleLab\\Employee Data.bin", ios::binary);
if (file)
{
for (int i = 0; i < 4; i++)
{
file.write((char*)&this[i].firstName, sizeof(this[i].firstName));
file.write((char*)&this[i].lastName, sizeof(this[i].lastName));
file.write((char*)&this[i].hrWage, sizeof(this[i]).hrWage);
file.write((char*)&this[i].hrWork, sizeof(this[i]).hrWork);
}
}
else
{
cout << "File could not be opened..\n" << endl;
}
file.close();
}
};
Main Function
int main()
{
cout << "In this program, LIST will read the user information"
<< " in from a binary file, and output it into a different binary"
<< " file.\n" << endl;
Employee data[4];
data->getInput();
data->writeBin();
//creating linked list
Node fourth;
Node third(&fourth);
Node second(&third);
Node first(&second);
LList LIST(&first, &fourth);
LIST.readBin();
LIST.writeBin();
LIST.print();
return 0;
}
In main(), you are constructing your LIST object with pointers to local Node objects that are created in automatic memory within main()'s call frame. When main() exits, all of its local variables are destroyed automatically. But, when the LIST object is destroyed, its destructor tries to call delete on those Node objects which were not created in dynamic memory with new. Thus, your code exhibits undefined behavior.

Count Leaf Nodes In a Generic Tree (Recursively)

I am trying to make a C++ program to count the number of Leaf Nodes in a generic tree using a Recurisve approach.
here is my code:
int countLeafNodes(TreeNode<int> *root)
{
if (root = NULL)
{
return 0;
}
int total = 0;
if (root->children.size() == 0)
{
return 1;
}
for (int i = 0; i < root->children.size(); i++)
{
total += countLeafNodes(root->children[i]);
}
return total;
}
int main()
{
TreeNode<int> *root = takeInputLevelWise();
cout << "Total Leaf Nodes = " << countLeafNodes(root) << endl;
return 0;
}
But I don't get any output on my editor (vs code) so I tested it on an online judge and it was giving SIGSEGV error. I know we get that error for an Invalid memory reference but I don't understand where in my code I am doing that mistake. Please someone tell me what's wrong with the code and why it is not working.
here is the complete code:
#include <bits/stdc++.h>
using namespace std;
template <typename T>
class TreeNode
{
public:
T data;
vector<TreeNode<T> *> children;
TreeNode(T data)
{
this->data = data;
}
~TreeNode()
{
for (int i = 0; i < children.size(); i++)
{
delete children[i];
}
}
};
TreeNode<int> *takeInputLevelWise()
{
int rootData;
cout << "Enter Root Data" << endl;
cin >> rootData;
TreeNode<int> *root = new TreeNode<int>(rootData);
queue<TreeNode<int> *> pendingNode;
pendingNode.push(root);
while (!pendingNode.empty())
{
TreeNode<int> *front = pendingNode.front();
pendingNode.pop();
int numChild;
cout << "Enter number of children of " << front->data << endl;
cin >> numChild;
for (int i = 0; i < numChild; i++)
{
int childData;
cout << "Enter " << i << "th child of " << front->data << endl;
cin >> childData;
TreeNode<int> *child = new TreeNode<int>(childData);
front->children.push_back(child);
pendingNode.push(child);
}
}
return root;
}
int countLeafNodes(TreeNode<int> *root)
{
if (root = NULL)
{
return 0;
}
int total = 0;
if (root->children.size() == 0)
{
return 1;
}
for (int i = 0; i < root->children.size(); i++)
{
total += countLeafNodes(root->children[i]);
}
return total;
}
int main()
{
TreeNode<int> *root = takeInputLevelWise();
cout << "Total Leaf Nodes = " << countLeafNodes(root) << endl;
return 0;
}
I am pretty sure there is no problem with the TreeNode class or takeInputLevelWise() function as I have used the same code in many other questions to generate the tree. The problem must be in the countLeafNodes() function.
There is a problem in your countLeafNodes function.
if (root = NULL)
{
return 0;
}
Hope you find the error.

finding min, max, and average of linked list

I have a program in which I'm supposed to build functions using linked lists to perform a variety of tasks. Currently, I am having an issue finding the min and max value of the linked list. For some reason when both come out to be the highest which digit which is 9, and when I try to find the average of the list, it still comes out as 9.
additionally, I think it's interfering with my pop function which is supposed to delete the last item, but when I try to work it by sections one part wont work until he previous section is running for whatever reason.
here is my header
#include <iostream>
using std::cout;
using std::endl;
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
class LinkedList
{
private:
struct Node
{
int data;
Node *next;
};
int size;
Node *head, *tail;
public:
LinkedList();
~LinkedList();
// misc
void display();
// sorting and searching
// reverse --> sorting in descending
int linearSearch(int key);
void sort();
void reverse();
// various math
int min();
int max();
int mean();
// adding
void append(int num);
void insert(int num, int pos);
// removing
void pop();
void remove(int pos);
};
#endif // LINKEDLIST_H
the header's source file
#include "linkedlist.h"
LinkedList::LinkedList()
{
head = nullptr;
tail = nullptr;
size = 0;
}
LinkedList::~LinkedList()
{
if(head != nullptr)
{
Node *temp;
while(head != nullptr)
{
temp = head->next;
// deletes head
delete head;
// goes to next element
head = temp;
}
}
}
void LinkedList::display()
{
Node *temp = head;
for(int i = 0; i < size; i++)
{
cout << temp->data << "\t";
temp = temp->next;
}
cout << endl;
}
void LinkedList::append(int num)
{
// list is empty
if(head == nullptr)
{
head = new Node;
head->data = num;
head->next = nullptr;
// sets tail to head
tail = head;
}
else
{
// creates new node
Node *temp = new Node;
// sets new node data
temp->data = num;
temp->next = nullptr;
// sets previous tail link to new node
tail->next = temp;
// sets this node to new tail
tail = temp;
}
// increments size
size++;
}
void LinkedList::pop()
{
if(size > 1)
{
Node *temp = head;
// loops to node before tail
while(temp->next->next != nullptr)
{
temp = temp->next;
}
// deletes tail
delete tail;
// sets new tail
tail = temp;
tail->next = nullptr;
}
// if there's only one item
else if(size == 1)
{
Node *temp = tail;
// head and tail are now null
head = nullptr;
tail = nullptr;
// deletes node
delete temp;
}
size--;
}
void LinkedList::insert(int num, int pos)
{
if(pos ==0)
{
Node *temp=new Node;
temp->data=num;
temp->next=head;
head=temp;
}
if(pos>1)
{
Node *pre=new Node;
Node *cur=new Node;
Node *temp=new Node;
cur=head;
for(int i=1;i<pos+1;i++)
{
pre=cur;
cur=cur->next;
}
temp->data=num;
pre->next=temp;
temp->next=cur;
}
size++;
}
int LinkedList::linearSearch(int key)
{
Node *temp = head;
for(int i = 0; i < size; i++)
{
if(temp->data == key)
{
return i;
}
temp = temp->next;
}
return -1;
}
int LinkedList::max()
{
int max = INT_MIN;
for(int i = 0; i < size; i++)
{
while (head != NULL)
{
if (head->data < max)
max = head->data;
head = head->next;
}
}
}
int LinkedList::min()
{
int min = INT_MAX;
for(int i = 0; i < size; i++)
{
while (head != NULL)
{
if (head->data < min)
min = head->data;
head = head->next;
}
}
}
void LinkedList::reverse()
{
Node* temp = head;
// Traverse the List
while (temp) {
Node* min = temp;
Node* r = temp->next;
// Traverse the unsorted sublist
while (r)
{
if (min->data < r->data)
min = r;
r = r->next;
}
// Swap Data
int x = temp->data;
temp->data = min->data;
min->data = x;
temp = temp->next;
}
}
void LinkedList::remove(int pos)
{
Node *temp = head;
if(pos ==0)
{
head = temp->next;
free(temp);
}
if(pos>1)
{
for(int i=0; temp!=NULL && i<pos-1;i++)
{
temp=temp->next;
}
temp->next = temp->next->next;
free(temp->next);
temp->next = temp->next;
}
size--;
}
int LinkedList::mean()
{
int sum = 0;
float avg = 0.0;
Node *temp = head;
while (head != NULL)
{
sum += temp->data;
temp = temp->next;
}
// calculate average
avg = (double)sum / size;
}
void LinkedList::sort()
{
Node* temp = head;
// Traverse the List
while (temp) {
Node* min = temp;
Node* r = temp->next;
// Traverse the unsorted sublist
while (r) {
if (min->data > r->data)
min = r;
r = r->next;
}
// Swap Data
int x = temp->data;
temp->data = min->data;
min->data = x;
temp = temp->next;
}
}
And the main
#include <iostream>
#include "linkedlist.h"
using namespace std;
int main()
{
LinkedList nums;
// adding through append
nums.append(8);
nums.append(6);
nums.append(7);
nums.append(8);
nums.append(0);
nums.append(9);
// displays list
cout << "List after append: " << endl;
nums.display();
cout << endl;
// adding through insert
nums.insert(1, 0);
nums.insert(5, 4);
nums.insert(3, 8);
// displays list
cout << "List after inserting: " << endl;
nums.display();
cout << endl;
// testing searching
cout << "Testing linear search:" << endl;
int pres = nums.linearSearch(7);
if(pres < 0)
{
cout << "7 is not present in the list." << endl;
}
else
{
cout << "7 can be found at location " << pres << endl;
}
pres = nums.linearSearch(5);
if(pres < 0)
{
cout << "5 is not present in the list." << endl;
}
else
{
cout << "5 can be found at location " << pres << endl;
}
cout << endl;
// does math
cout << "Minimum, maximum, and average before removing any items: " << endl;
cout << "Min: " << nums.min() << endl;
cout << "Max: " << nums.max() << endl;
cout << "Mean: " << nums.mean() << endl << endl;
// displays items reversed
cout << "Items reversed: " << endl;
nums.reverse();
nums.display();
cout << endl;
// removing through pop
nums.pop();
nums.pop();
// displays list
cout << "List after popping: " << endl;
nums.display();
cout << endl;
// removing through remove
nums.remove(0);
nums.remove(2);
nums.remove(4);
// displays list
cout << "List after removing: " << endl;
nums.display();
cout << endl;
// displays items sorted
cout << "Items sorted: " << endl;
nums.sort();
nums.display();
cout << endl;
// does math
cout << "Minimum, maximum, and average after removing items: " << endl;
cout << "Min: " << nums.min() << endl;
cout << "Max: " << nums.max() << endl;
cout << "Mean: " << nums.mean() << endl << endl;
// testing searching
cout << "Testing linear search:" << endl;
pres = nums.linearSearch(7);
if(pres < 0)
{
cout << "7 is not present in the list." << endl;
}
else
{
cout << "7 can be found at location " << pres << endl;
}
pres = nums.linearSearch(5);
if(pres < 0)
{
cout << "5 is not present in the list." << endl;
}
else
{
cout << "5 can be found at location " << pres << endl;
}
return 0;
}
the only parts I'm really struggling with is the max, min, and mean along with getting my pop function to actually initiate. I know that the pop function is written correctly but ever since I made the max and min it wont work now.
There are several bugs that I have found in the code, and I have several remarks about it:
You should use spaces, and more consistently. There are places without enough spacing, and places with too many blank lines!
If you have two functions such as insert and append or pop and remove, they should use each other, meaning, append is just insert(0) (notice how I changed it in the code).
You are using double loops where it doesn't make sense (it isn't an error, but it is a bug!).
In the function max, you were doing the wrong comparison, asking if max is bigger than the current value...
You never return a value from min and max, which should at least create a warning in the compilation process!
You were creating empty nodes, and then you just put different values in their pointers, meaning that this new memory was still allocated (since there was no delete), but there was no way to access these anymore (this is a memory leak).
The biggest bug of all - When you loop in the min and max functions, you change the head of the list, which is a major bug (and that is why you got bugs after using this function). The solution is a simple but important lesson in C++ - Const Correctness.
What is const correctness, and why is it important?
When you have a function, that does not change the state of your object, it should be declared const. This is our way to tell the compiler (and other programmers) that it mustn't change the state of our object. For example, min, max and average are classic const functions - they simply make a calculation that does not change the list, and return. If you had written const in the declaration of those, the compilation would have failed, since you actually changed the list (changing the head), although you shouldn't!
Moreover, when receiving objects into a function, whenever possible, you should make the const T& where T is a type. They will enforce that you are using only const functions of this type.
Also, I suggest compiling (at least on g++) with the flags -Wpedantic -Werror'. The first adds some warnings about ISO C++ standards and the second makes all warnings into errors (and thus, yourmin,maxandmean` should not compile, since they don't return a value).
Here is the code:
class LinkedList
{
private:
struct Node
{
int data;
Node *next;
Node(int data_, Node* next_ = nullptr) :
data(data_),
next(next_)
{
}
};
int size;
Node *head, *tail;
public:
LinkedList();
~LinkedList();
void clear();
// various math
int min() const;
int max() const;
int average() const;
// adding
void append(int data);
void insert(int data, int pos);
// removing
void pop();
void remove(int pos);
};
LinkedList::LinkedList()
{
head = nullptr;
tail = nullptr;
size = 0;
}
LinkedList::~LinkedList()
{
clear();
}
void LinkedList::clear()
{
if (head != nullptr)
{
Node *temp;
while(head != nullptr)
{
temp = head->next;
delete head;
head = temp;
}
}
head = nullptr;
tail = nullptr;
size = 0;
}
void LinkedList::display()
{
Node *temp = head;
for(int i = 0; i < size; i++)
{
std::cout << temp->data << "\t";
temp = temp->next;
}
std::cout << std::endl;
}
void LinkedList::insert(int data, int pos)
{
if (pos == 0)
{
Node* prev_head = head;
head = new Node(data, prev_head);
if (size == 0)
{
tail = head;
}
}
else
{
Node *pre=nullptr;
Node *cur = head;
for(int i = 0 ; i < pos + 1; ++i)
{
pre = cur;
cur = cur->next;
}
Node *temp = new Node(data, cur);
pre->next = temp;
}
++size;
}
void LinkedList::append(int data)
{
insert(data, 0);
}
void LinkedList::pop()
{
if (size == 1)
{
Node *temp = tail;
head = nullptr;
tail = nullptr;
delete temp;
}
else
{
Node *temp = head;
while(temp->next != tail)
{
temp = temp->next;
}
Node* node_to_pop = tail;
tail = temp;
tail->next = nullptr;
delete node_to_pop;
}
--size;
}
int LinkedList::max() const
{
int max = INT_MIN;
for (Node* temp = head; temp != nullptr; temp = temp->next)
{
if (temp->data > max)
{
max = temp->data;
}
}
return max;
}
int LinkedList::min() const
{
int min = INT_MAX;
for(Node* temp = head; temp != nullptr; temp = temp->next)
{
if (head->data < min)
{
min = temp->data;
}
}
return min;
}
int LinkedList::average() const
{
int sum = 0;
for(Node* temp = head; temp != nullptr; temp = temp->next)
{
sum += temp->data;
temp = temp->next;
}
return (double)sum / size;
}

c++ Stuck making an binary tree implementation with an array and lists

I am working on writing a list of children binary tree implementation. In my code I have an array of lists. Each list contains a node followed by its children on the tree. I finished writing the code and everything compiled, but I keep getting a segmentation fault error and I cannot figure out why. I have been attempting to debug and figure out where my code messes up. I know that there is an issue with the FIRST function. It causes a segmentation fault. Also, when I try to print just one of the lists of the array, it prints everything. I have been stuck on this for a very long time now and would like some help. Can anyone offer suggestions as to why the FIRST and PRINT functions are not working? Maybe there is a large error that I just cannot see.
My code is as follows:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <array>
#include <string.h>
using namespace std;
struct node
{
char element;
struct node *next;
}*start;
class list
{
public:
void ADD(char n);
node* CREATE(char n);
void BEGIN(char n);
char FIRST();
char END();
char NEXT(char n);
char PREVIOUS(char n);
int LOCATE(char n);
void EMPTY();
void PRINT();
list()
{
start = NULL;
}
};
char PARENT(const char n, list tree[], int length)
{
int i=0;
list l;
for (i; i<length; i++)
{
l = tree[i];
if (n != l.FIRST())
{
if (l.LOCATE(n)>0)
return l.FIRST();
}
}
}
char LEFTMOST_CHILD(char n, list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
if (l.FIRST() == n)
return l.NEXT(n);
}
}
char RIGHT_SIBLING(char n, list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
if(n != l.FIRST())
{
if (l.LOCATE(n) > 0)
{
return l.NEXT(n);
}
}
}
}
char ROOT(list tree[]) //assumes array is in order, root is first item
{
list l;
l = tree[0];
cout << "Assigned tree to l" << endl;
return l.FIRST();
}
void MAKENULL(list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
l.EMPTY();
}
}
void list::PRINT()
{
struct node *temp;
if (start == NULL)
{
cout << "The list is empty" << endl;
return;
}
temp = start;
cout << "The list is: " << endl;
while (temp != NULL)
{
cout << temp->element << "->" ;
temp = temp->next;
}
cout << "NULL" << endl << endl;
}
void list::EMPTY()
{
struct node *s, *n;
s = start;
while (s != NULL)
{
n = s->next;
free(s);
s = n;
}
start = NULL;
}
int list::LOCATE(char n)
{
int pos = 0;
bool flag = false;
struct node *s;
s = start;
while (s != NULL)
{
pos++;
if (s->element == n)
{
flag == true;
return pos;
}
s = s->next;
}
if (!flag)
return -1;
}
void list::ADD(char n)
{
struct node *temp, *s;
temp = CREATE(n);
s = start;
while (s->next != NULL)
s = s->next;
temp->next = NULL;
s->next = temp;
}
node *list::CREATE(char n)
{
struct node *temp;
temp = new(struct node);
temp->element = n;
temp->next = NULL;
return temp;
}
void list::BEGIN(char n)
{
struct node *temp, *p;
temp = CREATE(n);
if (start == NULL)
{
start = temp;
start->next = NULL;
}
}
char list::FIRST()
{
char n;
struct node *s;
s = start;
cout << "s = start" << endl;
n = s->element;
cout << "n" << endl;
return n;
}
char list::END()
{
struct node *s;
s = start;
int n;
while (s != NULL)
{
n = s->element;
s = s->next;
}
return n;
}
char list::NEXT(char n)
{
char next;
struct node *s;
s = start;
while (s != NULL)
{
if (s->element == n)
break;
s = s->next;
}
s = s->next;
next = s->element;
return next;
}
char list::PREVIOUS(char n)
{
char previous;
struct node *s;
s = start;
while (s != NULL)
{
previous = s->element;
s = s->next;
if (s->element == n)
break;
}
return previous;
}
main()
{
list a,b,c,d,e,f,g,h,i,j,k,l,m,n;
a.BEGIN('A');
b.BEGIN('B');
c.BEGIN('C');
d.BEGIN('D');
e.BEGIN('E');
f.BEGIN('F');
g.BEGIN('G');
h.BEGIN('H');
i.BEGIN('I');
j.BEGIN('J');
k.BEGIN('K');
l.BEGIN('L');
m.BEGIN('M');
n.BEGIN('N');
a.ADD('B');
a.ADD('C');
b.ADD('D');
b.ADD('E');
e.ADD('I');
i.ADD('M');
i.ADD('N');
c.ADD('F');
c.ADD('G');
c.ADD('H');
g.ADD('J');
g.ADD('K');
h.ADD('L');
a.PRINT();
list tree[] = {a,b,c,d,e,f,g,h,i,j,k,l,m,n};
int length = sizeof(tree)/sizeof(char);
char root = ROOT(tree);
cout << "Found root" << endl;
char parent = PARENT('G', tree, length);
cout << "Found Parent" << endl;
char leftChild = LEFTMOST_CHILD('C', tree, length);
cout << "found left child" << endl;
char rightSibling = RIGHT_SIBLING('D', tree, length);
cout << "found right sibling" << endl;
cout << "The root of the tree is: ";
cout << root << endl;
cout << "The parent of G is: ";
cout << parent << endl;
cout << "The leftmost child of C is" ;
cout << leftChild << endl;
cout << "The right sibling of D is: " ;
cout << rightSibling << endl;
}
Any help will be very appreciated. Thanks you!
The fundamental problem is that you have written a lot of code before testing any of it. When you write code, start with something small and simple that works perfectly, add complexity a little at a time, test at every step, and never add to code that doesn't work.
The specific problem (or at least one fatal problem) is here:
struct node
{
char element;
struct node *next;
}*start;
class list
{
public:
//...
list()
{
start = NULL;
}
};
The variable start is a global variable. The class list has no member variables, but uses the global variable. It sets start to NULL every time a list is constructed, and every list messes with the same pointer. The function FIRST dereferences a pointer without checking whether the pointer is NULL, and when it is, you get Undefined Behavior.
It's not entirely clear what you intended, but you seem to misunderstand how variables work in C++.

Can't add to linked list in switch

I tested my class member function to add to a linked list outside of my switch and it works. But when I try to use it in my switch, it doesn't. It won't actually add to the list cause when I display the list nothing is there.
Class and implementation:
#ifndef HEADER_H
#define HEADER_H
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
template <class T>
class LinkedList{
template<typename T>
class Node
{
public:
Node(T value = 0) : data(value), nextptr(NULL){};
T retrieve() const{ return data; }
Node<T> *next() const{ return nextptr; }
private:
T data;
Node<T> *nextptr;
friend LinkedList<T>;
};
public:
LinkedList();
LinkedList(const T& x); //Copy Constructor
~LinkedList();
void DisplayList();
void ReverseList();
LinkedList<T> operator= (const LinkedList<T> & x); //Assignment Operator
bool isEmpty() const{ return Size() == 0; }
int Size() const{ return n; }
bool ElementAt(int k, T& x) const;
LinkedList<T>& RemoveAt(int k, T& x)
{
if (k < 0 || k >= Size())
{
cout << "Index not in list.";
}
Node<T> *del = NULL;
if (k == 0)
{
del = list_head;
list_head = del->nextptr;
}
else
{
Node<T> *prev = list_head;
del = list_head->nextptr;
for (int i = 1; i< k; i++)
{
prev = del;
del = del->nextptr;
}
prev->nextptr = del->nextptr;
}
n--; x = del->data; delete del;
return *this;
}
LinkedList<T>& Add(const T& x)
{
Node<T>
*node = new Node<T>(x);
if (Size() == 0)
list_head = node;
else
{
Node<T> *temp = list_head;
while (temp->nextptr)
{
temp = temp->nextptr;
}
temp->nextptr = node;
}
n++;
return *this;
}
private:
Node<T> *list_head;
int n;
};
//Constructor
template<class T>
LinkedList<T>::LinkedList()
{
list_head = NULL;
n = 0;
}
//Copy Constructor
template<class T>
LinkedList<T>::LinkedList(const T& x)
{
list_head = x.listhead;
n = x.n;
}
//Destructor
template<class T>
LinkedList<T>::~LinkedList()
{
Node<T> *temp = list_head, *del, *nextptr;
while (temp != NULL)
{
del = temp->nextptr;
delete temp;
temp = del;
}
}
template<class T>
bool LinkedList<T>::ElementAt(int k, T& x) const
{
if (k < 0 || k >= Size())
return false;
Node<T> *temp = list_head;
for (int i = 0; i< k; i++)
{
temp = temp->next;
}
x = temp->data;
return true;
}
// Assignment Operator
template<class T>
LinkedList<T> LinkedList<T>::operator=(const LinkedList<T> & x)
{
list_head = x.list_head;
n = x.n;
return *this;
}
template<class T>
void LinkedList<T>::DisplayList()
{
Node<T> *temp = list_head;
while (temp != NULL)
{
cout << temp->data << endl;
temp = temp->nextptr;
}
}
template<class T>
void LinkedList<T>::ReverseList()
{
Node<T> *t, *y = list_head, *r = NULL, *listhead;
while (y != NULL)
{
t = y->nextptr;
y->nextptr = r;
r = y;
y = t;
}
list_head = r;
}
#endif
Driver:
#include "stdafx.h"
#include <iostream>
#include "Header.h"
using namespace std;
int main()
{
int choice;
string item;
do
{
LinkedList<string> list;
int num;
cout << "1. Add new record to the file" << endl;
cout << "2. Delete a record in the file (by index)" << endl;
cout << "3. Display entire list of items" << endl;
cout << "4. Display entire list of items backwards" << endl;
cout << "5. Exit" << endl;
cin >> choice;
switch (choice)
{
case 1:
{
cout << "1. Add new record to the file" << endl;
cout << "Enter the Item Description:" << endl;
cin.ignore();
getline(cin, item);
list.Add(item);
}
break;
case 2:
{
cout << "2. Delete a record in the file" << endl;
cout << "Enter the index number of the item you want to delete" << endl;
cin >> num;
//list.RemoveAt(num);
}
break;
case 3:
{
cout << "3. Display entire list of items" << endl;
list.DisplayList();
}
break;
case 4:
{
cout << "4. Display entire list of items backwards" << endl;
list.ReverseList();
list.DisplayList();
list.ReverseList();
}
break;
case 5:
{
return 0;
}
break;
}
} while (0 < choice < 6);
return 0;
}
Any ideas?
Move your list declaration outside of your do..while loop. At the moment it is being reinitialized each time round the loop.