C++ linked list values changing retroactively - c++

EDIT: Solution Code included at the end.
I am trying to implement a linked list class that utilizes a node class as defined in the assignment. The below code block prints output as expected:
#include <iostream>
using namespace std;
// Node class as provided
class node {
void *info;
node *next;
public:
node (void *v) {info = v; next = 0; }
void put_next (node *n) {next = n;}
node *get_next ( ) {return next;}
void *get_info ( ) {return info;}
};
// Linked list class
class list {
//Start of the linked list
node *start;
public:
list (int v) {
start = new node (&v);
}
void insert (int value, int place=-1) {
node *temp = new node (&value);
if (place == 0) {
temp->put_next(start);
start = temp;
} else {
node *before = start;
for (int i = 1; before->get_next() != 0; i++) {
if (i == place) {
break;
}
before = before->get_next();
}
temp->put_next(before->get_next());
before->put_next(temp);
}
}
void remove(int place) {
if (place == 0) {
start = start->get_next();
} else {
node *curr = start;
for (int i = 1; curr != 0; i ++) {
if (i == place) {
curr->put_next(curr->get_next()->get_next());
break;
}
curr = curr->get_next();
}
}
}
void display() {
for (node *current = start; current != 0; current = current->get_next()) {
cout << *(static_cast<int*>(current->get_info())) << endl;
}
}
};
int main() {
list *tst = new list(10);
tst->display();
cout << "Prepending 9" << endl;
tst->insert(9,0);
tst->display();
cout << "Inserting 8" << endl;
tst->insert(8,1);
tst->display();
cout << "Prepending 7" << endl;
tst->insert(7,0);
tst->display();
tst->remove(0);
cout << "Removed the first element:" << endl;
tst->display();
cout << endl;
// cout << "Prepending 6" << endl;
// tst->insert(6,0);
// tst->display();
}
Creates this output:
10
Prepending 9
9
10
Inserting 8
9
8
10
Prepending 7
7
9
8
10
Removed the first element:
9
8
10
However, when I add this last statement to the end of the program flow in main:
tst->insert(6,0);
My output changes to this:
10
Prepending 9
9
10
Inserting 8
8
8
10
Prepending 7
7
7
7
10
Removed the first element:
134515798
134515798
10
What am I missing? How can adding a value later in execution change the output that happens before I even get to that point in the program flow?
I am using ideone.com as my IDE/to run the program, I've never had an issue before, but is that the issue?
Solution
#include <iostream>
using namespace std;
// Provided node class
class node {
void *info;
node *next;
public:
node (void *v) {info = v; next = 0; }
void put_next (node *n) {next = n;}
node *get_next ( ) {return next;}
void *get_info ( ) {return info;}
};
// List class template
template <class T>
class list {
node *start;
public:
list (T v) {
start = new node (&v);
}
// Insert method
void insert (T *value, int place=-1) {
node *temp = new node (value);
// If we're putting it at the beginning, then change the reference to start
if (place == 0) {
temp->put_next(start);
start = temp;
}
// We're inserting it somewhere other than the beginning, handle appropriately
else {
node *before = start;
// Loop to find preceeding node
for (int i = 1; before->get_next() != 0; i++) {
if (i == place) {
break;
}
before = before->get_next();
}
// Insert after preceeding node, and point at subsequent node
temp->put_next(before->get_next());
before->put_next(temp);
}
}
// Remove function
void remove(int place) {
// If we're removing hte beginning, then change start pointer
if (place == 0) {
start = start->get_next();
}
// Find node to remove
else {
node *curr = start;
for (int i = 1; curr != 0; i ++) {
if (i == place) {
// Cut target node out of list
curr->put_next(curr->get_next()->get_next());
break;
}
curr = curr->get_next();
}
}
}
// Print nodes
void display() {
for (node *current = start; current != 0; current = current->get_next()) {
cout << *(static_cast<T*>(current->get_info())) << endl;
}
cout << endl;
}
};
int main() {
int nine = 9;
int eight = 8;
int seven = 7;
int six = 6;
int five = 5;
cout << "Create list holding '10'" << endl;
list<int> *tst = new list<int>(10);
cout << "Prepending 9" << endl;
tst->insert(&nine,0);
cout << "Inserting 8 at 2nd place" << endl;
tst->insert(&eight,1);
cout << "Appending 7" << endl;
tst->insert(&seven);
cout << "Prepending 6" << endl;
tst->insert(&six,0);
cout << "Inserting 5 at 3rd place" << endl;
tst->insert(&five,2);
cout << "Show completed list:" << endl;
tst->display();
cout << "Removing the first element:" << endl;
tst->remove(0);
tst->display();
cout << "Removing the last element:" << endl;
tst->remove(4);
tst->display();
cout << "Removing the second element:" << endl;
tst->remove(1);
tst->display();
}

You have undefined behavior in your code, because you save pointers to local variables, variables that goes out of scope once the function returns.
The variable I'm talking about is the argument value inside the insert function, once the insert function returns that pointer is no longer valid.
The quick solution? Don't store pointers, store a list of integers. Or maybe make the list (and node) a templated class and store by value.
If you truly want a list that can contain anything, the consider using e.g. Boost any.

Related

Segmentation fault in UNIX but not Windows

I'm trying to get my DFS code working in UNIX, but whenever I run it it gives me a segmentation fault, yet it works fine in Windows. The code is supposed to take in a string and sort it to reach some predefined goal state by moving around a single letter at a time. I don't have much experience in UNIX so I would really appreciate some insight into this issue. Thank you!
struct node
{
node* parent;
string key;
int cost;
int heuristicCost;
node()
{
parent = nullptr;
key = "key";
cost = 0;
heuristicCost = 0;
}
};
void BFS(string sortString)
{
// Create Queue
list<node*> queue;
list<string> explored;
// Add the initial case to the Queue
node *n = new node;
n->key = sortString;
queue.push_back(n);
int steps = 1;
while (!queue.empty())
{
// Print out the current node to be checked and the operation that was performed on it
for (int i = 0; i < (int)queue.front()->key.length(); i++)
{
if (queue.front()->key[i] == 'X')
{
if (steps == 1)
{
cout << queue.front()->key << endl;
steps++;
}
else
{
cout << "move " << i << " " << queue.front()->key << endl;
steps++;
}
}
}
// Check if the goal state is reached
if (GoalTest(queue.front()->key))
{
cout << "Final Result for BFS:" << endl;
node* currentNode = queue.front();
list<node*> path;
while (currentNode->parent != nullptr) {
path.push_front(currentNode);
currentNode = currentNode->parent;
}
int i = 1;
while((int)path.size() >= 1)
{
cout << "Step " << i << ": " << path.front()->key << endl;
i++;
path.pop_front();
}
return;
}
else
{
// If goal state is not reached, add new nodes to the frontier
explored.push_back(queue.front()->key);
for (int i = 0; i < (int)queue.front()->key.length(); i++)
{
// Do a move action on the next node to be enqueued, if node is already in explored list, skip it
string key = Move(i, queue.front()->key);
bool found = (find(explored.begin(), explored.end(), key) != explored.end());
if (found)
{
continue;
}
else
{
node *newNode = new node;
newNode->key = key;
newNode->parent = queue.front();
queue.push_back(newNode);
}
}
// Remove the first node of the queue
queue.pop_front();
bool found = (find(explored.begin(), explored.end(), queue.front()->key) != explored.end());
while (found)
{
queue.pop_front();
found = (find(explored.begin(), explored.end(), queue.front()->key) != explored.end());
}
}
}
// If loop exits normally, search failed
cout << "Failure!" << endl;
return;
}

AVL Tree implementation c++

So I've posted about this recently, but I'm still at a loss for what is going wrong. Specifically, I can't seem to figure out what's causing my AVL Tree to take so long to sort. I read in a file of 500,000 random, unsorted numbers to sort by using a vector in a for loop to feed the tree the numbers one at a time. Now, I've also tested using a normal BST, as someone mentioned that having to create so many nodes one at a time might be why it's taking so long, but that completed in only 5 seconds, with only 12,164 nodes skipped due to being duplicates. My AVL Tree is taking upwards of 3 hours just to sort half the list, so something must be going wrong. Can anyone figure out what it is? As far as I know, the rebalancing and insertion logic is correct, because whenever I ran a bunch of test cases on it they all came out fine. I can't seem to track down where the problem is. Here's my full code for anyone that wants to check it out. Main is kind of a mess right now because of all the stuff I've included for testing purposes (like the tracking loop), but most of that will be gone in the final version.
EDIT:
This question has been answered.
#include <iostream>
#include<iomanip>
#include <time.h>
#include <vector>
#include <fstream>
using namespace std;
vector<int> numbers;
struct node
{
public:
int data, height;
node *leftChild, *rightChild;
};
node* root = NULL;
int findMin(node *p) // finds the smallest node in the tree
{
while (p->leftChild != NULL)
p = p->leftChild;
return p->data;
}
int findMax(node *p) // finds the largest node in the tree
{
while(p->rightChild != NULL)
p = p->rightChild;
return p->data;
}
int max(int a, int b) // gets the max of two integers
{
if(a > b)
return a;
else
return b;
}
int height(node *p) // gets the height of the tree
{
if(p == NULL)
return -1;
else
{
p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
}
return p->height;
}
node* newNode(int element) // helper function to return a new node with empty subtrees
{
node* newPtr = new node;
newPtr->data = element;
newPtr->leftChild = NULL;
newPtr->rightChild = NULL;
newPtr->height = 1;
return newPtr;
}
node* rightRotate(node* p) // function to right rotate a tree rooted at p
{
node* child = p->leftChild; // rotate the tree
p->leftChild = child->rightChild;
child->rightChild = p;
// update the height for the nodes
p->height = height(p);
child->height = height(child);
// return new root
return child;
}
node* leftRotate(node* p) // function to left rotate a tree rooted at p
{
node* child = p->rightChild; // perform the rotation
p->rightChild = child->leftChild;
child->leftChild = p;
// update the heights for the nodes
p->height = height(p);
child->height = height(child);
// return new root
return child;
}
int getBalance(node *p)
{
if(p == NULL)
return 0;
else
return height(p->leftChild) - height(p->rightChild);
}
// recursive version of BST insert to insert the element in a sub tree rooted with root
// which returns new root of subtree
node* insert(node*& p, int element)
{
// perform the normal BST insertion
if(p == NULL) // if the tree is empty
return(newNode(element));
if(element < p->data)
{
p->leftChild = insert(p->leftChild, element);
}
else
{
p->rightChild = insert(p->rightChild, element);
}
// update the height for this node
p->height = height(p);
// get the balance factor to see if the tree is unbalanced
int balance = getBalance(p);
// the tree is unbalanced, there are 4 different types of rotation to make
// Single Right Rotation (Left Left Case)
if(balance > 1 && element < p->leftChild->data)
{
return rightRotate(p);
}
// Single Left Rotation (Right Right Case)
if(balance < -1 && element > p->rightChild->data)
{
return leftRotate(p);
}
// Left Right Rotation (double left rotation)
if(balance > 1 && element > p->leftChild->data)
{
p->leftChild = leftRotate(p->leftChild);
return rightRotate(p);
}
// Right Left Rotation
if(balance < -1 && element < p->rightChild->data)
{
p->rightChild = rightRotate(p->rightChild);
return leftRotate(p);
}
// cout << "Height: " << n->height << endl;
// return the unmodified root pointer in the case that the tree does not become unbalanced
return p;
}
void inorder(node *p)
{
if(p != NULL)
{
inorder(p->leftChild);
cout << p->data << ", ";
inorder(p->rightChild);
}
}
void preorder(node *p)
{
if(p != NULL)
{
cout << p->data << ", ";
preorder(p->leftChild);
preorder(p->rightChild);
}
}
void print(node* root)
{
/*cout << "Min Value: " << findMin(root) << endl;
cout << "Max Value: " << findMax(root) << endl;
cout << "Pre Order: ";
preorder(root); */
cout << endl << "Inorder: ";
inorder(root);
cout << endl << endl << endl << endl;
}
void read()
{
int num;
ifstream file_save("data.txt");
if(file_save.is_open())
{
while(!file_save.eof())
{
file_save >> num;
numbers.push_back(num);
}
file_save.close();
}
else
{
cout << "Error in opening file!!" << endl;
}
}
int main()
{
double duration;
time_t begin = time(0);
read();
int x = 0;
int track = 0;
for (std::vector<int>::const_iterator i = numbers.begin(); i != numbers.begin() + 100000; ++i)
{
root = insert(root, numbers[x]);
x++;
track++;
if( (track % 10000) == 0)
{
cout << track << " iterations" << endl;
time_t now = time(0);
cout << now - begin << " seconds" << endl;
}
}
time_t end = time(0);
duration = end - begin;
// print(root);
cout << "The algorithm took " << duration << " seconds to complete." << endl;
return 0;
}
There are many problems with this code.
while(eof) is wrong.
The main loop expects exactly 100000 elements.
All key comparisons are exact (<, >). There are no rotations performed when a duplicate element is inserted. Thus a tree of identical elements will not be balanced at all.
The height of an empty tree is hardcoded to -1, but the height of a single-node three is initially set to 1, thus violating the invariant height(node) = 1+max(height(node->leftChild))+height(node->rightChild)).
height traverses the entire tree every time it is called, thus making insertion O(n).
So, it seems to me that the reason that it was taking so long was because of too many recursive calls all over the place. This modified code has less recursive calls and thus bogs down the CPU with less stacks to have to process. At least, that's what I'm getting out of this.
void newHeight(node* p)
{
double leftHeight = height(p->leftChild);
double rightHeight = height(p->rightChild);
if(leftHeight > rightHeight)
p->height = leftHeight;
else
p->height = rightHeight;
}
node* rotateright(node* p) // the right rotation round p
{
node* q = p->leftChild;
p->leftChild = q->rightChild;
q->rightChild = p;
newHeight(p);
newHeight(q);
return q;
}
node* rotateleft(node* q) // the left rotation round q
{
node* p = q->rightChild;
q->rightChild = p->leftChild;
p->leftChild = q;
newHeight(q);
newHeight(p);
return p;
}
node* rebalance(node* p) // p node balance
{
newHeight(p);
if( getBalance(p)==2 )
{
if( getBalance(p->rightChild) < 0 )
p->rightChild = rotateright(p->rightChild);
return rotateleft(p);
}
if (getBalance(p)==-2 )
{
if( getBalance(p->leftChild) > 0 )
p->leftChild = rotateleft(p->leftChild);
return rotateright(p);
}
return p; // no balance needed
}
node* insert(node* p, int element) // k key insertion in the tree with p root
{
if(!p) return newNode(element);
if(element < p->data)
p->leftChild = insert(p->leftChild, element);
else
p->rightChild = insert(p->rightChild, element);
return rebalance(p);
}

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

Reversing a singly-linked list in 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?

C++ Building a Sorted Link List from a Loop

I've been banging my head against the wall for about 3 hours now trying to come up with the fix for this but I can't figure it out. My test program is written as such...
int main()
{
SimpList<int> intList; // (empty) list of integers
cout << "Let's build a sorted list of integers." << endl;
cout << endl << "Uninitialized List: ";
intList.print();
cout << endl << "Length: " << intList.size() << endl;
int intData[] = { 5, 3, -2, 7, 9, -8, 1, -4 };
for (int i=0; i<8; i++)
intList.insert( intData[i] );
cout << endl << "After inserting 8 integers: ";
intList.print();
cout << endl << "Length: " << intList.size() << endl;
system("PAUSE");
return 0;
}
So the Link List is getting initialized from an array and a for loop. My class code for the node and list is here...
template < typename T > // Forward declaration of the SimpList class
class SimpList;
template < typename T >
class Node // Node class for the SimpList class
{
private:
// Constructors
Node () { next = 0; } // default constructor
// Complete the definition inline
Node ( const T &initItem, Node<T> *ptr ) { }
// Data members
T item; // Node data item
Node *next; // Pointer to the next node
friend class SimpList<T>;
};
template < typename T >
class SimpList
{
public:
// Constructor (add your code inline)
SimpList ()
{
head = &PHONY;
length = 0;
}
// List manipulation operations
void insert ( const T &newitem ); // insert a data item
bool remove ( T &item ); // remove data item
bool find ( T &item ) const; // find data item
void clear (); // empty the list
bool isEmpty () const {
if (length == 0)
return true;
else
return false;
}
// length accessor method
int size () const {
return length;
}
// print the list items
void print () const;
private: // data members
Node<T> PHONY; // empty node that anchors the list
Node<T> *head; // pointer to the beginning of the list
int length; // length of list
};
And then the insert and print functions are as follows...
template < typename T >
void SimpList<T>::print() const
{
if (length == 0)
{
cout << "List is empty." << endl;
return;
}
Node<T> *ptr = head->next;
while (ptr != NULL)
{
cout << ptr->item << " ";
ptr = ptr->next;
}
cout << endl;
}
template < typename T >
void SimpList<T>::insert(const T& newitem) {
Node<T> *currN = head->next;
Node<T> *prevN = 0;
Node<T> *tmp = new Node<T>();
tmp->item = newitem;
if(head->next == NULL ) {
head->next = tmp;
}
else {
prevN = head;
while(currN != NULL && currN->item < newitem) {
prevN = currN;
currN = currN->next;
}
prevN->next = tmp;
}
length++;
print();
}
I inserted the last "print()" into the insert function as a way of debugging what was happening and the output is quite perplexing as it gives me
5
3
-2
-2 7
-2 7 9
-8
-8 1
-8 -4
But I want the output to be sorted smallest to largest (-8 -4 -2 1 3 5 7 9)
edit: solved...forget to update tmp->next to currN. DERP.
Couple of things you need to fix:
PHONY->next is not null , so your initialization will fail :
if(head->next==NULL) {
head->next=tmp;
return;
}
Node constructor should initialize next to 0 instead of this , hence you will never hit NULL condition for end of your list.
in insert in else statement you should start search from head->next, currently you start search from currn = head which is PHONY which is not correct.
You also need to set tmp->next appropriately ,consider this case when you are inserting in middle of the list.