So I've got to implement doubly linked list. I've got constructor, destructor, many other methods like inserting too. But as I would like to apply to The Rule of Three I would need to implement copy assignment operator and a copy constructor. I've seen many solutions on the internet, but all of them required std::swap and std::move or std::copy. I cannot use any of those as all my algorithms have to be done without STL or boost::. I know I have to start like this:
list & list::operator=(const list & that)
{
if (this != &that)
{
}
return *this;
}
Then I would to something like this:
if (this != &that)
{
this->clear();
node *t = this->head;
node *o = that.head;
while (o->next)
{
t.append(o.value);
o = o.next;
t = t->next
}
}
return *this;
#Edit:
void menu_list()
{
char opt;
int *t;
list myList = list();
do {
display_menu("--- LISTA ---");
opt = _getche();
std::cout << '\n';
switch (opt) {
case '1': //reading a list from a text file
{
int elements;
std::ifstream file_stream;//
file_stream.open("data.txt"); //
if (!file_stream.good()) //
{
std::cout << "Nie udalo sie wczytac pliku!" << '\n';
break;
}
file_stream >> elements; //
t = new int[elements]; // stworzenie listy
for (int i = 0; i<elements; i++)
{
file_stream >> *(t + i); //
}
myList = list(t, elements); //zainicjalizowanie listy
delete[] t; //
std::cout << "\nObecny stan listy: "; std::cout << myList.to_string() << '\n';
break;
}
case '2': //deleting an element from a list
{
if (myList.is_empty())
{
std::cout << "Lista jest pusta! \n"; break;
}
int index;
std::cout << "Podaj indeks elementu do usuniecia: ";
scanf_s("%d", &index);
if (myList.size() <= index)
{
std::cout << "Lista nie ma tylu elementow!\n"; break;
}
else if (index < 0)
{
std::cout << "Indeks nie moze byc mniejszy od 0!\n"; break;
}
myList.remove(index);
std::cout << "\nObecny stan listy: "; std::cout << myList.to_string() << '\n';
break;
}
list.cpp (implementation of list header):
#include "list.h"
#include <ctime>
list::list() : head(nullptr), tail(nullptr), n(0)
{
}
list::list(int* t, int n) : head(nullptr), tail(nullptr), n(0)
{
if (!this->is_empty())
{
this->clear();
}
for (int i = 0; i < n; i++)
{
this->append(t[i]);
}
}
list::list(const list& obj)
{
}
clear() is a method that clears the whole list (and head and tail = nullptr) and append() is a method that appends a value at the end of a list.
Now, I guess this is wrong, but I don't have any clue how to make it work and I'd like to ask you guys how can I do it
Related
I have a problem with queue, with deleting first elements. Pointer "nastepca" should store address of next structure variable in a queue, but it stores nullptr for all of data in the structure and I cannot fixed it. I have tried many option but none of them worked. Is my queue works properly, is it put data in correct way, address alongside address before?
dolacz() - means add/equeue
zdejmij() - means delete/dequeue
koniec - means end
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class Kolejka
{
struct Element
{
T dane;
Element* nastepca;
Element(const T& dane, Element* nastepca) : dane(dane), nastepca(nastepca) {}
};
Element* start = nullptr; //pusty wskaznik nullptr
Element* koniec = nullptr; //pusty wskaznik nullptr
int licz_elementow = 0;
public:
void dolacz(const T& dane)
{
if (start == nullptr) //jezeli kolejka jest pusta to dodaj na poczatek (poczatek i koniec jest ten sam)
{
start = new Element(dane, start);
licz_elementow++;
}
else
{
ss++;
koniec = new Element(dane, koniec);
licz_elementow++;
}
}
void zdejmij() //nie działa
{
if (start == koniec)
{
start = koniec = nullptr;
licz_elementow--;
}
else
{
Element* tmp = start;
start = start->nastepca;
delete tmp;
licz_elementow--;
}
}
T& gora() //zwroci referencje typu T na początek kolejki
{
if (koniec == nullptr)
{
throw runtime_error("Pusta kolejka!");
}
return start->dane;
}
T& tyl() //zwroci referencje typu T na koniec kolejki
{
if (koniec == nullptr)
{
throw runtime_error("Pusta kolejka!");
}
return koniec->dane;
}
int rozmiar()
{
return licz_elementow;
}
bool pusty()
{
return start == nullptr;
}
};
class Auto
{
string marka;
friend ostream& operator <<(ostream& w, Auto& a); //zaprzyjaźniona funkcja przeciążająca operator <<
public:
Auto(string marka): marka(marka) {}
};
ostream& operator <<(ostream& w, Auto& a)
{
w << a.marka;
return w;
}
int main()
{
Kolejka <Auto> kol;
try
{
kol.dolacz(Auto("aaa"));
kol.dolacz(Auto("bbb"));
kol.dolacz(Auto("ccc"));
kol.dolacz(Auto("ddd"));
kol.zdejmij();
cout << "Liczba elementow: ";
cout << kol.rozmiar();
cout << endl;
cout << "Poczatek kolejki: ";
cout << kol.gora();
cout << endl;
cout << "Koniec kolejki: ";
cout << kol.tyl();
}
catch (runtime_error& BLAD)
{
cout << BLAD.what();
}
}
enter image description here
While debugging:
nastepca always have 0x00000000
start = new Element(dane, start);
should be
start = koniec = new Element(dane, nullptr);
When you add the first element, you should change the first and last pointers.
koniec = new Element(dane, koniec);
should be
Element* temp = new Element(dane, nullptr);
koniec->nastepca = temp;
koniec = temp;
When you add a new element (apart from the first) you need to make the old last element point to the new last element.
Pointer operations are tricky, you have to think carefully about what you are really doing. It might help to draw diagrams of the operations you have coded. That way you'd qucikly see that what you coded wasn't right.
I am working on a problem that requires the implementation of two ADT's. After Implementing, I need to test my bag implementations with the following template combinations:
<int, string>-- all functions
<string, int> -- insert and find functions only
My testing so far has been entering integers to test the different functions. I do not understand what it means to test the implementations with the templates.
Here is my bagADT implementation:
#include <stdlib.h>
#include "bagADT.h"
template <typename E>
class ABag : public Bag<E> {
private:
int maxSize;
int listSize;
E* listArray;
public:
ABag(int size = defaultSize) { // Constructor
maxSize = size;
listSize = 0;
listArray = new E[maxSize];
}
~ABag() { delete[] listArray; } // Destructor
bool addItem(const E& item) {
if (listSize >= maxSize) {
return false;
}
listArray[listSize] = item;
std::cout << "Add Item: Added " << item << " in spot " << listSize << std::endl;
listSize++;
return true;
}
bool remove(E& item) {
for (int i = 0; i < listSize; i++) {
if (listArray[i] == item) {
std::cout << "Remove: Removed " << item << " from position ";
item = i;
std::cout<< item << " and adjusted the location of all other elements." << std::endl;
for (i= item; i < listSize; i++) {
listArray[i] = listArray[i + 1];
}
listSize--;
return true;
}
}
return false;
}
bool removeTop(E& returnValue) {
if (listSize == 0) {
return false;
}
else {
returnValue = listArray[listSize - 1];
std::cout << "Remove Top: Removed " << returnValue << " from the top of the stack." << std::endl;
for (int i = listSize; i < maxSize; i++) {
listArray[i] = listArray[i + 1];
}
listSize--;
return true;
}
}
bool find(E& returnValue) const {
for (int i = 0; i < (listSize - 1); i++) {
if (listArray[i] == returnValue) {
returnValue = i;
return true;
}
}
return false;
}
bool inspectTop(E& item) const {
if (listSize == 0) {
return false;
}
else {
item = listArray[listSize - 1];
std::cout << "Inspect Top: The value on top is currently " << item << "." << std::endl;
return true;
}
}
void emptyBag() {
delete[] listArray;
listSize = 0;
listArray = new E[maxSize];
std::cout << "Empty Bag: Emptied the bag." << std::endl;
}
bool operator+=(const E& addend) {
if (listSize < maxSize) {
return true;
}
return false;
}
int size() const {
std::cout << "Size: Number of elements in listArray: " << listSize << std::endl;
return (listSize - 1);
}
int bagCapacity() const {
std::cout << "Bag Capacity: The capacity of this bag is " << maxSize << std::endl;
return maxSize;
}
};
Here is another file provided by my professor called kvpairs:
#ifndef KVPAIR_H
#define KVPAIR_H
// Container for a key-value pair
// Key object must be an object for which the == operator is defined.
// For example, int and string will work since they both have == defined,
// but Int will not work since it does not have == defined.
template <typename Key, typename E>
class KVpair {
private:
Key k;
E e;
public:
// Constructors
KVpair() {}
KVpair(Key kval, E eval)
{
k = kval; e = eval;
}
KVpair(const KVpair& o) // Copy constructor
{
k = o.k; e = o.e;
}
void operator =(const KVpair& o) // Assignment operator
{
k = o.k; e = o.e;
}
bool operator==(const KVpair& o) const {
if (o.k == k) {
return true;
}
return false;
}
//The following overload is provided by Adam Morrone, Spring 2016 class.
//Thanks Adam :)
friend ostream& operator<<(ostream& os, const KVpair& o) // output print operator
{
os << "Key: " << o.k << " Value: " << o.e;
return os;
}
// Data member access functions
Key key() { return k; }
void setKey(Key ink) { k = ink; }
E value() { return e; }
};
#endif
I am expected to show the test outputs using the above templates, but I have no idea how to do this. Also, ignore the += overload. It is incorrect and I know. I am supposed to overload it to directly add a new int to the array.
I think I understand now. I could be wrong, but this is my guess.
Your bag is singly templated, but it will be holding KVpair. They said they will use KVpair with <int, string> and <string, int>.
When they talk about testing it, that means they will be instantiating it as follows:
int main() {
ABag<KVPair<int, string>> bag;
bag.addItem(KVpair(1, "hi"));
//...
}
This is what I am pretty sure they mean by "testing it with templates".
As a minor edit, I don't know what C++ version you are using but if it's very archaic, you might need to write template instantiation like ABag<KVPair<int, string> > instead of putting them together. I remember vaguely this being an issue a long time ago.
I am writing a priority queue with a max heap structure as an assignment for school. I can either write it as an array or I can use a vector. I chose a vector. So the assignment is this, the user chooses options from a menu where he either wants to add,print, or view the elements. When the user chooses to add he gets ask who wants to be added, the instructor, student, or TA. He can enter i,I,t,T,S,s. The instructor having the highest priority where if the user chooses the option to print and there is an instructor in the queue he gets to go first. The TA having the second highest priority where if there is a TA and a student in the queue, the TA goes first. If there is is more than one instructor than the queue acts as a normal queue. I have written most of it, or tried. I got my max heap implementation from my textbook since they provide one. Now the problem is this, when I have more than one item in the priority queue and I choose to print, it crashes and gives me a vector subscript out of range exception. I been trying to fix it and no luck. Also, when I try to print the elements in the queue or print them, it needs to say the job# with the name of the person. Can someone help me find a way to implement that.
#pragma once
#include <vector>
struct Heap
{
std::vector<int> m_elements;
void ReHeapDown(int, int);
void ReHeapUp(int, int);
void Swap(int& a, int& b);
};
#include "heap.h"
void Heap::ReHeapDown(int index, int bottom)
{
int maxChild, rightChild, leftChild;
leftChild = index * 2 + 1;
rightChild = index * 2 + 2;
if (leftChild <= bottom)
{
if (leftChild == bottom)
maxChild = leftChild;
else
{
if (m_elements[leftChild] <= m_elements[rightChild])
maxChild = rightChild;
else
maxChild = leftChild;
}
if (m_elements[index] < m_elements[maxChild])
{
Swap(m_elements[index], m_elements[maxChild]);
ReHeapDown(maxChild, bottom);
}
}
}
void Heap::ReHeapUp(int index, int bottom)
{
int parent;
if (bottom > index)
{
parent = (bottom - 1) / 2;
if (m_elements[parent] < m_elements[bottom])
{
Swap(m_elements[parent], m_elements[bottom]);
ReHeapUp(index, parent);
}
}
}
void Heap::Swap(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
}
#include <iostream>
#include "heap.h"
#pragma once
class PQTYPE
{
private:
Heap m_Items;
public:
bool isEmpty() const;
void Enqueue(int, std::string);
void Dequeue(int, std::string);
void printElements();
};
#include "pqtype.h"
bool PQTYPE::isEmpty() const
{
return m_Items.m_elements.empty();
}
void PQTYPE::Enqueue(int newItem, std::string lName)
{
if (lName == "Student")
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (lName == "TA")
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (lName == "Instructor")
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
}
void PQTYPE::Dequeue(int item, std::string lName)
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
m_Items.m_elements[0] = m_Items.m_elements.back();
std::cout << "Now printing Job#" << m_Items.m_elements[item - 1] << " " << lName.c_str() << std::endl;
m_Items.m_elements.pop_back();
m_Items.ReHeapDown(0, item - 1);
}
}
void PQTYPE::printElements()
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
for (int i = 0; i < m_Items.m_elements.size(); i++)
{
std::cout << "Job#" << m_Items.m_elements[i] << std::endl;
}
}
}
#include"pqtype.h"
struct Person
{
int m_priority;
std::string m_name;
Person()
{
m_priority = 0;
m_name = " ";
}
};
int showMenu();
void addJobs(PQTYPE&, Person&);
void printJobs(PQTYPE&, Person&);
void viewJobs(PQTYPE&);
int main()
{
int option;
Person p;
PQTYPE pq;
do
{
option = showMenu();
switch (option)
{
case 1: addJobs(pq, p);
break;
case 2: printJobs(pq, p);
break;
case 3: viewJobs(pq);
break;
case 4:
break;
default: std::cout << "Wrong input\n";
break;
}
} while (option != 4);
return 0;
}
int showMenu()
{
int choice;
std::cout << " 1.)Add Job\n";
std::cout << " 2.)Print Job\n";
std::cout << " 3.)View Jobs\n";
std::cout << " 4.)Exit\n";
std::cout << " Enter Choice: ";
std::cin >> choice;
return choice;
}
void addJobs(PQTYPE& pq, Person& per)
{
char jobChoice;
std::cout << "Who is the job for ( Instructor(i or I), TA(t or T), Student(s or S) :";
std::cin >> jobChoice;
if (jobChoice == 'S' || jobChoice == 's')
{
per.m_priority++;
per.m_name = "Student";
pq.Enqueue(per.m_priority, per.m_name);
}
else if (jobChoice == 'T' || jobChoice == 't')
{
per.m_priority++;
per.m_name = "TA";
pq.Enqueue(per.m_priority, per.m_name);
}
if (jobChoice == 'I' || jobChoice == 'i')
{
per.m_priority++;
per.m_name = "Instructor";
pq.Enqueue(per.m_priority, per.m_name);
}
}
void printJobs(PQTYPE& pq, Person& p)
{
pq.Dequeue(p.m_priority, p.m_name);
}
void viewJobs(PQTYPE& pq)
{
pq.printElements();
}
In your original code the index used inside Dequeue() for accessing the vector doesn't seem to be initialised in the right way. Let's assume that you have added two entries to your list. In this case the value of P.m_priority inside your main() is 2. Now you're calling printJobs() for the first time. printJobs() calls pq.Dequeue(p.m_priority, p.m_name), so Dequeue() gets p.m_priority as its parameter item. Keep in mind that item has the value 2.
m_Items.m_elements[0] = m_Items.m_elements.back();
std::cout << "Now printing Job#" << m_Items.m_elements[item - 1] << " " << lName.c_str() << std::endl;
m_Items.m_elements.pop_back();
You're accessing your std::vector using an index of item - 1. This works for the first time, as there are two elements in your list. In this call, there is also a pop_back() done on your list, which decreases its size by one. The next time you call printJobs(), the given parameter item won't have changed, it still has the value 2. When you access your Itemlist, there is no longer an index of 1, and an subscript out of range exception will be thrown.
There were no fixed priorities assigned to the three entry types in your original version, so I added these (see addJobs() ).
So a possible solution to store the person's name could look like this:
struct Person
{
int m_priority;
std::string m_name;
Person()
{
m_priority = 0;
m_name = " ";
}
};
struct Heap
{
std::vector<Person> m_elements;
void ReHeapDown(int, int);
void ReHeapUp(int, int);
void Swap(Person& a, Person& b);
};
void Heap::ReHeapDown(int index, int bottom)
{
int maxChild, rightChild, leftChild;
leftChild = index * 2 + 1;
rightChild = index * 2 + 2;
if (leftChild <= bottom)
{
if (leftChild == bottom)
maxChild = leftChild;
else
{
if (m_elements[leftChild].m_priority <= m_elements[rightChild].m_priority)
maxChild = rightChild;
else
maxChild = leftChild;
}
if (m_elements[index].m_priority < m_elements[maxChild].m_priority)
{
Swap(m_elements[index], m_elements[maxChild]);
ReHeapDown(maxChild, bottom);
}
}
}
void Heap::ReHeapUp(int index, int bottom)
{
int parent;
if (bottom > index)
{
parent = (bottom - 1) / 2;
if (m_elements[parent].m_priority < m_elements[bottom].m_priority)
{
Swap(m_elements[parent], m_elements[bottom]);
ReHeapUp(index, parent);
}
}
}
void Heap::Swap(Person& a, Person& b)
{
Person temp;
temp = a;
a = b;
b = temp;
}
#include <iostream>
class PQTYPE
{
private:
Heap m_Items;
public:
bool isEmpty() const;
void Enqueue(Person);
void Dequeue();
void printElements();
};
bool PQTYPE::isEmpty() const
{
return m_Items.m_elements.empty();
}
void PQTYPE::Enqueue(Person newItem)
{
if (!newItem.m_name.compare("Student"))
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (!newItem.m_name.compare("TA"))
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (!newItem.m_name.compare("Instructor"))
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
}
void PQTYPE::Dequeue()
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
Person front = m_Items.m_elements.front();
std::cout << "Now printing Job#" << front.m_priority << " " << front.m_name.c_str() << std::endl;
m_Items.m_elements.erase(m_Items.m_elements.begin());
m_Items.ReHeapDown(0, m_Items.m_elements.size() - 1);
}
}
void PQTYPE::printElements()
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
for (int i = 0; i < m_Items.m_elements.size(); i++)
{
std::cout << "Job#" << m_Items.m_elements[i].m_priority << " " << m_Items.m_elements[i].m_name.c_str() << std::endl;
}
}
}
int showMenu();
void addJobs(PQTYPE&, Person&);
void printJobs(PQTYPE&, Person&);
void viewJobs(PQTYPE&);
int showMenu()
{
int choice;
std::cout << " 1.)Add Job\n";
std::cout << " 2.)Print Job\n";
std::cout << " 3.)View Jobs\n";
std::cout << " 4.)Exit\n";
std::cout << " Enter Choice: ";
std::cin >> choice;
return choice;
}
void addJobs(PQTYPE& pq, Person& per)
{
char jobChoice;
std::cout << "Who is the job for ( Instructor(i or I), TA(t or T), Student(s or S) :";
std::cin >> jobChoice;
if (jobChoice == 'S' || jobChoice == 's')
{
per.m_priority = 0;
per.m_name = "Student";
pq.Enqueue(per);
}
else if (jobChoice == 'T' || jobChoice == 't')
{
per.m_priority = 1;
per.m_name = "TA";
pq.Enqueue(per);
}
if (jobChoice == 'I' || jobChoice == 'i')
{
per.m_priority = 2;
per.m_name = "Instructor";
pq.Enqueue(per);
}
}
void printJobs(PQTYPE& pq)
{
pq.Dequeue();
}
void viewJobs(PQTYPE& pq)
{
pq.printElements();
}
int main()
int option;
Person p;
PQTYPE pq;
do
{
option = showMenu();
switch (option)
{
case 1: addJobs(pq, p);
break;
case 2: printJobs(pq);
break;
case 3: viewJobs(pq);
break;
case 4:
break;
default: std::cout << "Wrong input\n";
break;
}
} while (option != 4);
return 0
}
Are you sure that the methods ReHeapUp and ReHeapDown meet your requirements? And shouldn't there be a distinction between job number and priority?
I am creating a graph class that implements a findEdges() function. I created the graph class using an adjacency list using the std::list<>. For some reason when I run my driver program it reads from a file and creates the graph correctly. But when I try to choose a point and use findEdges() it works for the first test case but any case I read in after that just returns a blank set for some reason.
I will post some code below:
class Graph
{
public:
// Non-Default Constructor
inline Graph(int num) : cap(num), numItems(0) { adjList = new list<Vertex[num]; }
// Copy constructor
inline Graph(const Graph & rhs) throw (const char *) { *this = rhs; }
// Destructor
inline ~Graph() {delete [] adjList;};
// Assignment operator
inline const Graph & operator = (const Graph & rhs) throw (const char *);
inline bool isEdge(const Vertex v1, const Vertex v2) const;
inline Set<Vertex> findEdges(CourseVertex theVertex);
inline void add(Vertex v1, Vertex v2);
inline void add(Vertex v1, Set<Vertex> groupV);
inline int size() const { return cap; }
inline void clear() {numItems=0;}
private:
list<Vertex> * adjList;
int cap;
int numItems;
};
Find Edges Function:
Set<Vertex> Graph::findEdges(CourseVertex theVertex)
{
Set<Vertex> edges;
// Loop through adjList array
for(int i = 0; i < cap; i++)
{
// Find v1's adjacency list
if (*adjList[i].begin() == theVertex)
{
//cerr << adjList[i].getText() << endl;
// Loop through adjacency list and find vertices
// containg and edge with theVertex
for(list<Vertex>::const_iterator it = adjList[i].begin();
it != adjList[i].end(); ++it)
{
++it;
edges.insert(*it);
}
}
// if have not found v2, return false (or if v1 is not in the list)
return edges;
}
}
Driver Function:*
void testFindAll()
{
try
{
Graph g1(28);
CourseVertex vFrom;
CourseVertex vTo;
{
Graph g2(g1.size());
// read the class dependencies from a file
// CS124 CS165 CIT225 ECEN160 |
ifstream fin("/home/cs235/week13/cs.txt");
assert(fin.good());
while (fin >> vFrom) // read the first vertex, the class
{
cerr << "First Vertex: " << vFrom.getText() << endl;
while (fin >> vTo){ // keep reading until the "|" is encountered
cerr << "Prerequisites: " << vTo.getText() << endl;
g2.add(vFrom, vTo);
}
fin.clear(); // clear the error state which came from the "|"
fin.ignore();
}
fin.close();
g1 = g2;
//TESTING CORRECT INPUT GRAPHS - DELETE
/**********************************************************************/
for (int i = 0; i < g2.size(); i++){
list<Vertex>::const_iterator it;
for( it = g2.adjList[i].begin(); it != g2.adjList[i].end(); ++it)
cout << *it << " ";
cout << endl;
}
for (int i = 0; i < g1.size(); i++){
list<Vertex>::const_iterator it;
for( it = g1.adjList[i].begin(); it != g1.adjList[i].end(); ++it)
cout << *it << " ";
cout << endl;
}
/**********************************************************************/
g2.clear();
}
// g2 is destroyed
// prompt for the next class
cout << "For the given class, the prerequisites will be listed:\n";
cout << "> ";
while (cin >> vFrom)
{
Set <Vertex> s = g1.findEdges(vFrom);
cerr << s << endl;
for (SetConstIterator <Vertex> it = s.cbegin(); it != s.cend(); ++it)
{
cout << '\t' << (vTo = *it) << endl;
}
cout << "> ";
}
}
catch (const char * error)
{
cout << error << endl;
}
}
This is my output. The output that's between the curly brackets are how many Point there are until an edge.
So the file I read in should look like this:
CS165 CS124 |
CS235 CS165 |
CS237 CS165 |
CS238 CS237 |
CS246 CS235 |
CS306 CS235 CS237 |
This is what my output looks like:
For the given class, the prerequisites will be listed:
> CS165
{ CS124 }
CS124
> CS235
{ }
This is what my output should look like:
For the given class, the prerequisites will be listed:
> CS165
{ CS124 }
CS124
> CS235
{ CS165 }
CS165
Due to some cerr's I'm able to see that it's creating my graph correctly, with the right edges and everything. For some reason my findEdges() function returns an empty set when I attempt to find the edge of anything past the first line of the graph. Any help is appreciated.
Assignment Operator:
const Graph & Graph::operator = (const Graph & rhs) throw (const char *)
{
if (this != &rhs) // check that not self-assignment
{
//--Allocate a new array if necessary
if (cap != rhs.cap)
{
//delete [] adjList;
cap = rhs.cap;
adjList = new std::list<Vertex>[cap];
if (adjList == 0) // Check if memory available
{
std::cerr << "ERROR: Unable to allocate a new buffer for Vector\n";
}
}
//--- Copy rightHandSide's list elements into this new array
cap = rhs.cap;
for (int i = 0; i < cap; i++)
{
//std::cerr<<adjList[i]<<std::endl;
adjList[i] = rhs.adjList[i];
}
}
return *this;
}
I tried to strictly implement in c++ what I'm studying in algorithmic at the moment, recursive functions with simple linked lists. Here is what I've come by :
#include <iostream>
using namespace std;
class Liste {
private :
int val;
Liste *suivante;
public :
Liste(int val = 0, Liste *suivante = NULL) {
this->val = val;
this->suivante = suivante;
}
void afficherElement() const {
cout << "Adresse : " << this << endl;
cout << "Valeur : " << val << endl;
cout << "Adresse suivante : " << suivante << endl;
cout << endl;
}
int tete() const {
return val;
}
Liste reste() const {
return *suivante;
}
bool estVide() const {
return (suivante == NULL);
}
Liste prefixer(int val) {
Liste *nouvelle = new Liste(val, this);
return *nouvelle;
}
Liste suffixer(int val) {
suivante = new Liste(val);
afficherElement(); // test (last element won't be displayed)
return *suivante;
}
};
int main() {
Liste uneListe(3); // 1st element
uneListe.suffixer(5).suffixer(8).suffixer(10); // adding 3 more
cout << "-----------\n\n";
uneListe.afficherElement(); // displaying 1st element : ok
uneListe.reste().afficherElement(); // displaying 2nd element : pointer is NULL !!???
// uneListe.reste().reste().afficherElement(); --> segmentation fault, predictably enough
return 0;
}
As you can guess, it doesn't work. When I add elements, calling the display method within the add method, elements seem to be well formed although the pointer value and the next element's adress differ (I don't get why).
But, after adding process is done, I try to display the list again, 1st element is well linked with 2nd, but then there is a NULL pointer value. Wonder why ??
I've seen a code with two classes (Node and List), that works fine, but I'd like to know what is wrong with mine. Is it that I'm creating new objects of a class within this same class ?
Thanks,
for right this problem you most change this line
Liste suffixer(int val)
to
Liste* suffixer(int val)
and then change this line
return *suivante;
to
return suivante;
and in main use this line
uneListe.suffixer(5)->suffixer(8)->suffixer(10);
instead of
uneListe.suffixer(5).suffixer(8).suffixer(10);
Your class methods Liste::prefixer(int val) and Liste suffixer(int val) will return a copy of the object created, they should return a pointer to the object (or a reference).
e.g.
Liste *Liste::suffixer(int val){
if(suivante == nullptr)
suivante = new Liste(val);
else
throw std::runtime_error("Generic error message");
return suivante;
}
or
Liste &Liste::suffixer(int val){
... previous inner method ...
return *suivante;
}
Class Liste contains a value and a reference, which is not what a list is: a singly linked list is a pointer to an element containing a value and a pointer to the next node.
You might use a value+pointer element as a list object, ignoring the val member. This would require different coding for some methods, e.g., for tete() and reste().
But, since using
typedef Liste * real_list_type;
is what you have in mind (? - see below), let's look at the methods.
bool estVide() const { return (suivante == NULL); }
This is in contradiction to the real_list_type being a mere List *; if you compare this to method reste(), it actually tests whether the tail is empty, not the list itself! (It would be in sync with using a value+pointer object as the list object.)
Liste suffixer(int val) { suivante = new Liste(val); ... }
This is bad: it replaces suivante with a new object, no matter what's stored in there (a memory leak). You'll have to do
Liste suffixer(int val) {
if( suivante == NULL ){
suivante = new Liste(val);
} else {
suivante->suffixer( val );
}
return *this;
}
LATER
I think that would be the best way to keep it as close to the abstract concept as possible. Note that there is no "isEmpty" - this is done by a test whether the List * variable representing the list equals NULL, but you can't have a method for that.
template<typename T>
class List {
public:
List( T v, List* t = nullptr ) : value(v), next(t){}
~List(){ delete next; }
List* prepend( T v ){
return new List( v, this );
}
List* append( T v ){
if( next == nullptr ){
next = new List( v );
} else {
next->append( v );
}
return this;
}
T head(){ return value; }
List* tail(){ return next; }
void dump(){
List* curr = this;
std::string del = "";
while( curr != nullptr ){
std::cout << del << curr->value;
del = ", ";
curr = curr->next;
}
std::cout << std::endl;
}
private:
T value;
List* next;
};
int main(){
typedef List<int> * intList;
intList list = new List<int>( 1 );
list->append( 2 )->append( 3 );
list->dump();
}
Here is the "fixed" version of my first attempt :
#include <iostream>
using namespace std;
class Liste {
private :
int val;
bool vide;
Liste *suivante;
public :
Liste(int val = 0, bool vide = true, Liste *suivante = NULL) {
this->val = val;
this->vide = vide;
this->suivante = suivante;
}
void afficherElement() const {
cout << "Adresse : " << this << endl;
cout << "Valeur : " << val << endl;
cout << "Vide : " << vide << endl;
cout << "Adresse suivante : " << suivante << endl;
cout << endl;
}
int head() const {
return val;
}
Liste *reste() const {
return suivante;
}
bool estVide() const {
return vide;
}
Liste *prefixer(int val) {
Liste *nouvelle = new Liste(val, this);
return nouvelle;
}
Liste *suffixer(int val) {
if(suivante == NULL) {
suivante = new Liste(val);
vide = false;
}
return suivante;
}
};
void afficherListe(Liste *uneListe) {
(*uneListe).afficherElement();
if(!(*uneListe).estVide()) {
afficherListe((*uneListe).reste());
}
}
int main() {
Liste *test = new Liste(3);
(*test).suffixer(5);
afficherListe(test);
return 0;
}
As expected it's awfully unpractical.
Laune's solution looks good...
However, the whole thing is bizarre, I suppose I'd be better off sticking with the regular List/Nodes way. Definitely gonna talk about that with my teacher.