Writing a double-linked list seemed like a good practice for understanding it. I tried to fix all the errors that were pointed out to me in the last question, as well as add new functionality. In General, I will be happy to receive new optimization tips and answers with instructions for bugs or memory leaks.
#include <ctime>
#include <random>
template <typename T>
class QEList
{
private:
struct Node
{
Node *right;
Node *left;
T value;
Node(Node* left_a,const T& value_a, Node* right_a) : left(left_a), value(value_a), right(right_a) {}
Node(Node* left_a,Node* right_a) : left(left_a) , right(right_a) {}
};
public:
class const_iterator;
class iterator : public std::iterator<std::bidirectional_iterator_tag,Node,int,Node*,T>
{
friend class QEList;
friend class const_iterator;
private:
typename iterator::pointer ptr;
iterator(typename iterator::pointer ptr_a) : ptr(ptr_a) {}
public:
iterator& operator++()
{
ptr = ptr->right;
return *this;
}
iterator& operator--()
{
ptr = ptr->left;
return *this;
}
iterator operator++(int)
{
typename iterator::pointer temp = ptr;
ptr = ptr->right;
return temp;
}
iterator operator--(int)
{
typename iterator::pointer temp = ptr;
ptr = ptr->left;
return temp;
}
typename iterator::reference operator*() { return ptr->value; } //возвращает ссылку на значение узла
friend bool operator==(const iterator& i1, const iterator& i2){ return i1.ptr == i2.ptr; }
friend bool operator!=(const iterator& i1, const iterator& i2) { return !(i1 == i2); }
friend bool operator==(const iterator& iter, const const_iterator& c_iter);
friend bool operator!=(const iterator& iter, const const_iterator& c_iter);
};
class const_iterator : public std::iterator<std::bidirectional_iterator_tag,const Node,int,const Node *,const T>//comments from iterator are also relevant for const_iterator
{
friend class QEList;
private:
typename const_iterator::pointer ptr;
const_iterator(typename const_iterator::pointer ptr_a) : ptr(ptr_a) {}
public:
const_iterator(const iterator& iter) : ptr(iter.ptr) {}
const_iterator& operator++()
{
ptr = ptr->right;
return *this;
}
const_iterator& operator--()
{
ptr = ptr->left;
return *this;
}
const_iterator operator++(int)
{
typename const_iterator::pointer temp = ptr;
ptr = ptr->right;
return temp;
}
const_iterator operator--(int)
{
typename const_iterator::pointer temp = ptr;
ptr = ptr->left;
return temp;
}
typename const_iterator::reference operator*() { return ptr->value; }
friend bool operator==(const const_iterator& c_iter1, const const_iterator& c_iter2) { return c_iter1.ptr == c_iter2.ptr; }
friend bool operator!=(const const_iterator& c_iter1, const const_iterator& c_iter2) { return !(c_iter1 == c_iter2); }
friend bool operator==(const iterator& iter, const const_iterator& c_iter);
friend bool operator!=(const iterator& iter, const const_iterator& c_iter);
};
friend bool operator==(const iterator& iter, const const_iterator& c_iter) { return iter.ptr == c_iter.ptr; }
friend bool operator!=(const iterator& iter, const const_iterator& c_iter) { return !(iter == c_iter); }
QEList() = default;
template<typename... Types>
QEList(const T &value,Types&&... values) : QEList(values...)
{
push_front(value);
}
QEList(const QEList &QEL) { *this = QEL; }
QEList(const_iterator begin_pos,const const_iterator end_pos) // copies everything from begin_pos to end_pos (end_pos itself is not copied)
{
for(;begin_pos != end_pos;begin_pos++)
this->push_back(*begin_pos);
}
QEList(T &&value) { push_front(value); }
~QEList()
{
this->clear();
delete end_ptr;
}
void pop_back()//deletes the last node
{
Node* temp = end_ptr;
end_ptr = end_ptr->left;
end_ptr->right = nullptr;
delete temp;
m_size--;
}
void pop_front()//deletes the first node
{
Node* temp = head;
head = head->right;
head->left = nullptr;
delete temp;
m_size--;
}
void push_back(const T &value_a)//adds the value to the end of the list
{
end_ptr = new Node(end_ptr,nullptr);
end_ptr->left->value = value_a;
if(m_size > 0) end_ptr->left->left->right = end_ptr->left;
end_ptr->left->right = end_ptr;
m_size++;
}
void push_front(const T &value_a)//adds the value to the top of the list
{
head = new Node(nullptr,value_a,head);
head->right->left = head;
m_size++;
}
void clear()
{
Node *buffer;
for(int i = 0;i<m_size;i++)
{
buffer = head;
head = head->right;
delete buffer;
}
head = end_ptr;
m_size = 0;
}
void erase(const_iterator position)//deletes the node that the iterator points to (the iterator itself becomes hung)
{
if(position.ptr != head && position.ptr != end_ptr->left)
{
position.ptr->left->right = position.ptr->right;
position.ptr->right->left = position.ptr->left;
delete position.ptr;
m_size--;
}
else if(position.ptr == head)
{
this->pop_front();
}
else
{
this->pop_back();
}
}
void erase(const_iterator begin_pos,const const_iterator end_pos)//deletes everything from begin_pos to end_pos (end_pos itself is not deleted)
{
while(begin_pos != end_pos)
{
this->erase(begin_pos++);
}
}
iterator begin() { return iterator(head); }
const_iterator cbegin() const { return const_iterator(head); }
iterator end() { return iterator(end_ptr); }
const_iterator cend() const { return const_iterator(end_ptr); }
T& operator[](unsigned const int &index) const
{
if(index > (m_size-1)/2)
{
return scroll_node(-(m_size-1-index),end_ptr->left)->value;
}
else
{
return scroll_node(index,head)->value;
}
}
void operator=(const QEList &QEL)
{
this->clear();
auto iter = QEL.cbegin();
for(;iter != QEL.cend();iter++)
{
this->push_back(*iter);
}
}
size_t size() const { return m_size; }
private:
size_t m_size = 0;
Node *end_ptr = new Node(nullptr,nullptr);
Node *head = end_ptr;
Node* scroll_node(int index,Node* node_ptr) const //moves node_ptr to index forward(if index is negative ,then moves it back)
{
if(index > 0)
for(int i = 0; i < index;i++)
{
node_ptr = node_ptr->right;
}
else
{
index = abs(index);
for(int i = 0; i < index;i++)
{
node_ptr = node_ptr->left;
}
}
return node_ptr;
}
};
#include <iostream>
template<typename S>
QEList<S> qsort(const QEList<S> &lis)
{
srand(time(NULL));
if(lis.size() <= 1)
{
return lis;
}
QEList<S> min;
QEList<S> max;
QEList<S> elems;
S elem = lis[rand()%lis.size()];
auto iter = lis.cbegin();
for(;iter != lis.cend();iter++)
{
if(*iter > elem)
{
max.push_back(*iter);
}
else if(*iter < elem)
{
min.push_back(*iter);
}
else
{
elems.push_back(elem);
}
}
min = qsort(min);
iter = elems.cbegin();
for(;iter != elems.cend();iter++)
{
min.push_back(*iter);
}
max = qsort(max);
iter = max.cbegin();
for(;iter != max.cend();iter++)
{
min.push_back(*iter);
}
return min;
}
template<typename S>
QEList<S> selection_sort(QEList<S> lis)
{
QEList<int> lis2;
while(lis.size()>0)
{
auto largestIter = lis.begin();
auto iter = largestIter;
for(;iter != lis.end();iter++)
if(*iter > *largestIter)
largestIter = iter;
lis2.push_front(*largestIter);
lis.erase(largestIter);
}
return lis2;
}
int main()
{
QEList<int> lis(2345,342,5,3425,2,34,32,4,32,43,24,2,34);
QEList<int> lis2 = qsort(lis);
std::cout << "size lis: " << lis.size() << std::endl;//print size lis: 13
std::cout << "size lis2: " << lis2.size() << std::endl;//print size lis2: 13
for(int i = 0; i < lis2.size() ; i++)
std::cout << lis2[i] << std::endl;
/*
print:
2
4
5
24
32
32
34
34
43
342
2345
3425
*/
QEList<int> lis3(selection_sort(QEList<int>(1,23,4,54,54,6543,56,3546,23452,51,65,4)));
std::cout << "size lis3: " << lis3.size() << std::endl; //print 12
for(int i = 0; i < lis3.size() ; i++)
std::cout << lis2[i] << std::endl;
/*
print:
2
2
4
5
24
32
32
34
34
43
342
2345
*/
std::cout << clock()/static_cast<double>(CLOCKS_PER_SEC) << std::endl;
return 0;
}