[C++11][数据结构]自己的双链表实现

这个双链表,是我模仿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运行正常。如果发现写的不对的地方,还请回复一下。

以下是类的实现:

  1 #pragma once
  2 
  3 #include <cstddef>
  4 #include <stdexcept>
  5 
  6 namespace jt {
  7 
  8 template <class value_t>
  9 class list {
 10   friend class list<value_t>;
 11 
 12 private:
 13   struct node {
 14     value_t val;
 15     node *next, *prev;
 16   } *_head = nullptr,
 17     *_tail = nullptr;
 18 
 19   size_t _siz;
 20 
 21   enum { endpointer = 1 };
 22 
 23 public:
 24   class iterator {
 25     friend class iterator;
 26     friend class list<value_t>;
 27 
 28   public:
 29     iterator(node *nn = nullptr) { _init(nn); }
 30     iterator(const iterator &i)  { _init(i.n); }
 31 
 32     value_t& operator*() const { return n->val; }
 33     value_t* operator->() const { return &(operator*()); }
 34     iterator operator++() { _inc(); return *this; }
 35     iterator operator++(int) { iterator tmp = *this; _inc(); return tmp; }
 36     iterator operator--() { _dec(); return *this; }
 37     iterator operator--(int) { iterator tmp = *this; _dec(); return tmp; }
 38     bool operator==(iterator& i) const { return i.n == n; }
 39     bool operator!=(iterator& i) const { return i.n != n; }
 40 
 41   private:
 42     node *n;
 43 
 44     void _init(node *nn) {
 45       if (nn) {
 46         n = nn;
 47       } else {
 48         n = (node*)endpointer;
 49       }
 50     }
 51 
 52     void _inc() { n = (n->next) ? n->next : (node*)endpointer; } // increment
 53     void _dec() { n = (n->prev) ? n->prev : (node*)endpointer; } // decrement
 54   };
 55 
 56   list() { clear(); }
 57   list(const list<value_t> &l) { if (&l != this) _init(l.begin(), l.end()); }
 58   ~list() { clear(); }
 59 
 60   bool empty() const { return !_head; }
 61 
 62   void clear() {
 63     if (!empty()) {
 64       node *tmp;
 65       for (node *n = _head; n; n = tmp) {
 66         tmp = n->next;
 67         delete n;
 68       }
 69 
 70       _head = nullptr;
 71       _tail = nullptr;
 72       _siz = 0;
 73     }
 74   }
 75 
 76   void insert(const iterator &pos, const value_t &val) {
 77     if (pos.n == _head) {
 78       push_front(val);
 79     } else {
 80       node *n = new node;
 81       n->val = val;
 82       n->next = pos.n;
 83       n->prev = pos.n->prev;
 84 
 85       pos.n->prev->next = pos.n->prev = n;
 86       ++_siz;
 87     }
 88   }
 89 
 90   void erase(const iterator &pos) {
 91     if (pos.n == _head) {
 92       pop_front();
 93     } else if (pos.n == _tail) {
 94       pop_back();
 95     } else {
 96       pos.n->prev->next = pos.n->next;
 97       pos.n->next->prev = pos.n->prev;
 98       delete pos.n;
 99       --_siz;
100     }
101   }
102 
103   iterator head() const { return iterator(_head); }
104   iterator tail() const { return iterator(_tail); }
105 
106   iterator begin() const { return iterator(_head); }
107   iterator end() const { return iterator((node*)endpointer); }
108 
109   void push_front(const value_t &val) {
110     node *n = new node;
111     n->val = val;
112     n->next = _head;
113     n->prev = nullptr;
114 
115     if (empty()) _tail = n;
116     else _head->prev = n;
117     _head = n;
118 
119     ++_siz;
120   }
121 
122   void push_back(const value_t &val) {
123     node *n = new node;
124     n->val = val;
125     n->next = nullptr;
126     n->prev = _tail;
127 
128     if (empty()) _head = n;
129     else _tail->next = n;
130     _tail = n;
131 
132     ++_siz;
133   }
134 
135   void pop_front() {
136     if (_siz == 0) {
137       throw std::logic_error("Empty List");
138     } else if (_siz == 1) {
139       clear();
140     } else {
141       node *tmp = _head->next;
142       delete _head;
143       _head = tmp;
144       _head->prev = nullptr;
145     }
146 
147     --_siz;
148   }
149 
150   void pop_back() {
151     if (_siz == 0) {
152       throw std::logic_error("Empty List");
153     } else if (_siz == 1) {
154       clear();
155     } else {
156       node *tmp = _tail->prev;
157       delete _tail;
158       _tail = tmp;
159       _tail->next = nullptr;
160     }
161 
162     --_siz;
163   }
164 
165   value_t front() const { return *head(); }
166   value_t back()  const { return *tail(); }
167 
168   size_t size() const { return _siz; }
169 
170 private:
171   template <class iter>
172   void _init(iter head, iter tail) {
173     clear();
174 
175     // copy
176     if (head && tail) {
177       for (; head != tail; ++head) {
178         push_back(*head);
179       }
180       push_back(*tail);
181     }
182   }
183 };
184 
185 }

我没有做测试,而是直接做了一个demo。

这个demo是一个正整数的统计计算器。可以插入,删除,求和,求平均数,等等。

以下是demo的代码,同样是C++11:

 1 #include "list.h"
 2 #include <iostream>
 3 #include <string>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <numeric>
 7 #include <algorithm>
 8 #include <map>
 9 #include <functional>
10 
11 int main() {
12   jt::list<unsigned> cont;
13   std::string buf;
14   std::string helpmsg =
15     "h for HELP\n"
16     "s for SUM\n"
17     "a for AVERAGE\n"
18     "z for SIZE\n"
19     "i,n,p for INSERT n AT p\n"
20     "e,n for ERASE AT p\n"
21     "p,n for PUSH_BACK n\n"
22     "q for QUIT";
23 
24   int n = -1;
25   int p = -1;
26 
27   // create func
28   std::map<char, std::function<void()>> func;
29   func['h'] = [&]() { std::cout << helpmsg << std::endl; };
30   func['s'] = [&]() { std::cout << "sum: " << std::accumulate(cont.begin(), cont.end(), 0) << std::endl; };
31   func['a'] = [&]() { std::cout << "average: " << double(std::accumulate(cont.begin(), cont.end(), 0)) / cont.size() << std::endl; };
32   func['z'] = [&]() { std::cout << "size: " << cont.size() << std::endl; };
33   func['i'] = [&]() {
34     auto i = cont.begin();
35     while (--p) ++i;
36     cont.insert(i, n);
37   };
38   func['e'] = [&]() {
39     auto i = cont.begin();
40     while (--n) { ++i; }
41     cont.erase(i);
42   };
43   func['p'] = [&]() { cont.push_back(n); };
44   func['q'] = [](){};
45 
46   char *optargs = "hsaziepq";
47 
48   while (buf != "q") {
49     // display
50     std::cout << "\n[ ";
51     std::for_each(cont.head(), cont.end(), [&](const unsigned &n) { std::cout << n << " "; });
52     std::cout << "]" << std::endl;
53 
54     // read in args
55     std::cout << optargs << "> ";
56     std::cin >> buf;
57 
58     if (!strchr(optargs, buf[0])) {
59       std::cout << "Wrong Argument" << std::endl;
60     } else {
61       sscanf(buf.c_str(), "%*c,%d,%d", &n, &p);
62       func[buf[0]]();
63     }
64   }
65 
66   return 0;
67 }

下面我使用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: 0

[ ]
hsaziepq> z
size: 0

[ ]
hsaziepq> p,1

[ 1 ]
hsaziepq> p,5

[ 1 5 ]
hsaziepq> p,9

[ 1 5 9 ]
hsaziepq> a
average: 5

[ 1 5 9 ]
hsaziepq> s
sum: 15

[ 1 5 9 ]
hsaziepq> z
size: 3

[ 1 5 9 ]
hsaziepq> i,2,3

[ 1 5 2 9 ]
hsaziepq> e,3

[ 1 5 9 ]
hsaziepq> i,3,2

[ 1 3 5 9 ]
hsaziepq> i,2,2

[ 1 2 3 5 9 ]
hsaziepq> i,4,4

[ 1 2 3 4 5 9 ]
hsaziepq> e,6

[ 1 2 3 4 5 ]
hsaziepq> s
sum: 15

[ 1 2 3 4 5 ]
hsaziepq> a
average: 3

[ 1 2 3 4 5 ]
hsaziepq> z
size: 5

[ 1 2 3 4 5 ]
hsaziepq> q
原文地址:https://www.cnblogs.com/jt2001/p/cpplist20150819.html