链表是一种线性存储结构称为线性链表(链表),并且储存空间不连续,是真正的动态数据结构。常见的链表有单链表,循环链表,双向链表;
链表优点:方便插入和删除真正的动态,不需要处理固定的问题;
链表缺点:查找元素不友好,不能直接访问,结构麻烦。
链表的存储单元称为“结点”(Node),一个结点包涵(数据域,地址域);
1,单链表(Singly Linked List)
结构如下:
单链表节点(数据域data,后继结点地址域next)(分为带有头结点,不带有头结点)
代码结构:
public calss Node<E> {
E e ; //数据
Node next; //下一个地址
}
用内部类的形式实现,Node内部类:
//将Node节点设计成私有的类中类
private class Node<E> {
public E e;
public Node next;
//两个参数的构造函数
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
//一个参数的构造函数
public Node(E e) {
this.e = e;
this.next = null;
}
//无参构造函数
public Node() {
this(null, null);
}
@Override
public String toString() {
return e.toString();
}
}
(一)在链表头添加元素:
1,首先有个node结点 ,让node的下一个结点指向head (头) :node.next=head; (此时node成为了新的链表头)
2,让head指向node ,node指向666的这个节点 ,所以执行完后就结束了
//在链表头添加新的元素e
public void addFirst(E e) {
//添加的方式
Node node = new Node(e);
node.next=head;
head=node;
//简便方法1
// dummHead = new Node(e, dummHead);//因为上边有构造方法
//简便方法2
//add(0, e);简便的方法
size++;//维护长度
}
一句话个可以完成上面的的三句话:// // Head = new Node(e, Head); new Node传入一个元素e, 然后将head地址传入,在返回给head结点。
(二) 在链表的指定位置添加元素
1,首先要创建出node的几点(666),要想插入相应的位置就必须找到插入之后的之前的那(prev),让prev指向node,node指向之前prev之后的结点。
node的下一个结点指向,之前prev的下一个结点,然后prev的下一个节点变成node
就是这样的: node.next = prev.next;
prev.next = node;
关键:找到要添加的结点的前一个节点;
注意顺序:
代码:
//在链表的index(0--based)的位置添加新的元素e (实际不常用,练习用)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("位置不合法");
}
Node prev = dummyHead;//初始时prev指向dummyHead
for (int i = 0; i < index; i++) {//获取到需要添加元素位置的前一个元素 从dummyHead开始遍历
prev = prev.next; //当前一个节点的前一个节点
}
// Node node = new Node(e);
// node.next = prev.next;
// prev.next = node;
//简便后的方式
prev.next = new Node(e, prev.next);
size++;
}