前面我们讲了线性表的java实现。线性表的Java实现
它是有缺点的,最大的缺点在于插入和删除时需要移动大量元素,当表很长时,对性能的损耗严重。
今天来介绍表的链式存储结构——单链表。
单链表的存储结构
单链表:链表中的每一个节点由元素和对下一个节点的引用组成。
指针域 - 每一个节点包含指向下一个节点的指针。
节点 - 节点由元素和指向下一个节点的指针组成。
链表在jdk中也有实现-LinkedList, 现在我们自己来实现一个LinkedList.
首先定义一个元素类,单链表我们需要一个表头header
private Node header;
private class Node {
public Elem data;
public Node next;
}
单链表的插入
先来看单链表的插入,假设要插入的节点为s,要将s插入到p和q之间,只需要让s.next和p.next做一点改变即可。
s.next = p.next;
p.next = s;
这里注意顺序不能颠倒,如果先p.next = s,此时会使p.next被覆盖为s的地址了;再执行s.next = p.next,相当于s.next = s;
就不符合我们需要插入的顺序了。所以这里一定要注意插入代码的顺序。
我们来看完整的插入代码:
public void insert(Elem e, int index) {
if (header == null) {
LogUtil.d(TAG, "LinkedList header is empty, can not insert");
} else {
Node p = new Node();
p.data = e;
int i = 0;
Node temp = header;
while (i < index && temp != null) {
temp = temp.next;
i++;
}
if (temp == null) {
LogUtil.d(TAG, "Insert index out of bounds");
return;
}
p.next = temp.next;
temp.next = p;
}
}
分析:
1.从头节点开始遍历链表,直到找到要插入的位置;
2.如果找到插入的位置,执行上述的插入操作;
3.如果没有找到插入的位置,则说明数组越界,返回。
单链表的删除
再来看单链表的删除,删除操作相对插入要简单直观一些,假设要删除的节点为p,只需要:
p.next = p.next.next;
这个直接从图上看很直观,就不做解释了。看完整代码:
public void delete(int index) {
if (header == null) {
LogUtil.d(TAG, "LinkedList header is empty, can not delete");
} else {
if (index == 0) {
deleteAtFirst();
} else {
int i = 0;
Node temp = header;
Node prev = header;
while (i < index && temp != null) {
prev = temp;
temp = temp.next;
i++;
}
if (temp == null) {
LogUtil.d(TAG, "Delete index out of bounds");
return;
}
Node deleteNode = prev.next;
prev.next = prev.next.next;
deleteNode = null;
}
}
}
删除的思路和插入类似,先遍历找到要删除的节点,然后执行删除操作;
需要注意的是,如果删除的是头节点,需要对header做特殊的操作。
好了,插入和删除讲完了,至于get操作,其实已经包含在插入和删除的代码中了,直接遍历找到对应位置的元素即可。
文末推荐个人开发的app,Google Play : 数据结构与算法教程 (需要科学上网)
提供了丰富的动画演示、模拟场景来帮助你更好的理解抽象的数据结构和复杂的算法。(文中的动图都是从app中截取的片段)