460 lines
11 KiB
C++
460 lines
11 KiB
C++
/*
|
|
The MIT License
|
|
|
|
Copyright (c) 2016 Thomas Sarlandie thomas@sarlandie.net
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
A big thanks to NorthWestern University ~riesbeck on implementing iterators.
|
|
Could not have done it without you!
|
|
http://www.cs.northwestern.edu/~riesbeck/programming/c++/stl-iterator-define.html
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
//#define _USE_STD_LIST_FOR_LINKED_LIST_
|
|
|
|
#ifdef _USE_STD_LIST_FOR_LINKED_LIST_
|
|
#include <list>
|
|
|
|
template <class T> using LinkedList = std::list<T>;
|
|
#else
|
|
|
|
template <class T> class LinkedListIterator;
|
|
template <class T> class LinkedListConstIterator;
|
|
template <class T> class LinkedListCircularIterator;
|
|
|
|
template <class T> class LinkedList {
|
|
private:
|
|
class node {
|
|
public:
|
|
T value;
|
|
node *next;
|
|
|
|
node(const T &v) : value(v), next(0) {};
|
|
};
|
|
|
|
node *head;
|
|
|
|
friend class LinkedListIterator<T>;
|
|
friend class LinkedListConstIterator<T>;
|
|
friend class LinkedListCircularIterator<T>;
|
|
|
|
public:
|
|
typedef LinkedListIterator<T> iterator;
|
|
typedef LinkedListConstIterator<T> const_iterator;
|
|
using constIterator=const_iterator;
|
|
typedef LinkedListCircularIterator<T> circularIterator;
|
|
|
|
LinkedList() : head(0) {};
|
|
|
|
LinkedList(const LinkedList &l) : head(0) {
|
|
for (constIterator it = l.begin(); it != l.end(); it++) {
|
|
add(*it);
|
|
}
|
|
};
|
|
|
|
~LinkedList() {
|
|
clear();
|
|
};
|
|
|
|
LinkedList<T>& operator=(const LinkedList<T> &l) {
|
|
clear();
|
|
for (constIterator it = l.begin(); it != l.end(); it++) {
|
|
add(*it);
|
|
}
|
|
return *this;
|
|
};
|
|
|
|
void push_back(const T &v) {
|
|
if (head == 0) {
|
|
head = new node(v);
|
|
}
|
|
else {
|
|
node *n = head;
|
|
while (n->next != 0) {
|
|
n = n->next;
|
|
}
|
|
n->next = new node(v);
|
|
}
|
|
};
|
|
|
|
inline void add(const T &v) { push_back(v); }
|
|
|
|
iterator insert(iterator pos, const T& v) {
|
|
if ( head==0 || pos._current==head ) {
|
|
head=new node(v);
|
|
head->next=pos._current;
|
|
pos._current=head;
|
|
} else {
|
|
node *n;
|
|
for ( n=head;n->next!=pos._current; n=n->next );
|
|
n->next=new node(v);
|
|
n->next->next=pos._current;
|
|
pos._current=n->next;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
T& front() {
|
|
return head->value;
|
|
}
|
|
|
|
T& back() {
|
|
node *n = head;
|
|
while ( n!=0 && n->next!=0 ) {
|
|
n=n->next;
|
|
}
|
|
return n->value;
|
|
}
|
|
|
|
void remove(const T &v) {
|
|
node *n = head;
|
|
// remove from beginning
|
|
while ( n!=0 && n->value==v ) {
|
|
head=n->next;
|
|
delete(n);
|
|
n=head;
|
|
}
|
|
|
|
while ( n!=0 ) {
|
|
node *del=n->next;
|
|
if ( del!=0 && del->value==v ) {
|
|
n->next=del->next;
|
|
delete(del);
|
|
}
|
|
n=n->next;
|
|
}
|
|
}
|
|
|
|
void clear() {
|
|
node *n = head;
|
|
while (n != 0) {
|
|
node *next = n->next;
|
|
delete(n);
|
|
n = next;
|
|
}
|
|
head = 0;
|
|
};
|
|
|
|
iterator erase(LinkedListIterator<T> l) {
|
|
if ( l==end() ) return l;
|
|
node *dn = l._current;
|
|
l++;
|
|
if ( dn==head ) {
|
|
head=dn->next;
|
|
} else {
|
|
node *n=head;
|
|
for ( ;n->next!=dn;n=n->next );
|
|
n->next=dn->next;
|
|
}
|
|
delete dn;
|
|
return l;
|
|
}
|
|
|
|
void removeFirst() {
|
|
node *n = head;
|
|
if (head) {
|
|
head = head->next;
|
|
delete(n);
|
|
}
|
|
};
|
|
|
|
iterator begin() {
|
|
return iterator(head);
|
|
};
|
|
|
|
constIterator begin() const {
|
|
return constIterator(head);
|
|
};
|
|
|
|
iterator end() {
|
|
return iterator(0);
|
|
};
|
|
|
|
constIterator end() const {
|
|
return constIterator(0);
|
|
};
|
|
|
|
circularIterator circularBegin() {
|
|
return circularIterator(head);
|
|
};
|
|
|
|
circularIterator circularEnd() {
|
|
return circularIterator(0);
|
|
};
|
|
|
|
int size() const {
|
|
LinkedList<T>::node *n = head;
|
|
int sz = 0;
|
|
while (n != 0) {
|
|
n = n->next;
|
|
sz++;
|
|
}
|
|
return sz;
|
|
};
|
|
|
|
bool operator==(const LinkedList<T> &l) const {
|
|
auto it=begin();
|
|
auto oit=l.begin();
|
|
for (;it!=end() && oit!=l.end() && (*it)==(*oit); it++, oit++);
|
|
return ( (*it)==(*oit) );
|
|
};
|
|
|
|
bool operator!=(const LinkedList<T> &l) const {
|
|
return !(*this==l);
|
|
};
|
|
|
|
template< class Compare >
|
|
void sort( Compare comp ) {
|
|
if ( head==0 || head->next==0 ) return; // Empty list or 1 element list
|
|
bool sortDone;
|
|
do {
|
|
sortDone=true;
|
|
node *pa=head;
|
|
node *a=head;
|
|
node *b=a->next;
|
|
while ( b!=0 ) {
|
|
if ( !(*comp)(b->value,a->value) ) {
|
|
pa=a;
|
|
} else { // sort required
|
|
sortDone=false;
|
|
a->next=b->next;
|
|
b->next=a;
|
|
if ( a==head ) {
|
|
head=b;
|
|
} else {
|
|
pa->next=b;
|
|
}
|
|
}
|
|
a=pa->next;
|
|
b=a->next;
|
|
}
|
|
|
|
} while ( !sortDone );
|
|
}
|
|
protected:
|
|
template<class L> friend void MoveListItemForward(LinkedList<L> &list, const L &v);
|
|
template<class L> friend void MoveListItemBack(LinkedList<L> &list, const L &v);
|
|
void moveBack(const T &v) {
|
|
node *n = head;
|
|
|
|
if ( n==0 || n->value==v ) return; // can not move
|
|
|
|
node *p=n;
|
|
n=n->next;
|
|
if ( n!=0 && n->value==v ) { // move second
|
|
head->next=n->next;
|
|
head=n;
|
|
n->next=p;
|
|
}
|
|
|
|
node *pp=p;
|
|
for (p=n,n=n->next;n!=0 && n->value!=v; pp=p, p=n, n=n->next );
|
|
if ( n==0 ) return;
|
|
|
|
p->next=n->next;
|
|
pp->next=n;
|
|
n->next=p;
|
|
}
|
|
|
|
void moveForward(const T &v) {
|
|
node *n = head;
|
|
|
|
if ( n==0 || n->next==0 ) return; // can not move, only one value
|
|
|
|
node *p=n;
|
|
n=n->next;
|
|
if ( p->value==v ) { // move first
|
|
head=n;
|
|
p->next=n->next;
|
|
n->next=p;
|
|
}
|
|
|
|
node *pp=p;
|
|
for (p=n,n=n->next;n!=0 && p->value!=v; pp=p, p=n, n=n->next );
|
|
if ( n==0 ) return;
|
|
pp->next=n;
|
|
p->next=n->next;
|
|
n->next=p;
|
|
}
|
|
};
|
|
|
|
template <class T> class LinkedListIterator {
|
|
friend class LinkedList<T>;
|
|
protected:
|
|
typename LinkedList<T>::node *_current;
|
|
|
|
public:
|
|
LinkedListIterator(typename LinkedList<T>::node *node=0) : _current(node) {};
|
|
|
|
LinkedListIterator<T>& operator=(const LinkedListIterator<T> &l) {
|
|
_current = l._current;
|
|
return *this;
|
|
};
|
|
|
|
LinkedListIterator<T>& operator=(const LinkedListConstIterator<T> &l) {
|
|
_current = l._current;
|
|
return *this;
|
|
};
|
|
|
|
bool operator==(LinkedListIterator<T> l) {
|
|
return l._current == _current;
|
|
}
|
|
|
|
bool operator!=(LinkedListIterator<T> l) {
|
|
return l._current != _current;
|
|
}
|
|
|
|
LinkedListIterator<T> & operator++() {
|
|
if ( _current!=0) _current = _current->next;
|
|
return *this;
|
|
}
|
|
|
|
// Postfix operator takes an argument (that we do not use)
|
|
LinkedListIterator<T> operator++(int) {
|
|
LinkedListIterator<T> clone(*this);
|
|
++(*this);
|
|
return clone;
|
|
}
|
|
|
|
T & operator*() {
|
|
return _current->value;
|
|
}
|
|
|
|
T * operator->() {
|
|
return &(operator*());
|
|
}
|
|
};
|
|
|
|
template <class T> class LinkedListConstIterator {
|
|
protected:
|
|
friend class LinkedListIterator<T>;
|
|
typename LinkedList<T>::node const *_current;
|
|
|
|
public:
|
|
LinkedListConstIterator(typename LinkedList<T>::node const *node) : _current(node) {};
|
|
|
|
bool operator==(LinkedListConstIterator<T> l) {
|
|
return l._current == _current;
|
|
}
|
|
|
|
bool operator!=(LinkedListConstIterator<T> l) {
|
|
return l._current != _current;
|
|
}
|
|
|
|
LinkedListConstIterator<T> & operator++() {
|
|
if ( _current!=0) _current = _current->next;
|
|
return *this;
|
|
}
|
|
|
|
// Postfix operator takes an argument (that we do not use)
|
|
LinkedListConstIterator<T> operator++(int) {
|
|
LinkedListConstIterator<T> clone(*this);
|
|
_current = _current->next;
|
|
return clone;
|
|
}
|
|
|
|
const T & operator*() {
|
|
return _current->value;
|
|
}
|
|
};
|
|
|
|
template <class T> class LinkedListCircularIterator : public LinkedListIterator<T> {
|
|
protected:
|
|
typename LinkedList<T>::node *_head;
|
|
|
|
public:
|
|
LinkedListCircularIterator(typename LinkedList<T>::node *head) : LinkedListIterator<T>(head), _head(head) {};
|
|
|
|
LinkedListCircularIterator<T> & operator++() {
|
|
if (this->_current->next) {
|
|
this->_current = this->_current->next;
|
|
}
|
|
else {
|
|
this->_current = this->_head;
|
|
}
|
|
return *this;
|
|
};
|
|
|
|
LinkedListIterator<T> operator++(int) {
|
|
LinkedListIterator<T> clone(*this);
|
|
++(*this);
|
|
return clone;
|
|
};
|
|
};
|
|
|
|
#ifdef DEBUG_TEST_LINKED_LIST
|
|
LinkedList<double> DoubleList;
|
|
|
|
void PrintTestList() {
|
|
for (auto it=DoubleList.begin(); it!=DoubleList.end(); it++) {
|
|
Serial.println((*it));
|
|
}
|
|
}
|
|
void TestList() {
|
|
DoubleList.add(5);
|
|
DoubleList.add(6);
|
|
DoubleList.add(9);
|
|
PrintTestList();
|
|
DoubleList.remove(6);
|
|
PrintTestList();
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
template <class T>
|
|
void MoveListItemForward(LinkedList<T> &list, const T &v) {
|
|
#ifdef _USE_STD_LIST_FOR_LINKED_LIST_
|
|
auto it=list.begin();
|
|
if ( it==list.end() ) return; // Empty list
|
|
|
|
for ( ;it!=list.end() && (*it)!=v; it++);
|
|
if ( it==list.end() ) return; // not found
|
|
auto itn=it;
|
|
itn++;
|
|
if ( itn==list.end() ) return; // v is last value
|
|
itn++;
|
|
list.erase(it);
|
|
list.insert(itn,v);
|
|
#else
|
|
list.moveForward(v);
|
|
#endif
|
|
}
|
|
|
|
template <class T>
|
|
void MoveListItemBack(LinkedList<T> &list, const T &v) {
|
|
#ifdef _USE_STD_LIST_FOR_LINKED_LIST_
|
|
auto it=list.begin();
|
|
if ( it==list.end() ) return; // Empty list
|
|
if ( (*it)==v ) return; // v at begin
|
|
|
|
auto itp=it;
|
|
it++;
|
|
for ( ;it!=list.end() && (*it)!=v; itp=it, it++);
|
|
if ( it==list.end() ) return; // not found
|
|
list.erase(it);
|
|
list.insert(itp,v);
|
|
#else
|
|
list.moveBack(v);
|
|
#endif
|
|
}
|