这个双链表,是我模仿stl的list制作的,只实现了一些基本功能,像merge,transfer这些就没有实现,用户可以用基本操作来自己做外部实现。
我没有选用stl的[begin,end)迭代器模式,而是使用传统的[head,tail]。不过,为了配合stl算法,我还是加了两个begin(),end()方法,模拟了一下stl容器。模拟的还算及格,至少我可以做类似for (; begin != end; ++begin)这样的事,也可以让我的容器搭配一些stl算法,这在之后的demo里可以看到。不过,我的iterator很朴素,所以不能用于std::sort。
至于模拟的实现,我的方法是让所有越界的迭代器都指向一个预先设定好的内存地址。然后用户调用end()方法的时候,就返回指向这个内存地址的迭代器。这样,当我的迭代器越界的时候,就和end()指向的内存地址一样了。
代码采用C++11实现,在Win7 Mingw32 Gcc4.7的环境下,demo运行正常。如果发现写的不对的地方,还请回复一下。
以下是类的实现:
#pragma once #include <cstddef>
#include <stdexcept> namespace jt { template <class value_t>
class list {
friend class list<value_t>; private:
struct node {
value_t val;
node *next, *prev;
} *_head = nullptr,
*_tail = nullptr; size_t _siz; enum { endpointer = }; public:
class iterator {
friend class iterator;
friend class list<value_t>; public:
iterator(node *nn = nullptr) { _init(nn); }
iterator(const iterator &i) { _init(i.n); } value_t& operator*() const { return n->val; }
value_t* operator->() const { return &(operator*()); }
iterator operator++() { _inc(); return *this; }
iterator operator++(int) { iterator tmp = *this; _inc(); return tmp; }
iterator operator--() { _dec(); return *this; }
iterator operator--(int) { iterator tmp = *this; _dec(); return tmp; }
bool operator==(iterator& i) const { return i.n == n; }
bool operator!=(iterator& i) const { return i.n != n; } private:
node *n; void _init(node *nn) {
if (nn) {
n = nn;
} else {
n = (node*)endpointer;
}
} void _inc() { n = (n->next) ? n->next : (node*)endpointer; } // increment
void _dec() { n = (n->prev) ? n->prev : (node*)endpointer; } // decrement
}; list() { clear(); }
list(const list<value_t> &l) { if (&l != this) _init(l.begin(), l.end()); }
~list() { clear(); } bool empty() const { return !_head; } void clear() {
if (!empty()) {
node *tmp;
for (node *n = _head; n; n = tmp) {
tmp = n->next;
delete n;
} _head = nullptr;
_tail = nullptr;
_siz = ;
}
} void insert(const iterator &pos, const value_t &val) {
if (pos.n == _head) {
push_front(val);
} else {
node *n = new node;
n->val = val;
n->next = pos.n;
n->prev = pos.n->prev; pos.n->prev->next = pos.n->prev = n;
++_siz;
}
} void erase(const iterator &pos) {
if (pos.n == _head) {
pop_front();
} else if (pos.n == _tail) {
pop_back();
} else {
pos.n->prev->next = pos.n->next;
pos.n->next->prev = pos.n->prev;
delete pos.n;
--_siz;
}
} iterator head() const { return iterator(_head); }
iterator tail() const { return iterator(_tail); } iterator begin() const { return iterator(_head); }
iterator end() const { return iterator((node*)endpointer); } void push_front(const value_t &val) {
node *n = new node;
n->val = val;
n->next = _head;
n->prev = nullptr; if (empty()) _tail = n;
else _head->prev = n;
_head = n; ++_siz;
} void push_back(const value_t &val) {
node *n = new node;
n->val = val;
n->next = nullptr;
n->prev = _tail; if (empty()) _head = n;
else _tail->next = n;
_tail = n; ++_siz;
} void pop_front() {
if (_siz == ) {
throw std::logic_error("Empty List");
} else if (_siz == ) {
clear();
} else {
node *tmp = _head->next;
delete _head;
_head = tmp;
_head->prev = nullptr;
} --_siz;
} void pop_back() {
if (_siz == ) {
throw std::logic_error("Empty List");
} else if (_siz == ) {
clear();
} else {
node *tmp = _tail->prev;
delete _tail;
_tail = tmp;
_tail->next = nullptr;
} --_siz;
} value_t front() const { return *head(); }
value_t back() const { return *tail(); } size_t size() const { return _siz; } private:
template <class iter>
void _init(iter head, iter tail) {
clear(); // copy
if (head && tail) {
for (; head != tail; ++head) {
push_back(*head);
}
push_back(*tail);
}
}
}; }
我没有做测试,而是直接做了一个demo。
这个demo是一个正整数的统计计算器。可以插入,删除,求和,求平均数,等等。
以下是demo的代码,同样是C++11:
#include "list.h"
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <numeric>
#include <algorithm>
#include <map>
#include <functional> int main() {
jt::list<unsigned> cont;
std::string buf;
std::string helpmsg =
"h for HELP\n"
"s for SUM\n"
"a for AVERAGE\n"
"z for SIZE\n"
"i,n,p for INSERT n AT p\n"
"e,n for ERASE AT p\n"
"p,n for PUSH_BACK n\n"
"q for QUIT"; int n = -;
int p = -; // create func
std::map<char, std::function<void()>> func;
func['h'] = [&]() { std::cout << helpmsg << std::endl; };
func['s'] = [&]() { std::cout << "sum: " << std::accumulate(cont.begin(), cont.end(), ) << std::endl; };
func['a'] = [&]() { std::cout << "average: " << double(std::accumulate(cont.begin(), cont.end(), )) / cont.size() << std::endl; };
func['z'] = [&]() { std::cout << "size: " << cont.size() << std::endl; };
func['i'] = [&]() {
auto i = cont.begin();
while (--p) ++i;
cont.insert(i, n);
};
func['e'] = [&]() {
auto i = cont.begin();
while (--n) { ++i; }
cont.erase(i);
};
func['p'] = [&]() { cont.push_back(n); };
func['q'] = [](){}; char *optargs = "hsaziepq"; while (buf != "q") {
// display
std::cout << "\n[ ";
std::for_each(cont.head(), cont.end(), [&](const unsigned &n) { std::cout << n << " "; });
std::cout << "]" << std::endl; // read in args
std::cout << optargs << "> ";
std::cin >> buf; if (!strchr(optargs, buf[])) {
std::cout << "Wrong Argument" << std::endl;
} else {
sscanf(buf.c_str(), "%*c,%d,%d", &n, &p);
func[buf[]]();
}
} return ;
}
下面我使用demo的记录,看了可能会比较好理解代码一点:
[ ]
hsaziepq> h
h for HELP
s for SUM
a for AVERAGE
z for SIZE
i,n,p for INSERT n AT p
e,n for ERASE AT p
p,n for PUSH_BACK n
q for QUIT [ ]
hsaziepq> s
sum: [ ]
hsaziepq> z
size: [ ]
hsaziepq> p, [ ]
hsaziepq> p, [ ]
hsaziepq> p, [ ]
hsaziepq> a
average: [ ]
hsaziepq> s
sum: [ ]
hsaziepq> z
size: [ ]
hsaziepq> i,, [ ]
hsaziepq> e, [ ]
hsaziepq> i,, [ ]
hsaziepq> i,, [ ]
hsaziepq> i,, [ ]
hsaziepq> e, [ ]
hsaziepq> s
sum: [ ]
hsaziepq> a
average: [ ]
hsaziepq> z
size: [ ]
hsaziepq> q