#include<stdio.h> /** 单链表 **/ /* 利用指针可以为直接映射到改变上 且后续的地址传递比较方便,永远不要对表头做操作。只赋值。 */ struct Node { int val; Node * next; }; Node * Head,Last; void CreatList_L(int n) { Node *p,*q; Head = new Node(); Head->next = NULL; p = Head; while(n--) { q = new Node(); scanf("%d",&q->val); q->next = p->next; p->next = q; } } void CreatList_LO(int n) { Node *p,*q; Head = new Node(); Head ->next = NULL; p = Head; while(n--) { q = new Node(); scanf("%d",&q->val); q -> next = NULL; //这个是需要注意的。一开始 q->next 初始化出来之后的值是随机的。并非NULL.而输出时候直接while(p) 即利用NULL==0 p->next = q; p = p->next; } } /* 对于insert 我们只考虑insert 0 位置才是最有效率的 那么要实现添加为O(1)就必须在建表的时候。 对于逆建表。 insert 相当于在一个序列的尾巴插入 并且你可以即时处理这个尾部 对于顺序建表。insert 相当于在一个序列的头部插入 并且你可以即时处理这个头部 */ void OutPut() { Node *p; p = Head->next; while(p) { printf("%d",p->val); p = p->next; } } int main() { /* int *L; L = new int(); int n,i; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) { scanf("%d",&L[i]); } for(i=0;i<n;i++) { printf("%d",L[i]); } } 顺序表 q = L+L.lenth-1 就能指向顺序表的最底端 */ int n; while(scanf("%d",&n)!=EOF) { CreatList_LO(n); OutPut(); } }
对于可持久化链表:
思考一个这样的问题。对于可持久化链表(确切地说应该是可持久化数据结构)。可持久化体现在能够恢复到旧版本。可以联想浏览器的历史痕迹。即对链表的每一步操作能做一个新版本来保存起来。
http://www.cnblogs.com/tedzhao/archive/2008/11/12/1332112.html
这里有更加全面的解释。感谢这位作者的辛勤劳动。
具体实现:
我们需要用一个数组存储各个版本的头指针。根据上面链接的那个博文可以知道插入中间的时候。前面的所有节点都要复制下来。这是必须的。因为单链表是从头指针开始的。如果不复制。头指针就只有一个。明显不能符合版本分开。假如理想状态下。我们的每次插入如果不是插入。而是添加(添加也是插入)。添加到头位置。(添加到尾部就是恰恰最坏情况了)。那我们的可持久化链表是极其有效率的。
这里有一个题恰恰是利用了这个特点。
URAL 1992 CVS
模拟题
分析时间 基本上可以知道 要求我们的每一步操作是在O(1)的级别。
这个题目要支持维护最后一个元素。(不管是学习列表还是记忆列表)。
那么我们应该使用逆建表。这里有一个问题就是数据是实时的。
那我们只要把模仿着逆建表慢慢添加入元素即可
用一个数组存储表头。维护count 每一次操作后加1表示有新的版本。
code 后续补上。