Created
December 12, 2014 03:15
-
-
Save dgodfrey206/869e029f5b2ceedd168e to your computer and use it in GitHub Desktop.
Doubly linked list
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <initializer_list> | |
#include <stdexcept> | |
template <class T> | |
class list; | |
template <class T> | |
class Node | |
{ | |
Node(T const& data, Node* next = nullptr, Node* prev = nullptr) | |
: data(data) | |
, next(next) | |
, prev(prev) | |
{ } | |
friend class list<T>; | |
private: | |
T data{0}; | |
Node* next{0}, *prev{0}; | |
}; | |
template <class T> | |
class list | |
{ | |
typedef T& reference; | |
typedef T const& const_reference; | |
typedef unsigned int size_type; | |
template <class U> | |
using ref_ptr = U*&; | |
public: | |
list(); | |
list(std::initializer_list<T>); | |
list(list const&); | |
list& operator=(list const&); | |
void assign(list const&); | |
reference operator[](size_type); | |
const_reference operator[](size_type) const; | |
reference front(); | |
const_reference front() const; | |
reference back(); | |
const_reference back() const; | |
bool empty() const; | |
size_type size() const; | |
size_type max_size() const; | |
void push_back(T const&); | |
void pop_back(); | |
void push_front(T const&); | |
void pop_front(); | |
void clear(); | |
void swap(list<T>&); | |
private: | |
Node<T>* head; | |
Node<T>* tail; | |
mutable size_type m_size{0}; | |
private: | |
void delete_node(Node<T>**); | |
void internal_swap(ref_ptr<Node<T>>, ref_ptr<Node<T>>); | |
void dec_size() const { if (m_size) --m_size; } | |
void inc_size() const { ++m_size; } | |
}; | |
template <class T> | |
list<T>::list() | |
: head{0}, tail{0} | |
{ } | |
template <class T> | |
list<T>::list(std::initializer_list<T> l) | |
: head{0} | |
, tail{0} | |
{ | |
for (auto const& x : l) | |
push_back(x); | |
} | |
template <class T> | |
list<T>::list(list<T> const& other) { assign(other); } | |
template <class T> | |
void list<T>::push_back(T const& value) | |
{ | |
Node<T>* node = new Node<T>{value}; | |
if (head == nullptr) | |
head = node; | |
else | |
tail->next = node; | |
tail = node; | |
inc_size(); | |
} | |
template <class T> | |
void list<T>::push_front(T const& value) | |
{ | |
head = new Node<T>{value, head}; | |
inc_size(); | |
} | |
template <class T> | |
void list<T>::pop_front() | |
{ | |
Node<T>* temp = head; | |
head = head->next; | |
delete temp; | |
dec_size(); | |
} | |
template <class T> | |
void list<T>::pop_back() | |
{ | |
Node<T>* oldTail = tail; | |
tail = tail->prev; | |
delete oldTail; | |
dec_size(); | |
} | |
template <class T> | |
void list<T>::assign(list<T> const& other) | |
{ | |
head = 0; | |
tail = 0; | |
for (auto first = other.head; first != nullptr; first = first->next) | |
push_back(first->data); | |
} | |
template <class T> | |
auto list<T>::operator[](size_type pos) -> reference | |
{ | |
if (pos >= m_size) | |
throw std::out_of_range("Position out of range."); | |
Node<T>* ptr = head; | |
size_type count = 0; | |
while (ptr && count != pos) | |
{ | |
ptr = ptr->next; | |
count++; | |
} | |
return ptr->data; | |
} | |
template <class T> | |
auto list<T>::operator[](size_type pos) const -> const_reference | |
{ | |
return const_cast<list<T>&>(*this)[pos]; | |
} | |
template <class T> | |
list<T>& list<T>::operator=(list<T> const& other) | |
{ | |
assign(other); | |
return *this; | |
} | |
template <class T> auto list<T>::front() -> reference { return head->data; } | |
template <class T> auto list<T>::front() const -> const_reference { return head->data; } | |
template <class T> auto list<T>::back() -> reference { return tail->data; } | |
template <class T> auto list<T>::back() const -> const_reference { return tail->data; } | |
template <class T> | |
bool list<T>::empty() const { return head != nullptr; } | |
template <class T> | |
auto list<T>::size() const -> size_type | |
{ return m_size; } | |
template <class T> | |
void list<T>::clear() | |
{ | |
for (; head != nullptr; head = head->next) | |
delete_node(&head); | |
} | |
template <class T> | |
void list<T>::swap(list<T>& other) | |
{ | |
internal_swap(head, other.head); | |
std::swap(m_size, other.m_size); | |
} | |
template <class T> | |
void list<T>::internal_swap(ref_ptr<Node<T>> lhs, ref_ptr<Node<T>> rhs) | |
{ | |
using std::swap; | |
swap(lhs, rhs); | |
Node<T> **lnext = &lhs, **rnext = &rhs; | |
if (lhs) lnext = &lhs->next; | |
if (rhs) rnext = &rhs->next; | |
if (*lnext || *rnext) | |
internal_swap(*lnext, *rnext); | |
} | |
template <class T> | |
void list<T>::delete_node(Node<T>** node) | |
{ | |
Node<T> **prev = &(*node)->prev, **next = &(*node)->next; | |
delete *node; | |
*prev = *next; | |
dec_size(); | |
} | |
int main() | |
{ | |
list<int> l{1, 2, 3, 4}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment