目录
1.链表
链表是线性表最常见的两种表现方式之一
数据储存在节点(Node)中 Node一般来说包括:元素、前驱、后继
第一个节点的前驱是null,最后一个节点的后继是null
真正地实现了动态,不需要考虑动态扩容的问题
2.节点实现(内部类)
public class LinkList<E> {
private class Node {
//元素
public E e;
//节点
public Node next;
//指定元素与下一个节点的构造器
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
public Node(E e) {
this(e, null);//指定元素下一个节点为null
}
public Node() {
this(null, null);//空构造器,元素与下一个节点均为null
}
@Override
public String toString() {
return e.toString();
}
}
}
3.列表基本成员
- 头节点
- 元素数量
private Node head;//头节点 private int size;//元素数量 public LinkList() {//构造函数 head = null; size = 0; } public int getSize() { return size;//获得元素数量 } public boolean isEmpty() { return size == 0; } }
4.增删改查
-
4.1增加
-
public void addFirst(E e){//在头部添加 //将元素放进新生成的节点中 Node node = new Node(e); //将新节点指向现在的头部 node.next=head; //将头节点换成新节点 head=node; }
public void add(int index, E e) { if (index < 0 || index > size) { throw new IllegalArgumentException("参数不合法,添加失败"); } if (index == 0) { addFirst(e); } else { Node prev = head; for (int i = 0; i < index - 1; i++) { prev = prev.next; } Node node = new Node(e); node.next = prev.next; prev.next = node; size++; } }
public void addLast(E e) { add(size, e); }
4.1.1改进 虚拟头节点
- 由于在头部添加时,无前一个,所以产生了虚拟头节点
- 虚拟头节点的元素是null,指向了实际的头一个节点
-
package Array; public class LinkList<E> { //节点内部类 1.链表是由节点串起来的2.下一个节点应该作为引用 private class Node { //元素 public E e; //节点 public Node next; //指定元素与下一个节点的构造器 public Node(E e, Node next) { this.e = e; this.next = next; } public Node(E e) { this(e, null);//指定元素下一个节点为null } public Node() { this(null, null);//空构造器,元素与下一个节点均为null } @Override public String toString() { return e.toString(); } } private Node visualHead;//头节点 private int size;//元素数量 public LinkList() {//构造函数 visualHead = new Node(); size = 0; } public int getSize() { return size;//获得元素数量 } public boolean isEmpty() { return size == 0; } public void addFirst(E e) { // //将元素放进新生成的节点中 // Node node = new Node(e); // //将新节点指向现在的头部 // node.next = head; // //将头节点换成新节点 // head = node; add(0,e); } public void add(int index, E e) { // if (index < 0 || index > size) { // throw new IllegalArgumentException("参数不合法,添加失败"); // } if (index == 0) { addFirst(e); } else { Node prev = visualHead; for (int i = 0; i < index - 1; i++) { prev = prev.next; } Node node = new Node(e); node.next = prev.next; prev.next = node; size++; } } public void addLast(E e) { add(size, e); }
4.2查询
public E get(int index){ //根据索引查找元素 if (index < 0 || index > size) { throw new IllegalArgumentException("参数不合法,查找失败"); } Node current=visualHead.next; for (int i = 0; i < index; i++) { current=current.next; }return current.e; }
4.3修改链表中某处的元素
public void set(int index, E e) { if (index < 0 || index >= size) { throw new IllegalArgumentException("参数不合法,修改失败"); } Node current = visualHead.next; for (int i = 0; i < index; i++) { current = current.next; } current.e = e; }
4.4 删除操作
4.4.1 根据索引删除元素
//根据索引删除元素
public E remove(int index) {
//参数的合法性判断
if (index < 0 || index >= size) {
throw new IllegalArgumentException("删除失败,索引不合法");
}
//从虚拟头节点开始查找待删除节点的前一个
Node prev = visualHead;
//开始查找
for (int i = 0; i < index; i++) {
prev = prev.next;
}
//待删除节点
Node retNode = prev.next;
//删除操作
//待删除节点的前一个指向待删除结点的下一个
prev.next = retNode.next;
retNode.next = null;
size--;
//返回待删除节点的元素
return retNode.e;
}
//删除链表中第一个元素
public E removeFirst() {
return remove(0);
}
//删除链表中最后一个元素
public E removeLast() {
return remove(size - 1);
}
4.4.2 根据元素删除元素
//根据元素删除元素
public void removeElement(E e) {
//从虚拟头节点作为待删除节点的前一个
Node prev = visualHead;
//通过while循环找到待删除元素所在节点
while (prev.next != null) {
//判断下一个的节点元素值与参数是否一致
if (prev.next.e.equals(e)) {
//跳出循环,执行接下来的操作
break;
}
//prev向后传递
prev = prev.next;
}
Node retNode = prev.next;
prev.next = retNode.next;
retNode.next = null;
size--;
}
5 遍历操作
-
@Override public String toString() { StringBuilder res = new StringBuilder(); Node current = visualHead.next;//从第一个实际结点出发进行遍历,虚拟头节点的下一个 // 在链表结束之前做以下操作 while (current != null) { res.append(current + "->");//加上箭头形象化链表 current = current.next;//往后传递 } res.append("null");//表示链表结束 return res.toString(); }