patterncppMinor
Double-ended queue and iterators
Viewed 0 times
doubleandqueueiteratorsended
Problem
I have created a double-ended container, but I have doubts about its efficiency in terms of performance. Can you please criticize the code? What can be done extra, such as shortening it?
```
#ifndef EXERCISE_H_
#define EXERCISE_H_
#include
typedef unsigned short ushort;
template
class list{
type_t data;
ushort size_;
public:
list head, tail, next, prev;
list();
virtual ~list();
ushort &size();
void setData(type_t);
type_t getData();
virtual void push_back(type_t) = 0;
virtual type_t pop_front() = 0;
virtual void push_front(type_t) = 0;
virtual type_t pop_back() = 0;
virtual type_t front() = 0;
virtual type_t back() = 0;
virtual void print() = 0;
};
// DEFAULT CTOR
template
list::list() : size_(0){ this->head = this->tail = this->next = this->prev = nullptr;}
// DTOR
template
list::~list() {}
template
ushort & list::size(){
return size_;
}
template
void list::setData(type_t value){
this->data = value;
}
template
type_t list::getData(){
return this->data;
}
/*\
* DEQUEUE CLASS
\*/
template
class dequeue : public list {
public:
void push_back(type_t);
type_t pop_front();
void push_front(type_t);
type_t pop_back();
type_t front();
type_t back();
void print();
};
// PUSH_BACK func
template
void dequeue::push_back(type_t value){
list * item = new dequeue;
if (!item) throw std::bad_alloc();
item->setData(value);
if (this->tail) {
this->tail->next = item;
item->prev = this->tail;
}
this->tail = item;
++this->size();
if (!this->head) this->head = this->tail;
}
// POP_BACK func
template
type_t dequeue::pop_back(){
if(!this->head) throw std::out_of_range("List is empty");
list * item;
type_t value;
if(this->tail && this->tail != this->head){
item = this->tail;
value = this->tail->getData();
this->tail = this->
```
#ifndef EXERCISE_H_
#define EXERCISE_H_
#include
typedef unsigned short ushort;
template
class list{
type_t data;
ushort size_;
public:
list head, tail, next, prev;
list();
virtual ~list();
ushort &size();
void setData(type_t);
type_t getData();
virtual void push_back(type_t) = 0;
virtual type_t pop_front() = 0;
virtual void push_front(type_t) = 0;
virtual type_t pop_back() = 0;
virtual type_t front() = 0;
virtual type_t back() = 0;
virtual void print() = 0;
};
// DEFAULT CTOR
template
list::list() : size_(0){ this->head = this->tail = this->next = this->prev = nullptr;}
// DTOR
template
list::~list() {}
template
ushort & list::size(){
return size_;
}
template
void list::setData(type_t value){
this->data = value;
}
template
type_t list::getData(){
return this->data;
}
/*\
* DEQUEUE CLASS
\*/
template
class dequeue : public list {
public:
void push_back(type_t);
type_t pop_front();
void push_front(type_t);
type_t pop_back();
type_t front();
type_t back();
void print();
};
// PUSH_BACK func
template
void dequeue::push_back(type_t value){
list * item = new dequeue;
if (!item) throw std::bad_alloc();
item->setData(value);
if (this->tail) {
this->tail->next = item;
item->prev = this->tail;
}
this->tail = item;
++this->size();
if (!this->head) this->head = this->tail;
}
// POP_BACK func
template
type_t dequeue::pop_back(){
if(!this->head) throw std::out_of_range("List is empty");
list * item;
type_t value;
if(this->tail && this->tail != this->head){
item = this->tail;
value = this->tail->getData();
this->tail = this->
Solution
-
I really recommend using an explicit type for your linked-list node:
Then, in your actual dequeue class you would have:
-
Returning the size as a reference is a no-no: the caller may assign some nonsensical value to it, which will break the invariants of your dequeue.
-
When it comes to terminology, "dequeue" is actually called deque (double-ended queue). Dequeue is a canonical name for the operation of removing and returning the head node in a FIFO queue data structure.
-
Your print function is a bit ad-hoc. There are two better options:
-
Add iterators. After doing that, you can use:
-
In your deque type, don't forget to delete all elements in its destructor.
I really recommend using an explicit type for your linked-list node:
template
struct linked_list_node
{
T datum;
linked_list_node* next;
linked_list_node* prev;
}Then, in your actual dequeue class you would have:
linked_list_node* head;
linked_list_node* tail;
size_t size;-
Returning the size as a reference is a no-no: the caller may assign some nonsensical value to it, which will break the invariants of your dequeue.
-
When it comes to terminology, "dequeue" is actually called deque (double-ended queue). Dequeue is a canonical name for the operation of removing and returning the head node in a FIFO queue data structure.
-
Your print function is a bit ad-hoc. There are two better options:
- Override
template std::ostream& operator&)
-
Add iterators. After doing that, you can use:
std::copy(dec.begin(), dec.end(), std::ostream_iterator(cout, ", "));-
In your deque type, don't forget to delete all elements in its destructor.
Code Snippets
template<typename T>
struct linked_list_node
{
T datum;
linked_list_node<T>* next;
linked_list_node<T>* prev;
}linked_list_node<T>* head;
linked_list_node<T>* tail;
size_t size;std::copy(dec.begin(), dec.end(), std::ostream_iterator<T>(cout, ", "));Context
StackExchange Code Review Q#151482, answer score: 8
Revisions (0)
No revisions yet.