[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
时间: 2024-10-11 10:23:53

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

数据结构学习之双链表基本操作

数据结构学习之双链表基本操作 0x1 前言 今天实验课,学习了下双链表的写法,这里记录下. 0x2 正文 题目要求如下: 本实验的双链链表元素的类型为char,完成如下实验要求: (1)初始化单链表h (2)采用尾插法依次插入a.b.c.d.e (3)输出单链表h (4)输出单链表h的长度 (5)判断单链表h是否为空 (6)输出单链表h的第3个元素 (7)输出元素a的逻辑位置 (8)在第4个元素位置上插入元素f (9)输出单链表h (10)删除单链表h的第3个元素 (11)输出单链表h (12)

【c++版数据结构】之双链表的实现(带头结点以及尾节点)

所实现的双链表的结构如下图所示: 双链表的实现,和第一篇文章单链表的实现大致相同点击打开链接 本篇文章在构建节点的同时,初始化构建节点的前驱和后继,具体细节参考下列代码 头文件:DList.h #ifndef DLIST_H_ #define DLIST_H_ typedef enum{FALSE,TRUE}Status; #include<iostream> #include<cassert> using namespace std; template<class Type

数据结构实践——循环双链表应用

本文针对数据结构基础系列网络课程(2):线性表的实践项目. [项目- 循环双链表应用] 设非空线性表ha和hb都用带头节点的循环双链表表示.设计一个算法Insert(ha,hb,i).其功能是:i=0时,将线性表hb插入到线性表ha的最前面:当i>0时,将线性表hb插入到线性表ha中第i个节点的后面:当i大于等于线性表ha的长度时,将线性表hb插入到线性表ha的最后面. 请在实现算法时,除项目中给出的特殊要求,其余工作均可利用项目4完成的算法支持. [参考解答](循环双链表的基本运算算法,请参考

java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制)

转载请注明出处(请尊重原创!谢谢~): http://blog.csdn.net/javazejian/article/details/53073995 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) ??这篇是数据结构与算法的第3篇,通过前两篇的介绍,对应顺序表和链表已有

java数据结构与算法之双链表设计与实现

转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/53047590 出自[zejian的博客] 关联文章: 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) ??上一篇文章分析顺序表和单链表,本篇就接着上篇继续聊链表,在单链表

【算法和数据结构】_13_小算法_双链表

没什么新的内容,把自己写的练习代码贴出来,供大家批判. 1 /* 2 本程序用来测试非线性存储结构:双链表 3 */ 4 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 9 10 //**************************************************0 11 // 定义双链表数据结构 12 struct dbllink 13 { 14 char data; 15 struct dbllink* preN

C# 数据结构 - 单链表 双链表 环形链表

链表特点(单链表 双链表) 优点:插入和删除非常快.因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作. 缺点:当需要查找某一个节点的时候就需要一个节点一个节点去访问,这样所花的时候就比较多了.(顺序表可以弥补这缺点,但插入和删除就非常耗性能) 单链表 单链表的构成:必须要有一个链表头(head),每个节点里面有一个Next用于指向下一个节点(类似于指针).最后一个节点的Next为null来标识链表的尾. 如下图 代码实现 1 /* ----

【数据结构】用C++实现双链表的各种操作(包括头删,尾删,插入,逆序,摧毁,清空等等)

//[数据结构]用C++实现双链表的各种操作(包括头删,尾删,插入,逆序,摧毁,清空等等) //头文件 #ifndef _LIST_H #define _LIST_H #include<iostream> using namespace std; template<class Type> class DList; template<class Type> class ListNode { friend class DList<Type>; public: L

redis源码分析(3)-- 基本数据结构双链表list

一.双链表结构 redis中实现的双链表结构体如下: 1 typedef struct list { 2 listNode *head; # 链表头 3 listNode *tail; # 链表尾 4 void *(*dup)(void *ptr); # 复制链表函数 5 void (*free)(void *ptr); # 释放节点函数 6 int (*match)(void *ptr, void *key); # 匹配函数 7 unsigned long len; # 链表节点个数 8 }