Traversing a non-STL linked-list in C++, possible? - c++

Let's say I'm using a non-standard linked-list class, List.h. This class is functioning, template'd and has the typical features of add/remove to front and add/remove to back, isEmpty(), etc.
This list does not have any begin() and end() functionality. Also, does a linked-list class have to include iterator functionality? Or is that something I can create on my own when I create a new List?
I'm used to working with STL, so I would usually use this code:
typedef vector<OBJECT>::iterator QuoteIt;
for(QuoteIt i = deposits.begin(); i != deposits.end(); ++i)
Anyway, lets say I create a new "List".
List<int>deposits;
or even a List of Objects
List<OBJECT>deposits;
So let's say I addToBack() 20 different integers, so that creates the appropriate # of new nodes.
Now, how can I traverse this list so I can find a sum of all these ints? Is that possible, or does my current functionality prevent that? I would have to implement some sort of iterator to my List Class?
Now I know I could keep an outside variable, every time I do an addToBack() call to keep track of my sums. However, I want the code to be compatible with Lists of Objects as well. (I want to be able to search one value in a node, and retrieve another value in the same node eventually)
I'm so used to working with stl::list and creating a for loop with iterators, I really dont' know how to get this working with other classes.
btw here is the code for List():
template<class NODETYPE>
class List{
public:
List();
~List();
void insertAtFront(const NODETYPE &);
void insertAtBack(const NODETYPE &);
bool removeFromFront( NODETYPE &);
bool removeFromBack( NODETYPE &);
bool isEmpty() const;
private:
ListNode< NODETYPE > *firstPtr; //pointer to first node
ListNode< NODETYPE > *lastPtr;
//Function to allocate a new node
ListNode< NODETYPE > *getNewNode ( const NODETYPE &);
};
//default constructor
template <class NODETYPE>
List< NODETYPE > ::List()
: firstPtr(0),
lastPtr(0)
{
cout<<"Creating Nodes! \n\n!"<<endl;
}
//deconstructor
template <class NODETYPE>
List<NODETYPE>::~List(){
if(!isEmpty() ){
cout<<"Destroying nodes!"<<endl;
ListNode<NODETYPE> *currentPtr=firstPtr;
ListNode<NODETYPE> *tempPtr;
while( currentPtr !=0){
tempPtr = currentPtr;
currentPtr=currentPtr->nextPtr;
delete tempPtr;
}
}
cout<<"All nodes destroyed! \n\n";
}
template <class NODETYPE>
bool List <NODETYPE>::removeFromFront( NODETYPE & value){
if ( isEmpty() )
return false;
else{
ListNode<NODETYPE> *tempPtr = firstPtr;
if (firstPtr== lastPtr)
firstPtr=lastPtr = 0;
else
firstPtr=firstPtr->nextPtr;
value = tempPtr->data;
delete tempPtr;
return true;
}
}
template <class NODETYPE>
bool List<NODETYPE>::removeFromBack(NODETYPE &value)
{
if (isEmpty())
return false;
else{
ListNode< NODETYPE> *tempPtr = lastPtr;
if( firstPtr == lastPtr)
firstPtr = lastPtr = 0;
else{
ListNode<NODETYPE> *currentPtr=firstPtr;
//Finds second to last element
while(currentPtr->nextPtr !=lastPtr)
currentPtr=currentPtr->nextPtr;
lastPtr = currentPtr;
currentPtr->nextPtr=0;
}
value = tempPtr->data;
delete tempPtr;
return true;
}
}
//Checks to see if list is empty
template< class NODETYPE>
bool List< NODETYPE >::isEmpty() const{
return firstPtr == 0;
}
//returns a pointer to newly created Node
template<class NODETYPE>
ListNode<NODETYPE> *List<NODETYPE>::getNewNode(const NODETYPE &value){
return new ListNode<NODETYPE>(value);
}

In response to:
Now, how can I traverse this list so I can find a sum of all these ints? Is that possible, or does my current functionality prevent that? I would have to implement some sort of iterator to my List Class?
You need to implement a way to iterate over your list that does not (as a side-effect) destroy your list.

In response to:
Now, how can I traverse this list so I
can find a sum of all these ints? Is
that possible, or does my current
functionality prevent that? I would
have to implement some sort of
iterator to my List Class?
No matter how you design a linked list, you must have some sort of pointer to the beginning of the list, and you have to have a way of knowing when you are at the end (e.g. when "next" is null, or by having a pointer to the end). By exposing those data one way or another, you can always set up a list traversal:
Start at the beginning. (In your case, get a hold of firstPtr.)
If you are not at the end, move to the next element. (In your case, get ->nextPtr.)
Using that pattern to accumulate a value as you visit each element you should be able to handle your task with ease.
If your list does not give you public access to its beginning, then it is certainly not a general-purpose list!

You can approach this many ways. You can either choose to create your own iterator or give public access to the list's head.
Option 1 is compatible with stl lists so you might want to go that route. An iterator is essentially a ptr that overrides the inc and dec operators to go to the next or previous position in the list.
If you studied basic data structures at all, you would know that traversing a list is trivial.
Node<type> t = head;
while (t != NULL)
{
// process node here
t = t->next;
}
The code can differ depending on if you use dummy nodes at all.

Since there is no functionality to just get the node without removing it from the list, you can't simply make an "add-on" iterator without changing the List class. The least you would need to do is to either
friend the external ListIterator class
friend free begin and end functions
add begin and end functions to the List class
Without any of those three, you can't achieve what you want.

Your list seems to have 2 ways of iterating it (forwards and backwards)
List<int>deposits;
.. add stuff:
int o;
int sum = 0;
while(deposits.removeFromFront(o)) {
sum+=o;
}
The bad thing though, is that iterating it, you also destroy the list,
you could provide public accessors to List::firstPtr and ListNode::nextPtr in which case you could do:
List<int>deposits;
.. add stuff:
int sum = 0;
for(ListNode<int> *ptr = deposits.firstPtr; ptr ; ptr = ptr->nextPtr)
sum+=ptr->data;
However, use an existing STL container if you can.

Related

Reversing a Doubly-Linked List with Values

I am currently unable to get a reverse function of a doubly linked list to properly work for an assignment, I've read up the other threads and searched on google but usually the difference is my problem passes in a constant and that it returns a "dlist". The professor has provided a "code tester" and it says that my code when doing "reverse(reverse(dlist c))" it's not equal to itself being "c". [Reversing it twice does not equal itself].
The dlist class is:
class dlist {
public:
dlist() { }
int sizeOfDlist =0; // To keep track of size
struct node {
int value;
node* next;
node* prev;
};
node* head() const { return _head; } // _head = beginning of list
node* tail() const { return _tail; } // _tails = end of list
node* _head = nullptr;
node* _tail = nullptr;
And here's the reverse function:
dlist reverse(const dlist& l){
if(l._head == nullptr||l._tail ==nullptr){ // Checks if l list is empty
dlist newRList;
return newRList;//return a blank list;
}
if(l.head()!=nullptr){
dlist::node* temp;
dlist::node* ptr1 = l._head;
dlist::node* previous = nullptr;
while(ptr1 != nullptr){
temp = ptr1->next;
ptr1->next = previous;
previous = ptr1;
ptr1 = temp;
}
dlist newRList;
newRList._head = previous;
return newRList;
}
else //if something passes by, return original list
return l;
}
Each dlist node has a pointer pointing towards the previous node and a pointer pointing towards the next node. The dlist node also contains an int value.
What I tried to implement was creating a list that starts at original list's "tail" or end. The list would then go backwards and swap the "next" and "prev" pointers as it goes along. What am I doing wrong?
Solved: By using a push_front function which adds a value to the front of a list and pushing everything else behind it, I was able to grab the values from the given constant dlist, and push_front all of the values into "newRList" which reverses the order.
Thanks to user4581301 and Basya Perlman for helping me out, here's the new reverse function:
dlist reverse(const dlist& l){
if(l._head == nullptr||l._tail ==nullptr){ // Checks if l list is empty
dlist newRList;
return newRList;//return a blank list;
}
if(l.head()!=nullptr){
dlist newRList;
for(int n=0; n<l.size(); n++){ // Size function checks the size of the doubly linked list
newRList.push_front(l.valueGetter(n)); // Value Getter is a function that grabs the value at a specific [iteration], push_front pushes said value into the front of the list.
}
return newRList;
}
else //if something passes by, return original list
return l;
}
Your reverse function looks like it is set up to return a new dlist. It returns an object, not a pointer or a reference.
Also, your parameter is a const dlist, yet you are trying to reverse it in-place, and then point a new pointer to the head of the list and return that. Then the tester is comparing the returned list to the original list; but the original list, which was meant to be const, but which was modified? I am a bit confused, so perhaps the computer running your program is too :-)
From the function definition, it looks as though the idea is to create a new list by copying the elements into the new list in reverse order, and leave the original list unchanged. In your comment, you have a push_back and a push_front function; you can loop forward through your existing list and push_front a copy of each element into the new list, to reverse it (whether you need to explicitly make a copy or not depends on the definition of the push_front function, which I do not have).

C++ Segmentation fault when trying to print linked list node string

I'm creating a linked list-based stack and i'm using class templates. I want to define the head node of the stack via user input and then print it, however I am receiving a segmentation fault and am quite lost at working out why.
TowerHanoi.cpp uses the below function which creates a string and then tries to store it in a node, which is then stored in the stack using push(), which adds it to the 'head' node of the Linked List. Upon attempting to print the head node of the Linked List i receive a segmentation fault:
rod[] refers to an array of LStack objects, which contains the Linked List and member functions that query and modify the Linked List.
void TowerHanoi::set_Discs(size_t disc) {
node<string>* temp= new node<string>();
while (disc != 0) {
string tmp_str;
for (size_t i=0; i<disc; i++) {
tmp_str.append("x");
}
disc--;
temp->set_data(tmp_str);
rod[0].push(temp);
node<string>* tmp_node1 = rod[0].top();
cout << "test: " + tmp_node1->data() << endl;
}
}
LStack.template contains the definition for 'push()':
namespace oreilly_A2 {
template <typename Item>
LStack<Item>::LStack() {
list = new LinkedList<Item>();
}
//push
template <typename Item>
void LStack<Item>::push(Item* head_in) {
list->addToHead(head_in);
used++;
}
//top
template <typename Item>
Item* LStack<Item>::top() {
return list->list_getHead();
}
LinkedList.template initializes the head node in the constructor and contains the addToHead(Item* entry) function:
namespace oreilly_A2 {
template <typename Item>
LinkedList<Item>::LinkedList() { //constructor initializing nodes
head= new node<std::string>();
tail= new node<std::string>();
current= new node<std::string>();
}
template <typename Item>
void LinkedList<Item>::addToHead(Item* entry) {
Item* temp = head;
head = entry;
head->set_link(temp);
}
Node.template initializes next and previous node to NULL and contains the set_data() function:
namespace oreilly_A2 {
template <typename Item>
node<Item>::node() {
next= NULL;
previous= NULL;
}
template <typename Item>
void node<Item>::set_data(Item new_data){
word = new_data;
}
template <typename Item>
Item node<Item>::data() const { //return the word
return word;
}
In your LinkedList<Item>::addToHead function, which is called by LStack<Item>::push, it uses the passed in node and puts it into the linked list by setting its next pointer to the head of the list. This means that the passed in node is now part of the list.
When your set_discs function loops around again, it changes the value of temp and again pushes it onto the stack. But the node pointed to by temp is already on the stack! This means that it will end up pointing to itself, which is definitely going to cause some issues.
One way you might be tempted to fix this is to allocate a new object for temp each time round the loop, but that means that it is up to the user of a LinkedList to know that he has to allocate new items each time.
A better way is to consider that someone using a LinkedList or LStack shouldn't need to know how it is stored, so they don't need to interact with a node at all. Consider changing your methods of LinkedList and LStack to just take an Item reference. They can then construct their own node to store the data. Something like:
template <typename Item>
void LinkedList<Item>::addToHead(Item &entry) {
node<Item>* temp = head;
head = new node<Item>;
head->set_date(Item);
head->set_link(temp);
}
Similarly, change your LStack to just take an Item & and pass it through to the LinkedList
Then make your rod as an array (or whatever collection it is) of LStack<string>, rather than what you have now, which I suspect is an array of LStack<node<string>>.
You will then not need to do any allocation in your main loop, just pass a normal std::string (tmp_string will do as it is) to the push function.
One more thing, unless you are doing this to learn about making linked lists (or for a class), consider just using the stl classes, such as std::stack. In general it is much better to use the library classes than roll your own, unless there is a good reason (like learning).

STL set find performance

How to overwrite operator() inside of class MyNode so that set::find can use, and a sets that stores MyNode*. Then I try to find pointer in set, whose data field is the same as in given object. The below code does not work as I expected. I set breakpoints in of operator method, but none stopped.
I understand I can define find struct compare{} outside of class MyNode, and then define sets like:
set sets
This is oK for me. Here I am wondering whether it is possible I can define compare inside of class MyNode.
My code is like:
class MyNode {
std::string data;
public:
MyNode();
MyNode(std::string str);
MyNode(const MyNode& orig);
virtual ~MyNode();
std::string getData();
bool operator<(const MyNode& node){
return data<node.data;
}
bool operator<( const MyNode* node){
return data<node->data;
}
};
void testset(){
MyNode* node1 = new MyNode("5S");
MyNode* node2 = new MyNode("AH");
MyNode* node3 = new MyNode("AH");
std::cout<<" "<<node2<<std::endl;
std::set<MyNode*> sets;
sets.insert(node1);
sets.insert(node2);
std::set<MyNode*>::iterator iter =sets.find(node3); // I expected node2 can be found, but it does not..
if(iter != sets.end()){
MyNode* no = *iter;
std::cout<<"find it "<<no<<std::endl;
}
}
Another question is if I only define set like:
set<MyNode> sets.
std::find(sets.begin(), sets.end(), findmethod("aa"))
Is this complexity O(N) or O(log N)?
As for the first question: std::set doesn't care about operator()(); it cares about operator<().
As for your second question: the std::find algorithm, unlike the std::set<T>::find method, is O(n).

C++ -- Using a class' elements from a nested class?

Okay so I have a class, LinkedList, with a nested class, LinkedListIterator. Within LinkedListIterator's methods I reference the private fields of LinkedList. Which I thought was legal. But I get the error:
from this location
every time I reference them.
And I get corresponding error messages on the fields in the enclosing class:
invalid use of non-static data member 'LinkedList<int>::tail'
Any idea why? The relevant code is below:
template<class T>
class LinkedList {
private:
//Data Fields-----------------//
/*
* The head of the list, sentinel node, empty.
*/
Node<T>* head;
/*
* The tail end of the list, sentinel node, empty.
*/
Node<T>* tail;
/*
* Number of elements in the LinkedList.
*/
int size;
class LinkedListIterator: public Iterator<T> {
bool add(T element) {
//If the iterator is not pointing at the tail node.
if(current != tail) {
Node<T>* newNode = new Node<T>(element);
current->join(newNode->join(current->split()));
//Move current to the newly inserted node so that
//on the next call to next() the node after the
//newly inserted one becomes the current target of
//the iterator.
current = current->next;
size++;
return true;
}
return false;
}
You can't just use non-static members like that. I think the following example will clear things out:
LinkedList<int>::LinkedListIterator it;
it.add(1);
What would current and tail be inside the method? There's no instance of LinkedList to speak of, so those members don't even exist yet.
I'm not saying make the members static, that would be wrong, but re-think your approach.
Look into how std iterators are.

Use Binary-Tree in Template as Priority queue

So i want to make a code, that creates a binary tree, that holds data, for example ints like 1,6,2,10,8 and on pop i get the biggest number, and after that it gets deleted from the tree, and on push i can insert a new element. And this should be in a template so i can easy change the data type i want to hold in the tree. Now i got the tree so far, without template it is working fine thought, i can add items, and i can print them, but when i try to put it in a template, i get the following error: use of class template requires template argument list . What could be the problem? Maybe i am doing it totally wrong. Any suggestions are welcome.
This was my first question it got fixed by avakar ty. (i will post the code at the end of my question)
I just read trough the project request , and its like, i have to make this thing i above in the first part of question described, but its like the binary tree should represent a priority queue. And that is why in the request is written that i have to use push to put a new element in the tree by priority order and with pop i will get the element with the highest priority and then that element will be deleted. So how could i use my Tree as a Priority queue, or is he already one(i think not but who knew)? I hope i could explain it.
And here is the code as promised:
#include <iostream>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot)
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);;
}
void PrintTree(Node* theRoot)
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" ";;
PrintTree(theRoot->rChildptr);
}
}
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(1);
myBT->AddItem(7);
myBT->AddItem(1);
myBT->AddItem(10);
myBT->AddItem(4);
myBT->PrintTree();
}
If you want to use the binary tree as a priority queue, you extract the maximum element by stepping only through right child pointers. Any left child would be smaller than the current element. So you record the value of that node and then remove it -- you would still have to write a node deletion routine.
The problem with a simple BST is that it can become unbalanced and send your complexities to O(n). You can use a self-balancing BST, but it's unusual for priority queues. Instead of BSTs they are usually heaps, as Kerrek said.
The simplest heap implementation that I know personally is the binary heap. The binary heap is theoretically a type of binary tree although not stored as such. So, depending on whether you had to implement a BST or just a binary tree, it might fit your requirements.
On this line:
BinaryTree<int> *myBT = new BinaryTree();
You need to also specify the type of template you want to instantiate on the right side of the assignment:
BinaryTree<int> *myBT = new BinaryTree<int>();
Because BinaryTree is not a BinaryTree<int>; one is the name of a template (BinaryTree) and one is the name of a specific type of that template (BinaryTree<int>). You can't create instances of plain templates, you have to give it the type of template you want to use all the time.