`
oldrev
  • 浏览: 234311 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
社区版块
存档分类
最新评论

双向链表模板类

阅读更多
参考 STL 实现的 Quick & Dirty 双向链表模板类,勉强看的过去。参考了 boost 的新概念迭代器,遵循D的命名风格,只实现了几个简单的成员函数。
迭代器使用 i.current属性或i()读取当前指向的元素,使用 i = x; 设置当前指向的元素

update:
添加了 ReverseIterator, rbegin, rend, insert, erase, popBack, popFront
D 的函数模板特化还是有问题(或者我不知道?)

D 代码
  1. // The STL-Like Template Class of Linked List
  2. // Author: Oldrev ( oldrev at gmail dot com)
  3. // License: BSD
  4. import std.stdio;
  5. // 越靠后的功能越多,后面的肯定包括前面的功能
  6. enum Traversal
  7. {
  8. // 支持的操作 ++i i++ *i++
  9. Incrementable,
  10. // ++i, a==b, a!=b
  11. SinglePass, //单遍,中途不能停
  12. // X u, ++i
  13. ForwardTraversal, //单向
  14. // --r, r--
  15. Bidirectional, //双向
  16. // r += n, a+n,n+a r-=n, a-n, b-a; a[n], a[n]=v, a
  17. RandomAccess //几乎就是数组
  18. }
  19. enum ValueAccess
  20. {
  21. Readable, // value = *a
  22. Writable, // *a = value
  23. Swappable, // swap(a, b)
  24. Lvalue
  25. // 返回引用? D没有显式引用,那就不支持吧
  26. }
  27. private void swap_(T)(inout T x, inout T y)
  28. {
  29. T t = x;
  30. x = y;
  31. y = t;
  32. }
  33. // 约定每个迭代器实现里需要有:
  34. // 一个 Traversal 型常量 TraversalCatalog 指示迭代器遍历方式类型
  35. // 一个 ValueAccess 型常量 ValueAccessCatalog 指示迭代器值访问类型
  36. // 这样算法可以通过 D 的 int 模板参数重载算法实现函数
  37. class List(EleType)
  38. {
  39. public alias EleType ValueType;
  40. public alias ValueType* PtrType;
  41. public alias List!(ValueType) SelfType;
  42. private struct Node
  43. {
  44. ValueType data;
  45. Node* prev;
  46. Node* next;
  47. static void join(Node* first, Node* second)
  48. {
  49. assert(first !is null);
  50. assert(second !is null);
  51. first.next = second;
  52. second.prev = first;
  53. }
  54. }
  55. // List 类的迭代器基模板
  56. private template IteratorBase(IterType)
  57. {
  58. public const Traversal TraversalCatalog = Traversal.Bidirectional;
  59. public const ValueAccess ValueAccessCatalog = ValueAccess.Swappable;
  60. private Node* m_node = null;
  61. private Node* node()
  62. {
  63. return m_node;
  64. }
  65. static IterType opCall(IterType i)
  66. {
  67. IterType ret;
  68. ret.m_node = i.m_node;
  69. return ret;
  70. }
  71. private static IterType opCall(Node* p)
  72. {
  73. IterType i;
  74. i.m_node = p;
  75. return i;
  76. }
  77. public ValueType opCall()
  78. {
  79. assert(m_node !is null);
  80. return m_node.data;
  81. }
  82. public PtrType ptr()
  83. {
  84. assert(m_node !is null);
  85. return &(m_node.data);
  86. }
  87. // 没办法,D 不能重载 *ptr
  88. public ValueType current()
  89. {
  90. assert(m_node !is null);
  91. return m_node.data;
  92. }
  93. public void current(ValueType v)
  94. {
  95. assert(m_node !is null);
  96. m_node.data = v;
  97. }
  98. void swap(inout IterType rhs)
  99. {
  100. IterType t = rhs;
  101. rhs = *this;
  102. *this = t;
  103. }
  104. IterType opPostInc() //i++
  105. {
  106. IterType i = *this;
  107. next();
  108. return i;
  109. }
  110. IterType opPostDec() // i--
  111. {
  112. IterType i = *this;
  113. back();
  114. return i;
  115. }
  116. bool opEquals(IterType rhs) // a == b
  117. {
  118. return rhs.m_node == this.m_node;
  119. }
  120. //D 不支持将=重载为两个同类型或可以隐式转换的类型之间的赋值
  121. ValueType opAssign(ValueType rhs) // *a = value
  122. {
  123. m_node.data = rhs;
  124. return m_node.data;
  125. }
  126. IterType opAddAssign(int n)
  127. {
  128. assert(n == 1);
  129. next();
  130. return *this;
  131. }
  132. IterType opSubAssign(int n)
  133. {
  134. assert(n == 1);
  135. back();
  136. return *this;
  137. }
  138. }
  139. public struct Iterator
  140. {
  141. mixin IteratorBase!(Iterator);
  142. public void next()
  143. {
  144. m_node = m_node.next;
  145. }
  146. public void back()
  147. {
  148. m_node = m_node.prev;
  149. }
  150. }
  151. public struct ReverseIterator
  152. {
  153. mixin IteratorBase!(ReverseIterator);
  154. public void next()
  155. {
  156. m_node = m_node.prev;
  157. }
  158. public void back()
  159. {
  160. m_node = m_node.next;
  161. }
  162. }
  163. //data members:
  164. private Node* m_head = null;
  165. private Node* m_tail = null;
  166. private uint m_length = 0;
  167. public this()
  168. {
  169. }
  170. public ~this()
  171. {
  172. clear();
  173. }
  174. public void clear()
  175. {
  176. if(empty)return;
  177. Iterator i = begin;
  178. while((i = erase(i)) != end){}
  179. m_head = null;
  180. m_tail = null;
  181. }
  182. public ValueType front()
  183. {
  184. assert(m_head !is null);
  185. return m_head.data;
  186. }
  187. public ValueType back()
  188. {
  189. assert(m_tail !is null);
  190. return m_tail.data;
  191. }
  192. public Iterator begin()
  193. {
  194. assert(!empty);
  195. return Iterator(m_head);
  196. }
  197. public Iterator end()
  198. {
  199. return Iterator(null);
  200. }
  201. public ReverseIterator rbegin()
  202. {
  203. return ReverseIterator(m_tail);
  204. }
  205. public ReverseIterator rend()
  206. {
  207. return ReverseIterator(null);
  208. }
  209. public bool empty()
  210. {
  211. return m_head == null;
  212. }
  213. public uint length()
  214. {
  215. return m_length;
  216. }
  217. public void pushFront(ValueType val)
  218. {
  219. Node* np = new Node;
  220. np.prev = null;
  221. np.data = val;
  222. if(m_head !is null)
  223. {
  224. m_head.prev = np;
  225. np.next = m_head;
  226. m_head = np;
  227. }
  228. else
  229. {
  230. np.next = null;
  231. m_head = np;
  232. m_tail = np;
  233. }
  234. m_length++;
  235. }
  236. public void pushBack(ValueType val)
  237. {
  238. Node* np = new Node;
  239. np.next = null;
  240. np.data = val;
  241. if(m_tail !is null)
  242. {
  243. m_tail.next = np;
  244. np.prev = m_tail;
  245. m_tail = np;
  246. }
  247. else
  248. {
  249. np.prev = null;
  250. m_head = np;
  251. m_tail = np;
  252. }
  253. m_length++;
  254. }
  255. // 删除第一个元素
  256. public void popFront()
  257. {
  258. assert(!empty);
  259. erase(Iterator(m_head));
  260. }
  261. public void popBack()
  262. {
  263. assert(!empty);
  264. erase(Iterator(m_tail));
  265. }
  266. //迭代器指向被删除的元素之后的下一个元素或 end,
  267. //注意删除之后 where 迭代器就无效鸟
  268. public Iterator erase(Iterator where)
  269. {
  270. assert(!empty);
  271. Node* i = where.m_node.next;
  272. Node* n = where.m_node;
  273. if(n.prev !is null) n.prev.next = n.next;
  274. if(n.next !is null) n.next.prev = n.prev;
  275. delete n;
  276. m_length--;
  277. return Iterator(i);
  278. }
  279. public Iterator erase(Iterator first, Iterator last)
  280. {
  281. assert(!empty);
  282. Iterator i = first;
  283. while(i != last) i = erase(i);
  284. return i;
  285. }
  286. //在给定的有效迭代器前面插入,返回新元素位置
  287. public Iterator insert(Iterator where, ValueType val)
  288. {
  289. assert(where.m_node !is null);
  290. Node* newNode = new Node;
  291. Node* oldPrev = where.m_node.prev;
  292. newNode.data = val;
  293. Node.join(newNode, where.m_node);
  294. if(oldPrev !is null)Node.join(oldPrev, newNode);
  295. return Iterator(newNode);
  296. }
  297. //在 where 前面连续插入 count 个相同的元素
  298. public void insert(Iterator where, uint count, ValueType val)
  299. {
  300. Iterator iter = where;
  301. for(uint i = 1; i < count; ++i)
  302. iter = insert(iter, val);
  303. return iter;
  304. }
  305. // 不能重载提领操作符就不能很好地使用,比如:
  306. // const int array[] = [1, 2, 3, 4];
  307. // auto list = List!(int);
  308. // list.pushBack(0);
  309. // list.insert(list.begin, array.ptr, array.ptr + array.length);
  310. // 看来只有专门为数组重载了
  311. // 在 where 前面插入一段元素,要求 InputIterator 定义了 ++i, i.current
  312. public void insertElements ( InputIterator ) // D 的函数模板还是有问题,为什么不能叫 insert
  313. (Iterator where, InputIterator first, InputIterator last)
  314. {
  315. InputIterator i = first;
  316. Iterator pos = where;
  317. while(i != last)
  318. {
  319. pos = insertBack(pos, i());
  320. ++i;
  321. }
  322. }
  323. // 在 where 后面插入,并返回新位置
  324. private Iterator insertBack(Iterator where, ValueType val)
  325. {
  326. Node* oldNext = where.m_node.next;
  327. Node* newNode = new Node;
  328. newNode.data = val;
  329. Node.join(where.m_node, newNode);
  330. if(oldNext !is null) Node.join(newNode, oldNext);
  331. return Iterator(newNode);
  332. }
  333. public void opCatAssign(SelfType rhs)
  334. {
  335. for(Iterator i = rhs.begin; i != rhs.end; ++i)
  336. {
  337. pushBack(i.current);
  338. }
  339. }
  340. public void swap(inout SelfType rhs)
  341. {
  342. assert(rhs !is null);
  343. swap_(rhs.m_tail, m_tail);
  344. swap_(rhs.m_head, m_head);
  345. swap_(rhs.m_length, m_length);
  346. }
  347. }
  348. // 最简单的 STL 算法, find
  349. // D不支持提领,我们只能约定 opCall 读取值,opAssign 设置值
  350. private IterType find(IterType, ValueType)(IterType first, IterType last, ValueType val)
  351. {
  352. IterType i = first;
  353. while(i != last && i() != val) ++i;
  354. return i;
  355. }
  356. void main()
  357. {
  358. alias List!(int) MyList;
  359. auto l = new MyList;
  360. l.pushBack(1);
  361. l.pushBack(2);
  362. l.pushBack(3);
  363. l.pushBack(4);
  364. l.pushBack(5);
  365. for(MyList.Iterator i = l.begin; i != l.end; i++)
  366. {
  367. writefln(i());
  368. }
  369. writefln("\nreversed:");
  370. MyList.Iterator i = l.begin;
  371. i++;
  372. i++;
  373. l.insert(i, 12);
  374. l.erase(i);
  375. for(MyList.ReverseIterator ri = l.rbegin; ri != l.rend; ri++)
  376. {
  377. writefln(ri());
  378. }
  379. }
分享到:
评论
3 楼 oldrev 2007-04-09  
由于GC的使用,链表也完全可以实现copy on write,因此我准备仔细设计之后为它添加一个存储 Policy,让用户可以在编译时决定时候启用 copy on write 特性。
2 楼 oldrev 2007-04-07  
引用
好!

不过Traversal和 ValueAccess 好像没用进去亚。

我把boost里面迭代器部分的PDF全下载了,还真不少,看完再说


Traversal 和 ValueAccess 是给算法重载用的
1 楼 qiezi 2007-04-07  
好!

不过Traversal和  ValueAccess  好像没用进去亚。

我把boost里面迭代器部分的PDF全下载了,还真不少,看完再说

相关推荐

    双向链表模板类简单实现

    本文将深入探讨双向链表及其在C++中的模板类实现,以"双向链表模板类简单实现"为主题,我们来详细了解一下这个话题。 双向链表,与单向链表不同,它的每个节点不仅包含数据,还包含两个指针,一个指向下一个节点...

    双向链表模板类的实现

    数据结构——双向链表模板类的实现 //数据结构——双向链表模板类的实现2007年06月16日 星期六 10:14 ////////////////////////////////////////////////////////////////////// // 模块名: 双向链表模板类 // 代码...

    VC 单向/双向链表模板类实例二则.rar

    VC中的双向链表模板类`DoublyLinkedList&lt;T&gt;`可能包含以下结构: 1. **节点定义**:与单向链表类似,但需要增加一个指向前一个节点的指针,如`ListNode* prev`。 2. **链表类定义**:除了单向链表的基本方法外,还会...

    支持类模版的C++双向链表

    在这个“支持类模版的C++双向链表”中,我们将探讨如何利用C++的模板特性来实现一个灵活且高效的双向链表,并应用到实际的排序算法中。这个实现适用于VC 6.0和VS2008等编译器。 首先,类模版是C++中的一种泛型编程...

    网上搜集的七种双向链表模板c++实现

    这里我们将深入探讨网上搜集的七种双向链表模板在C++中的实现。 1. **基础的双向链表模板** 双向链表的基本结构包括节点(Node)类和链表(DoublyLinkedList)类。节点类通常包含一个数据成员、一个指向前一个节点...

    双向链表模板(纯C++语言)

    这里的"双向链表模板(纯C++语言)"是用C++实现的一个通用(template)双向链表类。下面我们将深入探讨这个模板类的关键组成部分及其功能。 首先,`DoubleList`类包含一个内部结构体`Node`,用于表示链表中的每个...

    双向链表List模板类(模拟STL容器中的list)

    双向链表List模板类(模拟STL容器中的list),提供插入删除,清空,获取链表长度,判断链表是否为空等操作,内置了迭代器类型

    数据结构 双向链表(C++)

    在C++中,我们可以创建一个类来封装双向链表的管理。这个类通常包含指向头节点和尾节点的指针,以及一些基本操作的成员函数: ```cpp class DoublyLinkedList { private: Node* head; Node* tail; public: ...

    c++ 模板 双向链表 操作

    首先,我们需要定义一个表示双向链表节点的模板类。这个类通常包含三个部分:数据成员(用于存储数据),一个指向前一个节点的指针,以及一个指向后一个节点的指针。下面是一个简单的节点类模板定义: ```cpp ...

    双向链表(用模板实现)

    本教程将详细介绍如何使用模板来实现一个高效的双向链表。 首先,我们需要定义一个表示链表节点的结构体或类。这个节点应包含三个成员:一个数据部分,以及两个指针,分别指向下一个节点和前一个节点。模板在这里...

    Java版链表模板类

    `CList`可能是基本的链表模板类,而`CList2`可能是对`CList`的一个扩展或改进,例如增加了额外的功能或优化了性能。 1. **链表节点定义**: 在Java中,链表的基本单元是节点,通常包含两部分:数据域(存储元素)...

    C++双向链表统计文章单词出现频率

    在C++中,标准模板库(STL)提供了一个名为`list`的容器,它实现了双向链表。双向链表允许我们在O(1)的时间复杂度内进行前向或后向遍历,这对于我们的任务来说非常方便,因为我们需要遍历整个文本并统计单词。 接...

    双向链表(不用模板实现)

    在实际应用中,双向链表常用于实现高效的迭代器,例如在STL(标准模板库)中的`list`容器就是基于双向链表实现的。此外,它们也被用在各种算法中,如LRU缓存淘汰策略,因为双向链表可以快速地在链表中移动节点。 ...

    双向链表双向链表双向链表

    在Java中,`java.util.LinkedList`类也是基于双向链表实现的。这些高级语言的内置数据结构封装了底层的指针操作,使得开发者可以更专注于逻辑处理,而不是底层实现。 总的来说,双向链表是一种非常重要的数据结构,...

    VC++模板双向链表演示代码

    该示例使用VS2013编写,其中DoubleDIRList为数据元素类,DoubleDIRListContainer为自己手写实现的双向链表类,DequeForListContainer为使用Deque实现的双向链表类

    用双向链表做的n的阶乘

    注意,为了在VC2005中编译,我们需要确保代码遵循C语言标准,避免使用C++特有特性,如类和模板。此外,处理链表时需要特别注意内存管理,确保正确地释放不再需要的节点。 通过这种方式,我们可以学习如何在实际编程...

    用面向对象思想编写的C++双向链表类

    本篇文章将详细探讨在C++中使用面向对象思想编写双向链表类的相关知识点。 双向链表是一种线性数据结构,每个节点包含指向前后节点的指针,使得可以从两个方向遍历链表。在C++中,我们可以创建一个名为`ListNode`的...

    VC win32链表模板类

    这里采用模板机制实现双向链表。 由于做的项目需要对结点进行频繁的增删,这里把结点地址公布出来以提高删除结点的速度(删除时,不需要进行链表的搜索操作) 重载了ostream& operator运算符,方便使用cout写调试...

    CNewList C++写的管理双向链表的一个类

    通过阅读这些文件,开发者可以深入理解类的内部工作原理,以及如何在实际项目中有效地利用这个类来管理双向链表。 总结来说,`CNewList`类是C++中用于管理双向链表的一个工具,它提供了丰富的操作接口,便于插入、...

Global site tag (gtag.js) - Google Analytics