relational operator overloading not working in C++ - c++

I am trying to implement Huffman encoding in C++ using custom made priority_queue. I am storing the information in structure named Node. Here is the code
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
//two same name functions are for min heap and max heap(Function overloading)
struct Node{
char letter;
int value;
Node* left;
Node* right;
Node(char letter,int value, Node* left,Node* right){
this->letter = letter;
this->value = value;
this->left = left;
this->right = right;
}
bool operator < (const Node* &a){//HERE IS THE PROBLEM
if((this->value) < (a->value))
return true;
else
return false;
}
bool operator > (const Node* &a){//HERE IS THE PROBLEM
if((this->value) > (a->value))
return true;
else
return false;
}
};
template <class T>
class Priority_Queue{
public:
int k;
int sz;
vector<T> v;
Priority_Queue(int k){
sz = 0;
this->k = k;
}
void heapify(int index,int n){
int max_index = index;
for(int i = index*k+1;i <= min(n-1,index*k+k);++i){
if(v[i] > v[max_index])
max_index = i;
}
if(index != max_index){
swap(v[max_index],v[index]);
heapify(v,max_index,n);
}
}
void heapify(vector<int> &v,int index,int n,bool trigger){
//for calling min_heapify using function overloading
int min_index = index;
for(int i = index*k+1;i <= min(n-1,index*k+k);++i){
if(v[i] < v[min_index])
min_index = i;
}
if(index != min_index){
swap(v[min_index],v[index]);
heapify(v,min_index,n,trigger);
}
}
void Insert(T val){
if(sz == (int)v.size()){
v.push_back(val);
++sz;
}
else
v[sz++] = val;
int parent = (sz-1)/k;
int node = sz-1;
while(node >= 1){
int parent = (node-1)/k;
if(v[parent] < v[node]){
swap(v[parent],v[node]);
node = parent;
parent = (parent-1)/k;
}
else
break;
}
}
void Insert(T val, bool trigger){
if(sz == (int)v.size()){
v.push_back(val);
++sz;
}
else
v[sz++] = val;
int parent = (sz-1)/k;
int node = sz-1;
while(node >= 1){
int parent = (node-1)/k;
if(v[parent] > v[node]){// IF CONDITION DOESN'T WORK
swap(v[parent],v[node]);
node = parent;
parent = (parent-1)/k;
}
else
break;
}
}
void Pop(){
if(sz == 0){
cout << "Heap Underflow\n";
return;
}
swap(v[0],v[sz-1]);
--sz;
heapify(0,sz);
}
void Pop(bool trigger){
if(sz == 0){
cout << "Heap Underflow\n";
return;
}
swap(v[0],v[sz-1]);
--sz;
heapify(0,sz,trigger);
}
T Top(){
return v[0];
}
void printHeap(){
for(int i = 0; i < sz;++i){
cout << v[i]->value << " ";
}
cout << "\n";
}
};
int main()
{
string s;
cin >> s;
int n = s.length();
vector<int> freq(26,0);
for(int i = 0; i < n;++i){
++freq[s[i]-'a'];
}
Priority_Queue<Node*> pq(2);
for(int i = 0; i < 26;++i){
if(freq[i] == 0)
continue;
pq.Insert(new Node(char(i+'a'),freq[i],NULL,NULL),true);
}
pq.printHeap();
}
I don't have much experience with C++ and I am having trouble overloading relational operators where I want to compare two structure pointers based on the value parameter.For example: if I enter aab , the if condition in Insert function should be executed but it never happens. I searched up a lot regarding overloading of relational operators but none of them seem to fix the issue I am facing. Can someone please help me ? What am I doing wrong while overloading the operator?

You probably should make your method look like this:
bool operator<(const Node &node) const {
return value < node.value;
}
Notice the slightly different method signature. And then you should test it with an absolutely minimal method.
int main(int, char **) {
Node first{'a', 10, nullptr, nullptr};
Node second{'b', 5, nullptr, nullptr};
cout << "first < second: " << (first < second) << endl;
cout << "second < first: " << (second < first) << endl;
}
In your code, you might have to do this:
if (*v[index] < *v[otherIndex)
Another comment: don't name variables like v. That's going to bite you in the backside as your programs get bigger. Give them longer names that are more searchable and descriptive. vec is better than v.

Related

My C++ program returns EXC_BAD_ACCESS in Xcode ONLY

I made a program that involves a binary search tree. Basically, my segregates a set of input integers into "bins" in such a way that each bin are equal in value when their contents are summed.
#include <iostream>
#include <vector>
#ifndef DEBUG
#define DEBUG 0
#endif
using namespace std;
class Node {
private:
int weight = 0;
Node* leftNode;
Node* rightNode;
int bin = 0;
public:
Node() {}
Node(int weight) {
this->weight = weight;
}
void printContents() {
cout << weight << " ";
if(leftNode) leftNode->printContents();
if(rightNode) rightNode->printContents();
}
void addNode(Node* node) {
if(node->getWeight() <= this->weight) {
if(leftNode) leftNode->addNode(node);
else leftNode = node;
} else {
if(rightNode) rightNode->addNode(node);
else rightNode = node;
}
}
Node* getNode(int weight) {
if(!hasChildren()) {
if(this->weight == weight && bin == 0) return this;
else return nullptr;
} else {
Node* n = nullptr;
if(this->weight == weight && bin == 0) {
n = this;
}
Node* child;
if(leftNode && weight <= this->weight) {
child = leftNode->getNode(weight);
} else if(rightNode && weight > this->weight) {
child = rightNode->getNode(weight);
} else {
child = nullptr;
}
if(child) {
return child;
}
else return n;
}
}
bool hasChildren() {
if(leftNode || rightNode) return true;
else return false;
}
int getWeight() {
return weight;
}
void setBin(int bin) {
this->bin = bin;
}
int getBin() {
return bin;
}
void unbin() {
bin = 0;
}
void operator=(Node* node) {
this->weight = node->weight;
this->leftNode = node->leftNode;
this->rightNode = node->rightNode;
this->bin = node->bin;
}
};
class Bin {
private:
int binNum = 0;
int weight = 0;
int targetWeight = 0;
vector<Node*> nodes;
public:
Bin(int binNum, int targetWeight) {
this->binNum = binNum;
this->targetWeight = targetWeight;
}
void addNode(Node* node) {
weight += node->getWeight();
node->setBin(binNum);
nodes.push_back(node);
}
Node* removeLatestNode() {
Node* n = nodes.back();
weight -= n->getWeight();
nodes.pop_back();
n->unbin();
return n;
}
int getWeight() {
return weight;
}
bool isFull() {
if(weight == targetWeight) return true;
else return false;
}
bool willBeOverloaded(int x) {
if(weight + x > targetWeight) return true;
else return false;
}
};
void organize(Node* rootNode, int bins, int weightPerBin) {
#if DEBUG
cout << "Weight per bin: " << weightPerBin << endl;
#endif
for(int i = 1; i <= bins; i++) {
Bin bin(i, weightPerBin);
int x = weightPerBin;
while(!bin.isFull()) {
while(x > 0) {
Node* n = rootNode->getNode(x);
if (n) {
#if DEBUG
cout << "bin " << i << " : ";
cout << n->getWeight() << endl;
#endif
if (!bin.willBeOverloaded(n->getWeight())) {
#if DEBUG
cout << "adding to bin " << i << " : " << n->getWeight() << endl;
#endif
bin.addNode(n);
x = weightPerBin - bin.getWeight();
if(bin.isFull()) break;
} else {
x--;
}
} else {
x--;
}
}
if(!bin.isFull()) {
Node* n = bin.removeLatestNode();
#if DEBUG
cout << "removing from bin " << i << " : " << n->getWeight() << endl;
#endif
x = n->getWeight() - 1;
}
}
}
}
int getWeightPerBin(int* weights, int n, int bins) {
int weight = 0;
for(int i = 0; i < n; i++) {
weight += weights[i];
}
return weight/bins;
}
int main() {
int n;
int *weights;
int bins;
cin >> n;
weights = new int[n];
for(int i = 0; i < n; i++)
cin >> weights[i];
cin >> bins;
Node nodes[n];
nodes[0] = new Node(weights[0]); //the root node
for(int i = 1; i < n; i++) {
nodes[i] = new Node(weights[i]);
nodes[0].addNode(&nodes[i]);
}
organize(&nodes[0], bins, getWeightPerBin(weights, n, bins));
for(int i = 0; i < n; i++) {
cout << nodes[i].getBin() << " ";
}
return 0;
}
I developed this program in CLion IDE and it works perfectly. Recently I discovered that Xcode can also be used to develop C++ programs so I tried using it with the exact same code. But when I run the program, it always returns:
xcode error screenshot
It returns an error called EXC_BAD_ACCESS which is the first time I've encountered it. I'm a student who has a good background in Java and is currently learning C++ for a class. My knowledge in C++ is limited and I'd like to know whether this problem is due to Xcode or is inherent in my code.
You don't initialize leftNode and rightNode - they are not magically initialized to nullptr, so calling a function like
void printContents() {
cout << weight << " ";
if(leftNode) leftNode->printContents();
if(rightNode) rightNode->printContents();
}
will have Undefined Behaviour.
I suggest you initialize your variables before using them.

LinkedList Backtracking

I'm trying to backtrack through a linkedlist I have created to solve a knight's tour problem, but once I hit a condition requiring me to backtrack, it totally empties the list. I have figured out it is because when I return false from the function findpath() to keep my while loop going, it continually loops back through the goback() function. What I'm having trouble figuring out is why. When i go through the goback function and call the calcmove function, it pushes the correct move to the structure I have declared, so passing false should keep the loop going and restart with the boolean cando and figuring out if that is false or not. But, it should be true because I just tested it and pushed it to the stack. Instead, it's emptying the list after I backtrack for the first time. So calcmove() would just be returning false every time after the first pop. But I don't see why that's happening. I need to return false to keep the loop going. What I need it to do is go back only once, find a new move, and continue on. Why would it be looping back to the function where the value on the list gets popped? If the value worked, and a new move is created (which I did verify it is doing correctly), it should be ready to call with a new (true) boolean. Is this just an inherently bad way of implementing the backtracking?
#include "stdafx.h"
#include "Header.h"
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
llist list;
Move m;
int board[8][8];
int cx[] = { -2, -1, 1, 2, 2, 1, -2, -1 };
int cy[] = { 1, 2, 2, 1, -1, -2, -1, -2 };
int movenum = 1;
Move first;
/*Check to see if move is within the constraints of the board*/
bool constraints(int k, int b) {
if ((k < 0) || (b < 0) || (k > 7) || (b > 7) || (board[k][b] != -1)) {
return true;
}
else {
return false;
}
}
/* Initialization of 8x8 board, fill the array with -1 */
void initboard() {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
board[x][y] = -1;
}
}
}
/* Output the current board array */
void printboard(int arr[8][8]) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
cout << std::setw(2) << arr[x][y] << " ";
}
cout << endl;
}
}
void updateboard(int k, int b) {
board[k][b] = movenum;
movenum++;
}
bool calcmove(int x, int y, int i) {
for (i; i < 9; i++) {
int a0 = x + cx[i];
int a1 = y + cy[i];
/*if(board[a0][a1] == board[first.x][first.y]){
}*/
if (constraints(a0, a1) == false) {
updateboard(a0, a1);
m.x = a0;
m.y = a1;
m.index = i;
list.push(m);
//list.display();
return true;
}
}
return false;
}
void goback(int k, int b) {
board[k][b] = -1;
list.display();
Move m = list.pop();
bool cando = calcmove(m.x, m.y, m.index);
cout << "prev is " << m.x << " , " << m.y << endl;
if (cando) {
return;
}
else {
goback(m.x,m.y);
}
}
bool findpath(){
bool cando = calcmove(m.x, m.y, 0);
if (cando) {
return false;
}
else {
movenum--;
goback(m.x, m.y);
return false; /*------> inserting this here drains the list*/
}
return true;
}
int main()
{
int m1 = 1;
int m2 = 2; //random
first.x = m1;
first.y = m2;
first.index = 0;
list.push(first); //push first node on to stack
initboard();
updateboard(m1, m2); //update board
while (!findpath()) {
;
}
printboard(board);
}
the .h file:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include <ostream>
using std::cout;
using std::endl;
using std::setw;
struct Move {
int x;
int y;
uint32_t index;
};
struct node
{
public:
Move info;
struct node *next;
};
class llist {
struct node *start;
public:
void push(Move coords) {
struct node *p = new node;
p = newnode(coords);
if (start == NULL) {
start = p;
}
else {
p->next = start;
start = p;
//cout << "pushed" << endl;
}
}
Move pop() {
if (start == NULL) {
throw std::runtime_error("The list is empty");
}
else {
struct node *temp = new node;
temp = start;
Move data = start->info;
start = start->next;
delete temp;
//cout << "pop successful" << endl;
return data;
}
}
node *newnode(Move value) {
struct node *temp = new(struct node);
if (temp == NULL) {
return 0;
}
else {
temp->info = value;
temp->next = NULL;
return temp;
}
}
void display()
{
struct node *temp;
if (start == NULL)
{
cout << "The List is Empty" << endl;
return;
}
temp = start;
cout << "Elements of list are: " << endl;
while (temp != NULL)
{
cout << temp->info.x << "->";
temp = temp->next;
}
cout << "empty" << endl;
}
};
The goal of this is to create a linked list, solve the problem using the list for backtracking (push the current move unless no moves are available, then pop the previous values), and return the completed board.

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

Segmentation fault in trie implementation using vector c++

#include <iostream>
#include <vector>
#include <string>
using namespace std;
#define LOWERCASE_ALPHABET_SiZE 26
typedef int (*ptr) (char );
inline int charToIndex(char a) { return a - 'a'; };
class trienode
{
private:
vector< trienode* > child;
bool leaf;
public:
trienode(int );
~trienode();
void initialiseChild(int i);
trienode* getChild(int i);
void setLeaf() { leaf = true; };
bool isLeaf() { return leaf; };
};
trienode::trienode(int size)
{
for(int i = 0; i < size; i++)
{
child.push_back(NULL);
}
leaf = false;
}
trienode::~trienode()
{
for(int i = 0; i < child.size(); i++)
{
delete child.at(i);
child.at(i) = NULL;
}
}
void trienode::initialiseChild(int i)
{
child.at(i) = new trienode(child.size());
}
trienode* trienode::getChild(int i)
{
return child.at(i);
}
class trie
{
private:
trienode* root;
ptr toIndex;
public:
trie(int , ptr );
~trie();
void insert(const string& ref);
bool search(const string& ref);
};
trie::trie(int size, ptr toIndex) : toIndex(toIndex), root(new trienode(size)) { }
trie::~trie()
{
cout << "In destructor trie" << endl;
delete root;
root = NULL;
}
void trie::insert(const string& ref)
{
int size = ref.size();
trienode* root = root;
for(int i = 0; i < size; i++)
{
int index = toIndex(ref[i]);
if(root->getChild(index) == NULL) // crashing in getChild()
{
root->initialiseChild(index);
}
root = root->getChild(index);
}
root->setLeaf();
}
bool trie::search(const string& ref)
{
trienode* root = root;
int size = ref.size();
for(int i = 0; i < size && root != NULL; i++)
{
int index = toIndex(ref[i]);
if((root = root->getChild(index)) == NULL)
{
break;
}
}
return (root != NULL && root->isLeaf());
}
int main(int argc,char* argv[])
{
trie* altrie = new trie(LOWERCASE_ALPHABET_SiZE, charToIndex);
int n;
string temp;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> temp;
altrie->insert(temp);
}
int k;
for(int i = 0; i < k; i++)
{
cin >> temp;
if(altrie->search(temp))
{
cout << temp << " exists in the trie" << endl;
}
else
{
cout << temp << " doesn`t exist in the trie" << endl;
}
}
return 0;
}
I am creating Trie by supplying no of children it can have in each level and function pointer to convert the given character to index. After that I am Creating the root node of trie and when I`m inserting the first string it is getting Segmentation Fault in getChild Function
First things first explain me the reason behind the crash.
Explain me how I can improve the implementation of trie.
You are using the same name for member and local variables, like this:
trienode* root = root;
The compiler cannot tell the diffirence between the local root and trie::root so you are assigning it to itself.

Doubly linked list and how to move the iterator to the next node

I have to build a Deque list and inside the the Deque list, it has a function call find, to find the value inside the list. But I'm having problem to try to move the iter over to the next node if that node does not contain the value that I am searching for. Her is the snippet of my find function:
unique_ptr<DequeIterator<E>> find(E match)
{
assert(!is_empty());
bool is_found = true;
// set the pointer point to the first node from the beginning
unique_ptr<DequeIterator<E>> iter(iter_begin());
while(iter->node()->value() != match)
{
// here is I want to move the iter position
// over to the next node
iter->next();
// print out the value at the node to re-check if
// it matches
cout << iter->node()->value() << endl;
}
if(is_found)
{
cout << "found" << iter->node()->value() << endl;
}
else
cout << "no match" << endl;
return iter;
}
unique_ptr<DequeIterator<E>> iter_begin()
{
// _head is set to nullptr inside the constructor
return unique_ptr<DequeIterator<E>>(new DequeIterator<E>(_head));
}
DequeIterator class
template<class E>
class DequeIterator {
public:
// You may need to modify this class. Feel free to modify the definitions of
// these functions, or add new member functions.
DequeIterator(DNode<E>* node) {
_node = node;
}
bool at_end() {
return _node == nullptr;
}
E value() {
assert(!at_end());
return _node->value();
}
void set_value(E x) {
assert(!at_end());
_node->set_value(x);
}
void next() {
assert(!at_end());
_node = _node->next();
}
DNode<E>* node() { return _node; }
private:
DNode<E>* _node;
};
This is my DNode class
template<class E>
class DNode {
public:
DNode(DNode<E>* prev, E value, DNode<E>* next) {
_value = value;
_prev = prev;
_next = next;
dnode_census++;
}
~DNode() {
dnode_census--;
}
// The program crashes right here
// after it goes into the E value()
E value() { return _value; }
void set_value(E value) { _value = value; }
DNode<E>* prev() { return _prev; }
void set_prev(DNode<E>* prev) { _prev = prev; }
DNode<E>* next() { return _next; }
void set_next(DNode<E>* next) { _next = next; }
private:
E _value;
DNode<E> *_prev;
DNode<E> *_next;
};
Deque class
template<class E>
class Deque {
public:
Deque()
{
_head = 0;
_size = 0;
_tail = 0;
}
~Deque() {
clear();
}
// Make the deque empty. O(n) time.
void clear() {
while (!is_empty())
erase_back();
}
// Return the current size of the deque. O(1) time.
int size() {
return _size;
}
// Return true when the deque is empty. O(1) time.
bool is_empty() {
return (size() == 0);
}
unique_ptr<DequeIterator<E>> iter_begin()
{
return unique_ptr<DequeIterator<E>>(new DequeIterator<E>(_head));
}
unique_ptr<DequeIterator<E>> iter_at(int index)
{
assert((index >= 0) && (index <= size()));
unique_ptr<DequeIterator<E>> iter(iter_begin());
for(int j = 0; j < index; j++)
iter->next();
return iter;
}
E front()
{
assert(!is_empty());
return _head->value();
}
E back()
{
assert(!is_empty());
return _tail->value();
}
void insert_after(DequeIterator<E>& iter, E x)
{
if(_size == 0)
{
insert_front(x);
}
else
{
assert(!iter.at_end());
DNode<E>* temp = new DNode<E>(iter.node(), x, iter.node()->next());
iter.node()->next()->set_next(temp);
iter.node()->next()->set_prev(temp);
}
_size++;
}
void insert_before(DequeIterator<E>& iter, E x)
{
if(_size == 0)
{
insert_front(x);
}
else
{
assert(!is_empty());
DNode<E>* temp2 = new DNode<E>(iter.node()->prev(), x, iter.node());
(iter.node()->prev())->set_next(temp2);
(iter.node()->prev())->set_prev(temp2);
}
_size++;
}
void insert_front(E x)
{
if(is_empty())
{
DNode<E>* temp = new DNode<E>(nullptr, x, nullptr);
_head = temp;
_tail = temp;
}
else
{
DNode<E>* temp = _head;
DNode<E>* temp2 = new DNode<E>(nullptr, x, temp);
_head = temp2;
}
_size++;
}
void insert_back(E x)
{
if(is_empty())
{
insert_front(x);
}
else
{
assert(!is_empty());
DNode<E>* temp = new DNode<E>(_tail, x, nullptr);
_tail = temp;
_size++;
if(_size > 1)
cout << _tail->prev()->value() << endl;
}
}
void erase(DequeIterator<E>& iter)
{
assert((!is_empty()) || !iter.at_end());
DNode<E>* temp = iter.node();
temp->next()->set_prev(temp->prev());
temp->prev()->set_next(temp->next());
delete iter.node()->next();
_size--;
}
void erase_front()
{
assert(!is_empty());
DNode<E>* temp = _head;
_head = temp->next();
delete temp;
_size--;
}
void erase_back()
{
assert(!is_empty());
DNode<E>* temp = _tail;
_tail = temp->prev();
delete temp;
_size--;
}
unique_ptr<DequeIterator<E>> find(E match)
{
assert(!is_empty());
bool is_found = true;
unique_ptr<DequeIterator<E>> iter(iter_begin());
while(iter->value() != match)
{
iter->next();
cout << iter->value() << endl;
}
if(is_found)
{
cout << "found" << iter->node()->value() << endl;
}
else
cout << "no match" << endl;
return iter;
}
// Return the element value at position index, which must be
// valid. O(n) time.
E get(int index)
{
assert((index >= 0) && (index < size()));
unique_ptr<DequeIterator<E>> iter(iter_begin());
for(int j = 0; j < index; j++)
iter->next();
return iter->node()->value();
}
void meld(Deque<E>& other)
{
}
private:
DNode<E>* _head;
DNode<E>* _tail;
int _size;
};
main.cpp
int main() {
assert_no_leak(0);
// Element objects to reuse. All upper case letters of the alphabet.
//const int N = 5;
const int N = 26;
char letters[N];
for (int i = 0; i < N; i++)
letters[i] = 'A' + i;
// Now there are a series of unit tests. Each test checks a few
// related member functions. The tests use assert(...) to look for
// bugs, so if one of these assertions fails, that indicates a bug
// in your deque code.
print_test_title("Deque constructor");
unique_ptr<Deque<char>> q(new Deque<char>());
assert_no_leak(0);
print_test_title("Deque::size");
assert(q->size() == 0);
print_test_title("Deque::is_empty");
assert(q->is_empty());
print_test_title("Deque::insert_back");
for (int i = 0; i < N; i++) {
assert(q->size() == i);
assert_no_leak(i);
q->insert_back(letters[i]);
assert(!q->is_empty());
assert(q->size() == (i+1));
assert_no_leak(i+1);
}
print_test_title("iteration");
unique_ptr<DequeIterator<char>> iter(q->iter_begin());
assert(!iter->at_end());
assert_no_leak(N);
for (int i = 0; !iter->at_end(); i++, iter->next()) {
assert(i < N);
assert(iter->value() == letters[i]);
assert_no_leak(N);
}
assert_no_leak(N);
/* for (int i = 0; i < N; i++)
cout << q->get(i) << endl;*/
print_test_title("Deque::find");
iter = q->find('A');
assert(!iter->at_end());
assert(iter->value() == 'A');
assert_no_leak(N);
**// This is where I got the unhandled exception**
iter = q->find('T');
assert(!iter->at_end());
assert(iter->value() == 'T');
assert_no_leak(N);
iter = q->find('?');
assert(iter->at_end());
assert_no_leak(N);
print_test_title("Deque::get");
for (int index = 0; index < N; index++) {
assert(q->get(index) == letters[index]);
assert_no_leak(N);
}
print_test_title("Deque::front");
assert(q->front() == 'C');
assert_no_leak(N);
print_test_title("Deque::back");
assert(q->back() == 'Z');
assert_no_leak(N);
print_test_title("Deque::erase_front");
for (int i = 0; i < N; i++) {
assert(q->front() == letters[i]);
assert(q->size() == (N-i));
assert_no_leak(N-i);
q->erase_front();
}
assert(q->is_empty());
assert_no_leak(0);
print_test_title("Deque::erase_back");
for (int i = 0; i < N; i++)
q->insert_back(letters[i]);
for (int i = 0; i < N; i++) {
assert(q->back() == letters[N-i-1]);
assert(q->size() == (N-i));
assert_no_leak(N-i);
q->erase_back();
}
assert(q->is_empty());
assert_no_leak(0);
print_test_title("Deque::insert_front");
for (int i = 0; i < N; i++) {
q->insert_front(letters[i]);
assert(q->front() == letters[i]);
assert(q->size() == (i+1));
assert_no_leak(i+1);
}
assert(q->size() == N);
assert_no_leak(N);
print_test_title("Deque::clear");
q->clear();
assert(q->is_empty());
assert_no_leak(0);
for (int size = 0; size <= N; size++) {
assert(q->is_empty());
assert_no_leak(0);
for (int i = 0; i < size; i++)
q->insert_back(letters[i]);
assert(q->size() == size);
assert_no_leak(size);
q->clear();
assert(q->is_empty());
assert_no_leak(0);
}
print_test_title("insert_after, insert_before, erase");
assert(q->is_empty());
iter = q->iter_begin(); // iter is at end of empty queue
q->insert_before(*iter, 'X');
assert(queue_equals_string(*q, "X"));
assert_no_leak(1);
iter = q->iter_begin(); // iter is at start of queue with 1 element
q->insert_after(*iter, 'O');
assert(queue_equals_string(*q, "XO"));
assert_no_leak(2);
q->insert_after(*iter, 'Z');
assert(queue_equals_string(*q, "XZO"));
assert_no_leak(3);
iter->next(); // iter is at second position (Z)
q->insert_before(*iter, 'C');
assert(queue_equals_string(*q, "XCZO"));
assert_no_leak(4);
q->insert_after(*iter, 'A');
assert(queue_equals_string(*q, "XCZAO"));
assert_no_leak(5);
iter->next(); // iter is at fourth position (A)
q->erase(*iter); // erase A
assert(queue_equals_string(*q, "XCZO"));
assert_no_leak(4);
iter = q->iter_begin(); // X
iter->next(); // C
iter->next(); // Z
q->erase(*iter); // erase Z
assert(queue_equals_string(*q, "XCO"));
assert_no_leak(3);
q->erase(*q->iter_begin()); // erase X
assert(queue_equals_string(*q, "CO"));
assert_no_leak(2);
iter = q->iter_begin(); // erase O
iter->next();
q->erase(*iter);
assert(queue_equals_string(*q, "C"));
assert_no_leak(1);
q->erase(*q->iter_begin()); // erase C
assert(queue_equals_string(*q, ""));
assert_no_leak(0);
print_test_title("Deque::splice");
assert(q->is_empty());
assert_no_leak(0);
unique_ptr<Deque<char>> q2(new Deque<char>());
assert_no_leak(0);
for (int i = 0; i < 5; i++) {
q->insert_back(letters[i]);
q2->insert_back(letters[i]);
}
assert(q->size() == 5);
assert(q2->size() == 5);
assert_no_leak(10);
q->meld(*q2);
assert(q->size() == 10);
assert(q2->is_empty());
assert_no_leak(10);
assert(queue_equals_string(*q, "ABCDEABCDE"));
if (DO_PERFORMANCE_TEST) {
print_test_title("Performance");
q->clear();
time_t start = time(nullptr);
for (int i = 0; i < BIG_N; i++) {
q->insert_front('A');
if ((i % 1000) == 0)
cout << '.';
}
time_t stop = time(nullptr);
assert(q->size() == BIG_N);
cout << endl
<< " Elapsed time to insert_front " << BIG_N << " times: "
<< (stop - start) << " seconds" << endl;
}
return 0;
}
You're not really doing anything with that iterator. The whole point is you want to change it to point to the next item in the list.
Normally with iterators you would implement operator++. It might look something like this:
template <class E>
DequeIterator<E> & DequeIterator::operator++()
{
_node = _node->next;
return *this;
}
It's not clear why you are allocating your iterators and using unique_ptr. Normally you return iterators by value, and their internals are very simple (a pointer or two). No need to allocate them on the heap.
After seeing your iterator code, it seems you're just using the wrong next(). You're calling it on the current node, rather than the iterator:
iter->node()->next(); // incorrect
iter->next(); // correct
As suggested by WhozCraig in the comments:
the difference between this iterator and a post-increment matching
implementation with its by-value temp-copy return may be warranted for
the casual reader.
The ++ operation I gave was the prefix operator, meaning you need to do ++*iter. If you want to do (*iter)++, you need a postfix operator:
template <class E> DequeIterator<E> DequeIterator::operator++(int) {
DequeIterator<E> temp(*this);
_node = _node->next;
return temp;
}
And since your list is double-linked, you might like to provide the appropriate -- prefix and postfix operators.