链表就是一段内存颗粒的连接,如同珍珠项链。珠子就是存放的内容,线就是单向或双向指针。
链表相对于c数组,好处是内存全是散的,不需要整块内存,只处理头部或尾部数据很简单,中间加减数据不复杂。
但好处就是坏处,散在的内存就无法随机定位,对于随机操作就成了弟弟。而且对于巨大的数据量,析构都是问题。
想起一个故事,韩信要与项羽决战,但刘邦怎么催都不出战,因为缺少一个工具,战车。
战车不难造,又快又能抗打的没有,但是如果不想死,必须造出这种战车。铁车抗造,但马拉不动,只能挨打。木车轻快,但一箭穿心,车里的人都玩完。
怎么办?
结合,取其精华,去其糟粕,将木车防箭的地方镶上铁板,整体下来,依然没有铁车结实,没有木车轻快,但吸收了二者的优点,去除了二者的缺陷,已经可以一战了。
故事归故事,瞎说的,但道理是实在的。数组加链表的组合体,因该是对付大数据最合适的战车。
以下是纯单向链表实现的队列和栈,非常简单,不过我照着《算法4》这本书扣了半天,愣是没弄出来,最大的问题是java和C++的变量差的太远,其实java的变量更像C++的指针。怪不得C语言满天飞指针,因为在实现底层数据结构的时候,所有的玩法都是内存的玩法。
动态数组,说白了就是一段连续内存。链表就是不连续内存。对付内存,只能用指针,否则实现难度直接升一个量级,一点不夸张。
多说无益,见代码:再多说两句,链表析构比构造要慢太多了。C++写类的时候,一定给基础变量初始值,指针是nullptr,数值是0,否则就等着找bug吧。
#ifndef STACK #define STACK #include templatestruct ListStack; template struct ListQueue; template struct Node { private: T item; Node *next = nullptr; friend class ListStack ; friend class ListQueue ; }; template struct ListStack { bool isEmpty() { return N == 0; } int size() { return N; } void push(const T &item) { Node *oldfirst = first; first = new Node (); first->item = item; first->next = oldfirst; ++N; } T pop() { assert(first); T item = first->item; Node *temp = first; first = first->next; --N; delete temp; return item; } ~ListStack() { while (first) { Node *temp = first; first = first->next; delete temp; } } private: Node *first = nullptr; unsigned N = 0; }; template struct ListQueue { bool isEmpty() { return N == 0; } int size() { return N; } void enqueue(const T &item) { Node *oldlast = last; last = new Node (); last->item = item; if (first) { oldlast->next = last; } else { first = last; } ++N; } T dequeue() { assert(first); Node *df = first; T item = first->item; first = first->next; delete df; --N; return item; } ~ListQueue() { while (first) { Node *df = first; first = first->next; delete df; } last = nullptr; } private: Node *first = nullptr; Node *last = nullptr; unsigned N = 0; }; #endif



