链表为什么断不了?是拿振金做的吗?
  说了队列,说了栈,无论什么数据结构都离不开只能按一定顺序储存的结果,向特定位置加入某值的复杂度达不到O(1)O(1)O(1)。天空一声巨响,链表闪亮登场 链表就是这千千万万数据结构中的一个例外。

  链表的模型就是一条链(废话)!我们可以向这条链的任意一个地方加入一个新的节点,也可以删除任意的一个节点。

1.模型

  链表,顾名思义,是以链的形式来储存一个表。而这个链就很有意思了,有条件的可以哪一个项链看一下,我们从任意一个节点出发,都可以直接找的它前后的节点,为了满足这个性质,我们可以对每个节点增加两个储存的量:指向前一个点的指针 fromfromfrom,指向后一个点的指针 tototo 。这样,每个点除了储存这个点的值,还储存了分别指向前后点的指针。

  可以发现,项链总有个首尾,链表也一样。我们可以设立两个坐标,代表链表的头和链表的尾,即 headheadhead 和 tailtailtail 坐标。我们链表的第一个节点的前节点指针指向 headheadhead 坐标,最后一个节点的后节点指针指向 tailtailtail 坐标。所以链表的模型如图所示:
代码:

/*指针版*/                      /*下标版*/
struct link {                   struct link{int value;/*数据*/                int value;/*数据*/link* from, to;/*指针*/       int from, to;/*指针*/
};/*数据结构*/                  }Link[Size];/*数据结构*/    link* head, tail;               int head, tail, tot;void init() {                   void init() {                   head = new link();             head = 1, tail = 2;tail = new link();                tot = 2;head->to = tail;               Link[head].to = tail;tail->from = head;                Link[tail].from = head;
}/*初始化链表*/                  }

2.操作

1.添加节点

  由于链表的性质,链表的添加节点操作支持在任意一个你能找到的节点添加。

  当我们在某一位置添加节点时,我们需要知道这个位置所对应的的 fromfromfrom 指针和 tototo 指针。例如图示链表,我们要在 222 号节点后加入 777 号节点。
我们首先要找到 222 号节点,再通过 222 号节点的 tototo 指针找到 333 号节点。接下来,为了让 777 号节点紧跟在 222 号节点的后面,我们需要将 222 号节点的 tototo 指针从指向 333 变为指向 777 。同时,为了不破坏链表的连通性,我们需要将 777 的 tototo 指针指向 333。然后将 777 号、333 号的 fromfromfrom 指针 更新。
  在其他位置的除收尾外与上述情况相似。如果在收尾添加节点的话,只需要将首节点的 fromfromfrom 指针(或尾节点的 tototo 指针)指向所添加的节点,在将该节点的 tototo 指针(或 fromfromfrom 指针)指向首节点(或尾节点)并将其 fromfromfrom 指针指向 headheadhead 位置(或将其 tototo 指针指向 tailtailtail) 位置。

代码:

/*指针版*/                          /*下标版*/
void insert(Link* p, int val) {     void insert(int p, int val) {link *q = new Link();             int q = ++tot;q->value = val;                        Link[q].value = val;p->to->from = q;                    Link[Link[p].to].from = q;q->to = p->to;                        Link[q].to = Link[p].to;p->to = q;                         Link[p].to = q;q->from = p;                        Link[q].from = p;
}                                   }
2.删除节点

  与添加节点相似,链表中删除节点只需要知道被删除节点的 fromfromfrom (或tototo )指针指向的节点就能进行删除操作。如图,要将 222 号节点与 444 号节点之间的 333 号节点删除时。我们首先要知道 333 号节点的位置,然后,将 333 号节点 fromfromfrom 指针指向的节点的 tototo 指针指向 333 号节点 tototo 指针指向的节点。最后维护链表连通性即可。

可以看到,对点的删除,实际上是将链表中的某个点从链表中孤立出来。

代码:

/*指针版*/                                  /*下标版*/
void remove(Link* p) {                      void remove(int p) {p->to->from = p->from;                            Link[Link[p].to].from = Link[p].from;p->from->to = p->to;                            Link[Link[p].from].to = Link[p].to;delete p;//一定要有,否则内存泄漏就gg了   }
}
3.遍历

  遍历是链表的一个短板,由于插入和输出是没有考虑储存空间的连续性,链表中连续的数据的储存空间可能是不连续的,所以链表没法在 O(1)O(1)O(1) 的复杂度下找到某一特定点,只能通过遍历的方法来查找。
代码:

/*指针版*/                          /*下标版*/
//正向搜索特定值
Link* search(Link* p, int val) {            int search(int p, int val) {if (p->value == val)                       if (Link[p].value == val)return p;                                    return p;search(p->to, val);                         search(Link[p].to, val);
}                                           }
//int main() 内
search(head, val);                          search(head, val);//反向搜索特定值
Link* search(Link* p, int val) {            int search(int p, int val) {if (p->value == val)                       if (Link[p].value == val)return p;                                    return p;search(p->from, val);                       search(Link[p].from, val);
}                                           }
//int main() 内
search(tail, val);                          search(tail, val)

  此时,我们可以发现,在添加和删除节点时,只有 tototo 或 fromfromfrom 指针中的任意一个也可以正常进行操作 ,唯一的不同是遍历是只能从某一方向遍历,而不能双向遍历。

4.内存归还

  当我们用指针实现链表时,虽然这个链表可以动态变化长度,但是一个问题也随之而来:内存泄漏!!!因此,我们必须在指针实现的链表上加一步操作:归还所调用的内存。
代码:

void recycle() {while (head != tail) {head = head->to;delete head->from;}delete tail;
}

3.拓展——链式前向星

  我们储存图时,常常需要储存大量的边,此时如何调用又成了一个问题,但我们可以发现,无论是那一条边,他们总是从某个点到另一个点(自环除外),也就是说,我们可以用出发的点 ppp 来代表一些边的集合 SSS,位于集合 SSS 的边都从 ppp 出发到另外一个点。当我们调用边时,只需要以它的出发点作为关键字,就能在一定的时间内找到这条边。

  可以发现,上述方法不要求边按某种特定顺序储存,也不需要按某种顺序去遍历,只需要将所有从点 ppp 出发的边用某种方式联系起来就行了。由于 ppp 是不可能改变的,所以我们可以联想到链表的性质。链表的 headheadhead 坐标就对应这里的点 ppp ,由于没有顺序要求,可以在 O(1)O(1)O(1) 时间内在任意位置加入任意一点的链表自然成了更加方便快捷的选择。

【数据结构】链表(含链式前向星)相关推荐

  1. 可持久化链表(链式前向星)

    http://codeforces.com/group/aUVPeyEnI2/contest/229670 1 /******************************************* ...

  2. 洛谷 P1352 没有上司的舞会【树形DP/邻接链表+链式前向星】

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  3. 数据结构【链式前向星】

    第一次接触链式前向星是在学习图论的迪杰斯特拉算法时,大佬们纷纷用链式前向星+堆优化+迪杰斯特拉解题,秀的我萌新懵的一批,当时不知道啥是链式前向星,不过随着越来越深入,这种结构见得越来越多,慢慢的就明白 ...

  4. 存图利器——链式前向星

    存图的各种数据结构,复杂如下 邻接矩阵    O(1)(查询一条边)      O(n)枚举出边    O(N*N)空间复杂度 前向星 O(n)(查询一条边)      O(n)枚举出边    O(N ...

  5. 迪杰斯特拉最全详解(朴素版,堆优化+邻接表存图/链式前向星存图)

    迪杰斯特拉 迪杰斯特拉算法分析 迪杰斯特拉(朴素版) 迪杰斯特拉堆优化(邻接表存图) 迪杰斯特拉堆优化(链式前向星存图) 最短路--spfa(链式前向星存图) 迪杰斯特拉算法分析 一般用三种数据结构存 ...

  6. 图的存储 邻接矩阵+邻接表+链式前向星

    图的存储 - 邻接矩阵 在树的问题中,邻接矩阵是空间.时间的极大浪费. 假设树的结点个数为 N = 100000. 建立邻接矩阵需要空间为 1e5*1e5 但是由于只有 N - 1 条边,所以在邻接矩 ...

  7. 图的储存方式,链式前向星最简单实现方式 (边集数组)

    对于图来说,储存方式无非就是邻接矩阵.邻接表,今天看了看链式前向星的储存方式,说来说去不还是链表,是一种链表的简单的实现方式,还是比较好理解的.看他们写个结构体,个人不喜欢,没必要,也嫌麻烦,换一种更 ...

  8. 蓝桥集训之BFS、DFS和链式前向星

    配套视频 https://www.bilibili.com/video/BV1RD4y1F7Fq 一.建图基础 前言 图一般定义为二元集: 由顶点集与边集构成. 或者更抽象的说,由一个集合(顶点),和 ...

  9. 链式前向星——最完美图解

    图的存储方法很多,最常见的除了邻接矩阵.邻接表和边集数组外,还有链式前向星.链式前向星是一种静态链表存储,用边集数组和邻接表相结合,可以快速访问一个顶点的所有邻接点,在算法竞赛中广泛应用. 链式前向星 ...

最新文章

  1. 全球智能驾驶产业全景图
  2. 队列的链式存储和实现(C语言)【队列】(8)
  3. 企业管理系统java web_JavaWeb 基于 web的 企业人事管理系统 Jsp/Servlet 242万源代码下载- www.pudn.com...
  4. typescript接口定义
  5. 测试驱动开发 测试前移_测试驱动开发–双赢策略
  6. php 删除相对应的id,PHP 在下面这个留言板代码中加入删除按钮,每一个删除按钮删除相对应一行数据,这怎么弄...
  7. Python实战从入门到精通第七讲——字符串与文本1之字符串开头或结尾匹配
  8. 使用python turtle库绘制一个三角形和一个五角星_使用turtle库绘制一个五角星 如何采用Python语言绘制一个五角星...
  9. lsblk命令 – 查看系统的磁盘
  10. Excel案例-杜邦分析法
  11. 速度传感器330104-00-06-10-02-00
  12. 常见不等式考察(一)——Jensen不等式
  13. 互盾科技:智慧源于勤奋,伟大出自平凡
  14. COSClient上传图片失败
  15. 期刊以及会议的CCF类别查询方法
  16. 可擦写光盘不能擦除和刻写_光盘怎么判断是否可擦写
  17. EDI对接HELLA成功案例
  18. Delphi 多线程传递参数的问题
  19. 恰到好处的挫折:在最深的绝望,遇见最美的意外 ~ 【美】 格雷格 · S · 里德...
  20. 考研数学一大纲考点数整理

热门文章

  1. 软考系统集成项目管理工程师历年真题汇总(2020-2022)
  2. Verilog中#的使用与理解
  3. 基于 FFMPEG 的像素格式变换(swscale,致敬雷霄骅)
  4. Collectors简单使用
  5. 全国优秀计算机动画作品,分享創意——全国中小学优秀电脑作品分析.ppt
  6. FTP微软喊你回家吃饭
  7. 解决Win10安装DirectX报错:不能信任一个安装所需的压缩文件,请检查加密服务是否启用并且Cabinet文件证书是否有效
  8. qt介绍06——QMAKESPEC
  9. 求阶乘求1!+2!+…+20!,其中x!=1*2*…*x,表示阶乘
  10. 【不同的子序列II】