《数据结构与算法》2-链表

上一节我们总结了一下数组,数组的特性就是要吧数据存储在一块连续的存储块内。所以当我们知道了第一个数据的内存地址,就可以随机访问其他的数据。访问的事件复杂度是O(1)。但是数组的缺陷也比较明显:

  • 首先物理内存必须是连续的,数据量大的时候难以保证存储够用
  • 插入删除操作相对复杂,需要做数据的复制移位。

链表的出现就解决了上述问题。首先链表的基本元素是节点:Node。Node数据结构分两部分:

  • 1-数据域,用来保存数据
  • 2-指向下一个数据的指针。

上面的指针给了链表的极大扩展性:

  • 链表不需要物理存储的连续性,因为单个节点可以分开保存,只要有指针指向它的位置就能保证链表的顺序。
  • 链表的删除插入操作比较简单,比如A->B->C的链表中删除B,只要把A的下一节点指针指向C,B的指针置空,就能删除B节点。

但是链表也有自身的缺陷:

  • 首先,因为多了指针部分,单节点的内存占用更大了
  • 访问指定下标的数据变得困难,只能从头遍历链表到达指定位置,不能像数组可以做到随机访问。

上面的总结都是基于普通链表,即单链表(只有一个数据指针),有头节点(head)和尾节点(tail)。头节点指向第一个节点,尾节点指向最后一个节点,

判断单链表是否为空:head = tail,尾节点tail的指针为null;

单链表能够实现顺序的遍历。但是如果要倒序遍历,对单链表来说就非常难堪。所以针对链表的倒序,我们扩展单链表的指针部分:

  1. 数据域,保存数据
  2. pre指针,指向前一个节点
  3. next指针,指向下一个节点

这样的节点组成的链表成为双向链表,除头节点和尾节点之外的节点可以从当前节点向前遍历,也可以向后遍历。所以是双向链表

除了双向链表,还有一种循环链表。即tail节点的next指向head节点。

判断循环链表满的条件,(tail+1)%listSize = head

HashTable 中的桶指向的链表是单向链表。LinkedHashMap中的桶指向的链表是双向链表

所以到底是选择数组还是链表呢?

如果代码中很少需要删除新增数据的时候,我们还是优先使用数组。

如果频繁使用新增删除操作,可以使用链表。

示例:如果在代码中保存长度固定的数据,新增操作时,如果内存不够时,最近最少使用的优先删除。这个实现中应用链表就非常简单。

  1. 新增数据放在链表的头位置
  2. 长度不够时,删除队尾的数据

上面的算法就是最近最少使用原则

猜你喜欢

转载自blog.csdn.net/David_lou/article/details/108586322