Hi I am trying to make a doubly linked list to store individual numbers as nodes of a doubly linked list and then add them together and print them out for a homework assignment. I am having a lot of trouble getting this to work and have traced my problem to my add node functions as they don't update the pointers correctly. For example on the AddToFront() function I can't understand how I can get the prev pointer to work and point to the node behind it.
I can't use the STL and have to implement the LL myself in case anyone is wondering. Thanks!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
/////// PART A
template <class T>
class List {
private:
struct Node {
T data;
Node *next;
Node *prev;
};
Node *front, *current, *rear;
public:
List();
~List();
void AddtoFront (T newthing);
void AddtoRear (T newthing);
bool FirstItem (T & item);
bool LastItem (T & item);
bool NextItem (T & item);
bool PrevItem (T & item);
};
template <class T>
List<T>::List() {
front = NULL; current = NULL; rear = NULL;
}
template <class T>
List<T>::~List() {
}
template <class T>
void List<T>::AddtoFront (T newthing) {
if (front == NULL) {
Node *temp;
temp = new Node;
temp->data = newthing;
temp->next = front;
temp->prev = NULL;
front = temp;
} else {
Node *temp;
temp = new Node;
front->prev = temp;
temp->data = newthing;
temp->next = front;
temp->prev = NULL;
front = temp;
}
}
template <class T>
void List<T>::AddtoRear (T newthing) {
if (rear == NULL) {
Node *temp;
temp = new Node;
temp->data = newthing;
temp->prev = rear;
temp->next = NULL;
rear = temp;
} else {
Node *temp;
temp = new Node;
rear->next = temp;
temp->data = newthing;
temp->prev = rear;
temp->next = NULL;
rear = temp;
}
}
template <class T>
bool List<T>::FirstItem (T & item) {
if (front == NULL) { return false; }
current = front;
item = front->data;
return true;
}
template <class T>
bool List<T>::LastItem (T & item) {
if (rear == NULL) { return false; }
current = rear;
item = rear->data;
return true;
}
template <class T>
bool List<T>::NextItem (T & item) {
if (current != NULL) current = current->next;
if (current == NULL) { return false; }
item = current->data;
return true;
}
template <class T>
bool List<T>::PrevItem (T & item) {
if (current == NULL) { return false; }
if (current->prev != NULL) current = current->prev;
item = current->data;
return true;
}
/////// PART B
class BigNumber {
private:
//complete here...
//include here a List of integers, or shorts etc
List<int>L;
public:
//complete here...
//what methods do you need?
//e.g., ReadFromString, PrintBigNumber, AddBigNumbers
BigNumber();
~BigNumber();
void ReadFromString(char * decstring);
void PrintBigNumber();
void AddBigNumbers(BigNumber B1, BigNumber B2);
};
BigNumber::BigNumber(){
// anything here?
}
BigNumber::~BigNumber(){
//you can keep that empty
}
void BigNumber::ReadFromString (char * decstring ) {
//read a string, adding a new node per digit of the decimal string
// To translate 'digits' to integers: myinteger=decstring[index]-48
//You need to use the AddtoFront()
int temp;
for (unsigned i=0; i < strlen(decstring); ++i) {
//cin >> decstring[i];
temp = decstring[i]-48;
//L.AddtoFront(temp);
L.AddtoRear(temp);
//cout <<"Number added!" <<endl;
}
}
void BigNumber::PrintBigNumber () {
//complete here, print the list (i.e., use FirstItem() and NextItem() )
int val;
if (L.FirstItem(val)) {
cout << val;
} else {
cout << "print failed";
}
//if (L.FirstItem(val)) { cout << "true-first";} else { cout <<"false-first";};
//if (L.LastItem(val)) { cout << "true";} else { cout <<"false";};
//L.FirstItem(val);
//cout << val;
/*while (L.PrevItem(val)){
cout << val;
//cout <<"Print error!Value not here.";
}*/
}
void BigNumber::AddBigNumbers(BigNumber B1,BigNumber B2){
//complete here.
//use FirstItem(), NextItem() and AddNode()
//to add two big numbers, what do you have to do? Be careful about the carry
//Remember to add the last carry, the resulting number can have one more digit than B1 or B2
}
/////// PART C
BigNumber B1, B2, RES;
int main (int argc, char ** argv) {
//use command line arguments
if(argc!=3){printf("usage: executable number1 number2\n");exit(0);}
B1.ReadFromString(argv[1]);
B2.ReadFromString(argv[2]);
//print
cout << endl<< "Add the following numbers " << endl;
B1.PrintBigNumber();
cout << " + ";
B2.PrintBigNumber();
cout << " = " << endl;
//compute the addition
RES.AddBigNumbers(B1,B2);
//print the result
RES.PrintBigNumber();
cout << endl;
return 0;
}
EDIT: I added in a line each in AddToFront() and AddToRear(). Is this on the right track?
AddtoFront needs to also update the prev pointer for front. That is, you're currently doing
temp -> front <-> rest_of_list
where it needs to be
temp <-> front <-> rest_of_list.
Also, you might notice that the two branches of your if statement in AddtoFront are identical... :)
Related
I've gone through a bunch of threads trying to understand what is going on exactly with linked lists and bubblesort, and I think I get the bulk of it.
Right now my program is simply crashing when I get to the sort function and I am not sure why. Hopefully another set of eyes will see what I do not.
Any help is greatly appreciated.
DoublyList.h:
#include "listNode.h"
#ifndef DOUBLYLIST_H
#define DOUBLYLIST_H
template <typename T>
class DoublyList
{
public:
DoublyList();
~DoublyList();
void addFront(T d);
void addBack(T d);
T removeFront();
T removeBack();
T peak();
bool isEmpty();
int getSize();
void printList();
void sortList();
private:
ListNode<T> *front;
ListNode<T> *back;
int numOfElements;
};
template <typename T>
DoublyList<T>::DoublyList(){
front = NULL;
back = NULL;
numOfElements = 0;
}
template <typename T>
DoublyList<T>::~DoublyList(){
if(numOfElements!=0){
ListNode<T> *current;
current = front;
while (current != back)
{
ListNode<T> *temp = current;
current = current->next;
temp->next = NULL;
temp->prev = NULL;
delete temp;
numOfElements--;
}
//at this point current = back, now delete it
current->next = NULL;
current->prev = NULL;
delete current;
numOfElements--;
}
//this is a safeguard if you create a LL and then delete it without doing anything to it
else{
cout<<"deleted empty LL"<<endl;
delete front;
delete back;
}
}
template <typename T>
void DoublyList<T>::addFront(T d)
{
ListNode<T> *node = new ListNode<T>();
node->data = d;
if (isEmpty()){
back = node;
}
else{
front->prev = node;
}
node->next = front;
front = node;
++numOfElements;
}
template <typename T>
T DoublyList<T>::removeFront()
{
if (isEmpty()){
return T();
}
else
{
ListNode<T>* temp = front;
if (front->next == 0){
back = 0;
}
else
{
front->next->prev = 0;
}
front = front->next;
temp->next = 0;
T theData = temp->data;
delete temp;
--numOfElements;
return theData;
}
}
template <typename T>
void DoublyList<T>::addBack(T d)
{
ListNode<T> *node = new ListNode<T>();
node->data = d;
if (isEmpty()){
front = node;
}
else{
back->next = node;
}
node->prev = back;
back = node;
++numOfElements;
}
template <typename T>
T DoublyList<T>::removeBack()
{
if (isEmpty()) {
return T();
}
else
{
ListNode<T>* temp;
temp = back;
if (back->prev == 0){
front = 0;
}
else{
back->prev->next = 0;
}
back = back->prev;
temp->prev = 0;
T theData = temp->data;
delete temp;
--numOfElements;
return theData;
}
}
template <typename T>
T DoublyList<T>::peak()
{
if (isEmpty()) {
return T();
}
return front->data;
}
template <typename T>
int DoublyList<T>::getSize(){
return numOfElements;
}
template <typename T>
bool DoublyList<T>::isEmpty(){
if(numOfElements == 0){
return true;
}
else{
return false;
}
}
template <typename T>
void DoublyList<T>::printList(){
if(numOfElements!=0){
ListNode<T> *current = front;
while(current!=back)
{
cout<<current->data<<endl;
current = current->next;
}
cout<<back->data<<endl;
}
else{
cout<<"list is empty"<<endl;
}
}
template <typename T>
void DoublyList<T>::sortList(){
int size = getSize();
ListNode<T> *current;
ListNode<T> *dummy;
ListNode<T> *next;
if(current == NULL) return;
if(current -> next == NULL) return;
int swapped = 1;
while(swapped){
swapped = 0; //last pass unless there is a swap
while(current -> next != NULL){
if(current-> data < current -> next -> data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
dummy -> data = current -> data;
current -> data = current -> next -> data;
current -> next -> data = dummy -> data;
}
current = current -> next;
}
}
}
#endif
listNode.h:
#include <iostream>
#ifndef LISTNODE_H
#define LISTNODE_H
using namespace std;
template <typename T>
class ListNode
{
public:
T data;//the data that we will store
ListNode();
ListNode(int d);
~ListNode();
ListNode *next;//int and ptr and the member variables
ListNode *prev;
};
template <typename T>
ListNode<T>::ListNode(int d){
data = d;
next = NULL;
prev = NULL;
}
template <typename T>
ListNode<T>::ListNode(){}
template <typename T>
ListNode<T>::~ListNode(){
delete next;
delete prev;
cout<<"deleted Node"<<endl;
}
#endif
testList.cpp
#include <iostream>
#include "doublyList.h"
#include "genericQueue.h"
int main(){
DoublyList<int> testQueue;
testQueue.addBack(3);
testQueue.addBack(5);
testQueue.addBack(2);
testQueue.addBack(10);
testQueue.addBack(1);
cout << "Before Sort: " << endl;
testQueue.printList();
cout << "After Sort: " << endl;
testQueue.sortList();
testQueue.printList();
}
The erors I could find so far are:
Your default ListNode() constructor doesn't null the next and prev pointers.
In void DoublyList<T>::sortList() you don't initialize dummy, so it just points into nowhere. Actually there is no reason to use a node list at all, you can just directly use a variable of type T.
You don't initialize current in the same function and you actually should reset current to e.g. front at the beginning of each outer loop.
You don't use next at all (and don't need to), so just remove it.
To sum it up, this is what void DoublyList<T>::sortList() could look like:
template <typename T>
void DoublyList<T>::sortList(){
int size = getSize();
ListNode<T> *current=front;
T dummy;
if (current == NULL) return;
if (current->next == NULL) return;
int swapped = 1;
while (swapped){
current = front;
swapped = 0; //last pass unless there is a swap
while (current->next != NULL){
if (current->data < current->next->data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
dummy = current->data;
current->data = current->next->data;
current->next->data = dummy;
}
current = current->next;
}
}
}
and this is my suggestion for the ListNode constructor.
template <typename T>
ListNode<T>::ListNode() :
next(nullptr),
prev(nullptr),
data{}
{}
Besides that, I also agree with DaveB that swapping pointers is the approach you should actually use.
To start with you need to initialize current in your sort function,
current = first;
template <typename T>
void DoublyList<T>::sortList(){
ListNode<T> *current;
ListNode<T> *next;
T tmp;
current = front;
if(current == NULL) return;
if(current -> next == NULL) return;
int swapped = 1;
while(swapped){
swapped = 0; //last pass unless there is a swap
while(current->next != nullptr){
if(current->data < current->next->data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
tmp = current->data;
current->data = current->next->data;
current->next->data = tmp;
}
current = current -> next;
}
if (swapped) // go back to start of list for next pass
current = front;
}
}
I'm new with data structures in C++, and i'm trying to do a doubly linked list with templates. All the examples that i have seen are only for 1 element of the template node, so i'm trying to put 2 elements in the template node in the list, but i don't know how to do it, anyway, i tried to make the list.
Here's the code:
#include<iostream>
#include<cstring>
using namespace std;
template<class T>
// node class
class node
{
public:
node();
node(T);
~node();
node *next;
T data[2];
void borra_todo();
void print();
};
// by defect
template<typename T>
node<T>::node()
{
data[0] = NULL;
data[1] = NULL;
next = NULL;
}
// by parameter
template<typename T>
node<T>::node(T data_)
{
data[0] = data_[0];
data[1] = data_[1];
next = NULL;
}
// delete nodes
template<typename T>
void node<T>::borra_todo()
{
if (next)
next->borra_todo();
delete this;
}
// node printing
template<typename T>
void node<T>::print()
{
cout << data[0] << " " << data[1] << "->";
}
template<typename T>
node<T>::~node() {}
// list
template <class T>
class list
{
private:
node<T> *m_head;
int m_num_nodes;
public:
list();
~list();
void add_head(T);
void add_end(T);
void add_sort(T);
void fill(char r[30], char n[30]);
void search(T);
void del_by_data(T);
void print();
};
template<typename T>
list<T>::list()
{
m_num_nodes = 0;
m_head = NULL;
}
//add in the beginning
template<typename T>
void list<T>::add_head(T data_)
{
node<T> *new_node = new node<T>(data_);
node<T> *temp = m_head;
if (!m_head)
{
m_head = new_node;
}
else
{
new_node->next = m_head;
m_head = new_node;
while (temp)
{
temp = temp->next;
}
}
m_num_nodes++;
}
// add to the last
template<typename T>
void list<T>::add_end(T data_)
{
node<T> *new_node = new node<T> (data_);
node<T> *temp = m_head;
if (!m_head)
{
m_head = new_node;
}
else
{
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = new_node;
}
m_num_nodes++;
}
// it is supposed that sorts items in the list ...
template<typename T>
void list<T>::add_sort(T data_)
{
node<T> *new_node = new node<T> (data_);
node<T> *temp = m_head;
if (!m_head)
{
m_head = new_node;
}
else
{
for (int i =0; i <= 1; i++)
{
if (m_head->data[0] > data_[i])
{
new_node->next = m_head;
m_head = new_node;
}
else
{
while ((temp->next != NULL) && (temp->next->data[0] < data_[i]))
{
temp = temp->next;
}
new_node->next = temp->next;
temp->next = new_node;
}
}
m_num_nodes++;
}
}
// sort adding ...
template<typename T>
void list<T>::fill(char rfc[30])
{
char temprfc[30];
char tempnombre[30];
temprfc = "DUDE010101R0";
tempnombre = "Dude";
add_sort(temprfc, tempnombre);
temprfc = "AUDE010101R1";
tempnombre = "Commander";
add_sort(temprfc, tempnombre);
}
// print list
template<typename T>
void list<T>::print()
{
node<T> *temp = m_head;
if (!m_head)
{
cout << "List is empty" << endl;
}
else
{
while (temp)
{
temp->print();
if (!temp->next)
cout << "NULL\n";
temp = temp->next;
}
}
cout << endl;
}
// search the list
template<typename T>
void list<T>::search(T data_)
{
node<T> *temp=m_head;
int cont=1;
int cont2=0;
while(temp)
{
if(strcmp(temp->data,data_[0]))
{
cout<<"Element found " << temp->data;
cout << " in position: " << cont << endl;
cont2++;
}
temp=temp->next;
cont++;
}
if(cont2==0)
{
cout << "Element not found"<<endl;
}
}
// ... delete by data
template<typename T>
void list<T>::del_by_data(T data_)
{
node<T> *temp = m_head;
node<T> *temp1 = m_head->next;
int cont =0;
if (m_head->data == data_)
{
m_head = temp->next;
}
else
{
while (temp1)
{
if (temp1->data == data_)
{
node<T> *aux_node = temp1;
temp->next = temp1->next;
delete aux_node;
cont++;
m_num_nodes--;
}
temp = temp->next;
temp1 = temp1->next;
}
}
if (cont == 0)
{
cout << "No data" << endl;
}
}
// destroy the constructor
template<typename T>
list<T>::~list() {}
int main()
{
list<char> list1;
char element1[30];
char element2[30];
int dim, choice, pos;
do{
cout << "Select a choice.\n";
cout << "1. Print list\n";
cout << "2. Delete an element of the list\n";
cout << "3. Search an element of the list\n";
cout << "4. Exit\n";
cin >> choice;
switch(choice)
{
case 1:
{
cout << "Printing list:\n";
list1.fill("1","2");
list1.print();
break;
}
case 2:
{
cout << "Element to delete: ";
cin >> element1;
list1.search(element1);
element1 = "";
break;
}
case 3:
{
cout << "Element to search: ";
cin >> element1;
list1.search(element1);
element1 = "";
break;
}
}
}while(choice != 4);
return 0;
}
The code doesn't compile, it marks errors like:
" error: prototype for ‘void list::fill(char*)’ does not match any in class ‘list’
void list::fill(char rfc[30])
^
t3b.cpp:79:8: error: candidate is: void list::fill(char*, char*)
void fill(char r[30], char n[30]);"
Any ideas on how to fix it? Or any ideas on how to put 2 elements in a node using templates?
Thanks in advance.
Dude, you should really try to isolate the error a little bit before posting it. This is 500 lines of code, I had to copy and paste it all into an editor before I could even look at it.
When you declared fill, it had two arguments, when you defined it, it had one. Also, I would avoid arrays of characters for numerous reasons, instead use std::string.
I am using templates in c++ to create a linked list. I have coded a few functions , but the deletion of node ( either from head/tail ) isnt working properly. It displays an error and terminates. When debugging , the 'this' shown in watch windows contains a head which is null, which i have no idea why. Here is my code:
SLlistSc.h
#ifndef SLlistSc_H
#define SLlistSc_H
#include<iostream>
using namespace std;
template<class T> class SLlist;
template <class T> class snode{
friend class SLlist<T>;
private:
T info;
snode<T> *next;
public:
inline T getter() const { return info; }
inline void setter(T setValue){ info = setValue; }
snode(){ info = 0; next = 0; }
snode(T inf , snode *nex = 0){ info = inf; next = nex; }
~snode(){ delete next; }
};
template <class T> class SLlist{
private:
snode<T> *head, *tail;
static int total;
public:
SLlist(){ head = tail = 0; }
~SLlist(){
snode<T> *p = head;
while (head != 0){
head = head->next;
delete p;
p = head;
}
}
inline void incrcnt(){ total++; }
inline void decrcnt(){ total--; }
void displayList();
void addToHead(T inf);
void addToTail(T inf);
T deleteFromHead();
T deleteFromTail();
int returnIndex();
void deleteInfo();
void deleteAll();
};
template <class T> void SLlist<T>::displayList(){
snode<T> *p = head;
while (p != 0){
cout << "\n->" << p->info;
p = p->next;
}
return;
}
template <class T> void SLlist<T>::addToHead(T inf){
snode<T> *temp = new snode<T>(inf, 0);
if (head == 0){ head = tail = temp; temp = 0; delete temp; incrcnt(); return; }
else { temp->next = head; head = temp; temp = 0; delete temp; incrcnt(); return; }
}
template <class T> void SLlist<T>::addToTail(T inf){
snode<T> *temp = new snode<T>(inf, 0);
if (head == 0){ head = tail = temp; temp = 0; delete temp; incrcnt(); return; }
else{ tail->next = temp; tail = temp; temp = 0; delete temp; return; }
}
template <class T> T SLlist<T>::deleteFromHead(){
if (head == 0){ cout << "\nList is already empty"; return (T)0; }
if (head == tail){ delete head; head = tail = 0; T info = head->info; return info; }
else {
T info = head->info;
snode<T> *temp = head;
head = head->next;
temp = 0;
delete temp;
return info;
}
}
template <class T> T SLlist<T>::deleteFromTail(){
if (head == 0){ cout << "\nList is already empty"; return (T)0; }
if (head == tail){ delete head; head = tail = 0; T info = head->info; return info; }
else {
T info = tail->info;
snode<T> *temp = head;
while (temp != 0)
{
temp = tail;
}
delete tail;
tail = temp;
temp = 0; delete temp;
return (T)info;
}
}
#endif
and the cpp file : SLlistSc.cpp
// SLlistSc.cpp : Defines the entry point for the console application.
//
#include"SLlistSc.h"
#include<iostream>
using namespace std;
template <class T> int SLlist<T>::total = 0;
void main()
{
cout << "\t\t\t Singly Linked List Super Class Implementation";
SLlist<int> List1;
int userchoice=0, inf=0;
do{
cout << "\n\n\t\t Menu"
<< "\n\t1. Display List"
<< "\n\t2. Add to Head"
<< "\n\t3. Add to tail"
<< "\n\t4. Delete from Head"
<< "\n\t5. Delete from Tail"
<< "\n\t6. Exit";
cin >> userchoice;
switch (userchoice){
case 1: List1.displayList(); break;
case 2: cout << "\nEnter info to be added:";
cin >> inf;
List1.addToHead(inf); break;
case 3: cout << "\nEnter info to be added:";
cin >> inf;
List1.addToTail(inf); break;
case 4: inf = List1.deleteFromHead();
cout << "\n Value" << inf << "deleted from list"; break;
case 5: inf = List1.deleteFromTail();
cout << "\n Value" << inf << "deleted from list"; break;
case 6: cout << "\n\t\t\t\tExiting";
exit(0);
default: continue;
}
} while (userchoice < 4);
}
Another thing i would like to ask is , when we use templates on a class (eg. class A) , we are required to replace the A with A everywhere. Is it because compiler generates a new class ie.
A<T> isnt = A.
And while using friend class SLlist inside snode class , why do i have to declare as follows :
template<class T> class SLlist;
before the snode class? why cant i declare it directly in the snode class as :
friend class SLlist<T>;
Also if there is a chance of improvemet in my code , please go hard on me. Thanks.
You are attempting to use a pointer that is invalid because the block containing that pointer has been freed.
The Microsoft C++ debug runtime library overwrites freed memory with the pattern 0xFEEEFEEE which makes this problem easier to identify.
Trying to learn C++. Was wondering if someone could point me in the right direction on this error (pun intended).
The class is a LinkedList (reproduced in its entirety below). The error occurs on this line:
LinkedList<T>::ListNode LinkedList::find(int pos) const {
and says:
expected constructor, destructor, or type conversion before
'LinkedList'
Any tips would be greatly appreciated.
#ifndef LINKEDLIST_HPP
#define LINKEDLIST_HPP
#include <iostream>
using namespace std;
template <class T>
class LinkedList {
private:
// a ListNode consists of the item and a pointer to the next ListNode
struct ListNode {
T data;
ListNode *next;
};
int size; //Size of the list
ListNode *head; //the beginning of the list
public:
LinkedList(); // default oonstructor
~LinkedList(); // destructor
virtual bool isEmpty ();
virtual int getLength ();
virtual void insert (int pos, T item);
virtual T remove (int pos);
virtual T retrieve (int pos);
//helper methods
LinkedList(LinkedList ©List); //copy constructor
ListNode *find (int pos) const; // internal find function
};
//default constructor
template <class T>
LinkedList<T>::LinkedList() {
size = 0;
head = NULL;
}
//destructor
template <class T>
LinkedList<T>::~LinkedList() {
//loop through each node, and delete it
ListNode* current = head;
while (current != NULL) {
ListNode* next = current->next;
delete current;
current = next;
}
head = NULL; // set head node to back to null
}
//copy constructor
template <class T>
LinkedList<T>::LinkedList(LinkedList& copyList) {
size = copyList.size;
// if copyList is empty
if (copyList.head == NULL)
head = NULL;
else {
//create a new head
head = new ListNode;
head->data = copyList.head->data;
//create a new list
ListNode *newPtr = head; // start at the head
// iterate through rest of list to be copied
for (ListNode *copyPtr = copyList.head->next; copyPtr != NULL; copyPtr = copyPtr->next) {
newPtr->next = new ListNode;
newPtr->data = copyPtr->data;
}
//make last ListNode's next point to NULL
newPtr->next = NULL;
}
}
template <class T>
bool LinkedList<T>::isEmpty() {
if (size == 0)
return true;
return false;
}
template <class T>
int LinkedList<T>::getLength() {
return size;
}
// used in other methods to find a given index
template <class T>
LinkedList<T>::ListNode LinkedList::find(int pos) const {
// check that pos is in bound of LinkedList
if ((pos < 1) || pos > getLength()) {
cout << "Find position of out bounds" << endl;
return NULL;
} else { //search through ListNodes
ListNode *temp = head; // start at the head
for (int i = 1; i < pos; ++i)
temp = temp->next;
return temp;
}
}
template <class T>
T LinkedList<T>::retrieve(int pos) {
T tempData; // to hold retrieved data
try {
if ((pos < 1) || (pos > getLength())) {
cout << "Retrieve request outside LinkedList's bounds" << endl;
return NULL;
}
else { //traverse list
ListNode *temp = find(pos);
tempData = temp->data;
return tempData;
}
} catch (int e) {
cout << "Could not retrieve position " << pos << endl;
}
}
template <class T>
void LinkedList<T>::insert(int pos, T item) {
//check bounds
if ((pos < 1) || (pos > getLength() +1))
cout << "Must insert at a position between 1 and getLength() + 1" << endl;
else {
try {
//create new ListNode
ListNode *temp = new ListNode;
temp->data = item;
//if the new item is at the first position
if (pos == 1) {
temp->next = head;
head = temp;
}
else {
ListNode *prev = find(pos - 1);
temp->next = prev->next;
prev->next = temp;
}
//increment size
++size;
} catch (int e) {
cout << "Error inserting " << item << " at position " << pos << endl;
}
}
}
template <class T>
T LinkedList<T>::remove(int pos) {
//check bounds
if ((pos < 1) || (pos > getLength()))
cout << "Must remove a position between 1 and getLength()" << endl;
else {
try {
ListNode *temp; //to hold shifted node
//if node to be deleted is first node
if (pos == 1) {
temp = head;
head = head->next;
}
//for anything but the head
//write over the node before the pos'th index
else {
ListNode *prev = find(pos - 1);
temp = prev->next;
prev->next = temp->next;
}
//destroy temp, to free up memory
temp->next = NULL;
delete temp;
//decrement size
--size;
} catch (int e) {
cout << "Error removing item from position " << pos << endl;
}
}
}
#endif /* LINKEDLIST_HPP */
ListNode is a dependant type, so it needs to be qualified with typename. Also, your find function was declared to return a pointer-to-ListNode, but the definition returns a ListNode by value. This seems like a simple typo:
template <class T>
typename LinkedList<T>::ListNode* LinkedList<T>::find(int pos) const {
Qualify the dependant type with typename and add <T> (I'm not sure if this is necessary, might as well do it though):
typename LinkedList<T>::ListNode* LinkedList<T>::find(int pos) const {
See: Where and why do I have to put the "template" and "typename" keywords?
Also, your definition doesn't match. In-class it returns a pointer, but outside it returns a value.
Should be
LinkedList<T>::ListNode LinkedList<T>::find(int pos) const {
Trying to learn C++. I'm getting an error in my code, in the line:
class LinkedList : public LinkedList<T> {
The error says:
invalid use of incomplete type 'class
LinkedList,
std::allocator > >' declaration of 'class
LinkedList,
std::allocator > >'
Can anyone point out what I'm doing wrong? Here is the entire code.
#ifndef LINKEDLIST_HPP
#define LINKEDLIST_HPP
#include <iostream>
using namespace std;
template <class T>
class LinkedList : public LinkedList<T> {
private:
// a ListNode consists of the item and a pointer to the next ListNode
struct ListNode {
T data;
ListNode *next;
};
int size; //Size of the list
ListNode *head; //the beginning of the list
public:
LinkedList(); // default oonstructor
~LinkedList(); // destructor
virtual bool isEmpty ();
virtual int getLength ();
virtual void insert (int pos, T item);
virtual T remove (int pos);
virtual T retrieve (int pos);
//helper methods
LinkedList(LinkedList ©List); //copy constructor
ListNode *find (int pos) const; // internal find function
};
//default constructor
template <class T>
LinkedList<T>::LinkedList() {
size = 0;
head = NULL;
}
//destructor
template <class T>
LinkedList<T>::~LinkedList() {
//loop through each node, and delete it
ListNode* current = head;
while (current != NULL) {
ListNode* next = current->next;
delete current;
current = next;
}
head = NULL; // set head node to back to null
}
//copy constructor
template <class T>
LinkedList<T>::LinkedList(LinkedList& copyList) {
size = copyList.size;
// if copyList is empty
if (copyList.head == NULL)
head = NULL;
else {
//create a new head
head = new ListNode;
head->data = copyList.head->data;
//create a new list
ListNode *newPtr = head; // start at the head
// iterate through rest of list to be copied
for (ListNode *copyPtr = copyList.head->next; copyPtr != NULL; copyPtr = copyPtr->next) {
newPtr->next = new ListNode;
newPtr->data = copyPtr->data;
}
//make last ListNode's next point to NULL
newPtr->next = NULL;
}
}
template <class T>
bool LinkedList<T>::isEmpty() {
if (size == 0)
return true;
return false;
}
template <class T>
int LinkedList<T>::getLength() {
return size;
}
// used in other methods to find a given index
template <class T>
LinkedList<T>::ListNode LinkedList<T>::find(int pos) const {
// check that pos is in bound of LinkedList
if ((pos < 1) || pos > getLength()) {
cout << "Find position of out bounds" << endl;
return NULL;
} else { //search through ListNodes
ListNode *temp = head; // start at the head
for (int i = 1; i < pos; ++i)
temp = temp->next;
return temp;
}
}
template <class T>
T LinkedList<T>::retrieve(int pos) {
T tempData; // to hold retrieved data
try {
if ((pos < 1) || (pos > getLength())) {
cout << "Retrieve request outside LinkedList's bounds" << endl;
return NULL;
}
else { //traverse list
ListNode *temp = find(pos);
tempData = temp->data;
return tempData;
}
} catch (int e) {
cout << "Could not retrieve position " << pos << endl;
}
}
template <class T>
void LinkedList<T>::insert(int pos, T item) {
//check bounds
if ((pos < 1) || (pos > getLength() +1))
cout << "Must insert at a position between 1 and getLength() + 1" << endl;
else {
try {
//create new ListNode
ListNode *temp = new ListNode;
temp->data = item;
//if the new item is at the first position
if (pos == 1) {
temp->next = head;
head = temp;
}
else {
ListNode *prev = find(pos - 1);
temp->next = prev->next;
prev->next = temp;
}
//increment size
++size;
} catch (int e) {
cout << "Error inserting " << item << " at position " << pos << endl;
}
}
}
template <class T>
T LinkedList<T>::remove(int pos) {
//check bounds
if ((pos < 1) || (pos > getLength()))
cout << "Must remove a position between 1 and getLength()" << endl;
else {
try {
ListNode *temp; //to hold shifted node
//if node to be deleted is first node
if (pos == 1) {
temp = head;
head = head->next;
}
//for anything but the head
//write over the node before the pos'th index
else {
ListNode *prev = find(pos - 1);
temp = prev->next;
prev->next = temp->next;
}
//destroy temp, to free up memory
temp->next = NULL;
delete temp;
//decrement size
--size;
} catch (int e) {
cout << "Error removing item from position " << pos << endl;
}
}
}
#endif /* LINKEDLIST_HPP */
template <class T>
class LinkedList : public LinkedList<T> {
This doesn't make sense. It is like this:
class A : public A
Does this make sense to you? How exactly?
The class you're deriving from doesn't exist, rather it is being defined while you're deriving from it, so the compiler doesn't know what the base supposed to be. The compiler need to know the full definition of the base class before you derive from it.
Nawaz gave the right answer.
Just to give a few off-topic informations :
make your destructor virtual (even if inheriting from a templated container is not something very c++-ish).
Use const where it belongs :
LinkedList(const LinkedList ©List); //copy constructor
virtual bool isEmpty () const;
// etc.
Obviously, in real life you would use an stl container like std::list ;)