
7.双向链表的优雅实现
❝链表是基本的数据结构,尤其双向链表在应用中最为常见,LinkedList 就实现了双向链表。今天我们一起手写一个双向链表。❞
文中涉及的代码可访问 GitHub:https://github.com/UniqueDong/algorithms.git
上次我们说了「单向链表」的代码实现,今天带大家一起玩下双向链表,双向链表的节点比单项多了一个指针引用 「prev」。双向链表就像渣男,跟「前女友」和「现女友」,还有一个「备胎』都保持联系。前女友就像是前驱节点,现女友就是 「当前 data」,而「next」指针就像是他套住的备胎。每个 Node 节点有三个属性,类比就是 「前女友」+ 「现女友」 + 「备胎」。
使用这样的数据结构就能实现「进可攻退可守」灵活状态。
接下来让我们一起实现『渣男双向链表』。
定义Node
节点分别保存现女友、前女友、跟备胎的联系方式,这样就能够实现一三五轮换运动(往前看有前女友,往后看有备胎),通过不同指针变可以找到前女友跟备胎。就像渣男拥有她们的联系方式。
代码实现
定义好渣男节点后,就开始实现我们的双向链表。类似过来就是一个渣男联盟排成一列。我们还需要定义两个指针分别指向头结点和尾节点。一个带头大哥,一个收尾小弟。
头节点添加
新的渣男进群了,把他设置成群主带头大哥。首先构建新节点,prev = null,带头大哥业务繁忙,不找前女友,所以 prev = null;next 则指向原先的 first。
1.如果链表是空的,则还要把尾节点也指向新创建的节点。
2.若果链表已经有数据,则把原先 first.prev = newNode。
尾节点添加
将新进来的成员放在尾巴。
第一步构建新节点,把 last 指向新节点。
第二步判断 last 节点是否是空,为空则说明当前链表是空,还要把 first 指向新节点。否则就需要把原 last.next 的指针指向新节点。
指定位置添加
分为两种情况,一个是在最后的节点新加一个。一种是在指定节点的前面插入新节点。
在后面添加前面尾巴添加已经说过,对于在指定节点的前面插入需要我们先找到指定位置节点,然后改变他们的 prev next 指向。
节点查找
为了优化,根据 index 查找的时候先判断 index 落在前半部分还是后半部分。前半部分通过 first 开始查找,否则通过 last 指针从后往前遍历。
查找 Object 所在位置 indexOf ,若找不到返回 -1
判断 链表中是否存在 指定对象 contains ,其实还是利用 上面的 indexOf 方法,当返回值 不等于 -1 则说明包含该对象。
节点删除
有两种删除情况:
1.根据下标删除指定位置的节点。
2.删除指定数据的节点。
删除指定位置节点
1.首先判断该 index 是否合法存在。
2.查找要删除的节点位置,重新设置被删除节点关联的指针指向。
node() 方法已经在前面的查找中封装好这里可以直接调用,我们再实现 unlink 方法,该方法还会用于删除指定对象,所以这抽出来实现复用。也是最核心最不好理解的方法,我们多思考画图理解下。
分别找出被删除节点 x 的前驱和后继节点,要考虑当前链表只有一个节点的情况,最后还要把被删除节点的 的 next 指针 ,item 设置 null,便于垃圾回收,防止内存泄漏。
删除指定数据
这里判断下数据是否是 null , 从头节点开始遍历链表,当找到索要删除的节点的时候调用用前面封装好的 unlink 方法实现删除。
完整代码可以参考 GitHub:https://github.com/UniqueDong/algorithms.git
文章转载自公众号:码哥字节
