链表工作原理
问题1:虚拟结点的使用,为什么要使用虚拟结点?
虚拟结点就是C数据结构中所说的头结点,它的next指针指向第一个结点(当然Java中是没有指针的);使用了虚拟结点,在删除第一个结点时不会误删导致整个链表丢失,有利于维护链表。
问题2:链表中未使用数组,索引从何而来?
链表也是线性表,不论是逻辑顺序和存储顺序上,表中元素都是相邻的;所以我们可以从第一个结点开始到最后一个结点,给他指定一个索引来方便我们指定结点。
问题3:索引是如何在链表中进行移动的呢?
在链式存储结构中,我们通过next引用将结点连接起来,这样我们通过next引用的不断向后传递,索引随着next移动在链表中移动。
问题4:为什么使用内部类,来定义结点的数据结构?
在定义结点类时,不光使用内部类,同时利用 private 将结点类封装在链表中,将底层数据封装起来,留下接口给程序员使用,可以防止链表被破坏。
实现的方法
- isEmpty():判断链表是否为空
- contains(AnyType data):链表是否包含某个元素
- getSize():获得链表中存储元素个数
- getFirst():查询链表中的第一个元素
- get(int idx):根据给定索引查询链表中的元素
- getLast():查询链表中的最后一个元素
- addFirst():链表的头插法
- add(int idx, AnyType data):向指定索引位置插入元素
- addLast():链表的尾插法
- removeFirst():删除表头元素
- remove(int idx, AnyType data):删除指定索引位置的元素
- removeLast():删除表尾元素
具体代码实现
public class MyLinkedList <AnyType>{
private Node head;
private int size;
private class Node{
AnyType data;
Node next;
public Node() {
data = null;
next = null;
}
public Node(AnyType data, Node next) {
this.data = data;
this.next = next;
}
}
public MyLinkedList() {
head = new Node();
size = 0;
}
public boolean isEmpty() {
return head.next == null;
}
public boolean contains(AnyType data) {
if(isEmpty()) {
return false;
}
Node prev = head;
while(prev.next != null) {
prev = prev.next;
if(prev.data == data)
return true;
}
return false;
}
public int getSize() {
return size;
}
public AnyType getFirst() {
Node prev = head.next;
return prev.data;
}
public AnyType get(int idx) {
if(idx > size || idx < 0) {
throw new IllegalArgumentException("不合法位置");
}
Node prev = head;
for(int i = 0; i <= idx; i++) {
prev = prev.next;
}
return prev.data;
}
public AnyType getLast() {
return get(size-1);
}
public void addFirst(AnyType data) {
Node node = new Node(data, head.next);
head.next = node;
size++;
}
public void add(int idx, AnyType data) {
if(idx > size || idx < 0) {
throw new IllegalArgumentException("不合法位置");
}
Node prev = head;
for(int i = 0; i < idx; i++) {
prev = prev.next;
}
Node node = new Node(data, prev.next);
prev.next = node;
size++;
}
public void addLast(AnyType data) {
add(size, data);
}
public void removeFirst() {
if(isEmpty())
throw new IllegalArgumentException("空表无法进行删除操作");
head = head.next;
size--;
}
public void remove(int idx) {
if(isEmpty() || idx >= size)
throw new IllegalArgumentException("空表或者索引越界无法完成操作");
Node prev = head;
for(int i = 0; i < idx; i++) {
prev = prev.next;
}
Node outNode = prev.next;
prev.next = outNode.next;
size--;
}
public void removeLast() {
remove(size - 1);
}
public String toString() {
StringBuilder strb = new StringBuilder();
strb.append("链表:");
strb.append("size = "+size+"\n");
strb.append("[");
Node prev = head;
while(prev.next != null) {
prev = prev.next;
strb.append(prev.data);
if(prev.next != null)
strb.append(',');
}
strb.append("]");
return strb.toString();
}
}