目录
0.目录
1.线性表 – 数组
2.线性表 – 单向链表
3.栈
链表
链表是一种物理存储单元上非连续、非顺序的数据结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点组成,这些节点不必在内存中相连。每个节点由数据部分Data和链部分Next组成,Next指向下一个节点,这样当添加或者删除时,只需要修改相关节点的Next指向,效率很高)。
// 链表节点代码(使用内部类)
private class Node<E> {
private E element;
private Node<E> next;
public Node(E e, Node<E> next) {
element = e;
this.next = next;
}
public Node(E e) {
this(e, null);
}
public Node() {
this(null);
}
// 使用虚拟头结点保持逻辑连贯性、使用尾节点改进性能
private Node<E> dummyHead;
private Node<E> tail;
private int size = 0;
// 两种构造方法
public Linked(E e) {
dummyHead = new Node<>();
dummyHead.next = new Node<>(e);
tail = dummyHead.next;
size++;
}
public Linked() {
dummyHead = new Node<>();
tail = dummyHead;
}
// 在指定索引位置插入元素
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Wrong index: " + index);
}
Node<E> pre = dummyHead;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
pre.next = new Node<>(e, pre.next);
if (index == size) {
tail = pre.next;
}
size++;
}
// 顺序遍历链表(重写toString方法)
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Linked head[");
Node<E> cur = dummyHead;
while (cur.next != null) {
cur = cur.next;
sb.append(cur.element).append("->");
}
sb.append("NULL").append("]tail");
return sb.toString();
}
// 逆序遍历链表(递归思想)
public void printDesc() {
System.out.print("Linked tail[Null");
printDesc(dummyHead.next);
System.out.println("]head");
}
private void printDesc(Node<E> head) {
if (head != null) {
printDesc(head.next);
System.out.print("<-" + head.element);
}
}
// 单链表反转
public void reverse() {
// 非递归(效率高)
dummyHead.next = reverse(dummyHead.next);
// 递归
// dummyHead.next = reverseRecursion(dummyHead.next);
}
// 非递归实现
private Node<E> reverse(Node<E> head) {
Node<E> pre = null;
Node<E> cur = head;
Node<E> next = null;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 递归实现
private Node<E> reverseRecursion(Node<E> node) {
if (node == null) {
return null;
}
if (node.next == null) {
return node;
}
Node<E> next = node.next;
node.next = null;
Node<E> result = reverseRecursion(next);
next.next = node;
return result;
}
上述代码简单实现了基于单向链表实现的线性表的一些细节。单向链表实现的线性表,不需要扩容操作;引入了虚拟头结点,使各方法在实现逻辑上会更加统一;引入了尾节点tail,使得对单链表的部分尾部操作性能显著提升(O(n) -> O(1)),可显著提升基于单向链表实现的其他数据结构的性能(如队列、栈等,后续会介绍)。
除了上述单向链表,还有其他的实现方式,常见的有循环单向链表、双向链表、循环双向链表。其中,LinkedList集合类的实现就是双向链表。
复杂度分析
- 增:add – O(n)、addFirst 和 addLast(tail实现) – O(1)
- 删:remove – O(n)、removeFirst – O(1)
- 改:set – O(n)、setFirst 和 setLast(tail实现) – O(1)
- 查:get – O(n)、getFirst 和 getLast(tail实现) – O(1)
可以看出,基于单链表实现的线性表结构,特点是:中间操作慢、首尾操作快。
源码
public class Linked<E> {
private class Node<E> {
private E element;
private Node<E> next;
public Node(E e, Node<E> next) {
element = e;
this.next = next;
}
public Node(E e) {
this(e, null);
}
public Node() {
this(null);
}
@Override
public String toString() {
return element == null ? "null" : element.toString();
}
}
private Node<E> dummyHead;
private Node<E> tail;
private int size = 0;
public Linked(Node<E> node) {
dummyHead = new Node<>();
dummyHead.next = node;
if (node == null) {
tail = dummyHead;
} else {
tail = dummyHead.next;
size++;
}
}
public Linked(E e) {
dummyHead = new Node<>();
dummyHead.next = new Node<>(e);
tail = dummyHead.next;
size++;
}
public Linked() {
dummyHead = new Node<>();
tail = dummyHead;
}
/**
* 在指定索引位置插入元素 O(n)
* 特例:addFirst 和 addLast(tail实现) 为O(1)
*
* @param index
* @param e
*/
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Wrong index: " + index);
}
Node<E> pre = dummyHead;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
pre.next = new Node<>(e, pre.next);
if (index == size) {
tail = pre.next;
}
size++;
}
public void addFirst(E e) {
add(0, e);
}
public void addLast(E e) {
// 复用add方法,则时间复杂度为O(n)
// add(size, e);
// 使用tail节点实现,则时间复杂度为O(1)
tail.next = new Node<>(e);
tail = tail.next;
size++;
}
/**
* 删除指定位置的元素 O(n)
* 特例:removeFirst为O(1)
*
* @param index
*/
public void remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Wrong index: " + index);
}
Node<E> pre = dummyHead;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
if (index == size - 1) {
tail = pre;
}
// 使del节点能被JVM正常GC
Node<E> del = pre.next;
pre.next = del.next;
del.next = null;
size--;
}
public void removeFirst() {
remove(0);
}
public void removeLast() {
remove(size - 1);
}
/**
* 更改指定索引位置的元素 O(n)
* 特例:setFirst 和 setLast(tail实现) 为O(1)
*
* @param index
* @param e
*/
public void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Wrong index: " + index);
}
Node<E> cur = dummyHead.next;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.element = e;
}
public void setFirst(E e) {
set(0, e);
}
public void setLast(E e) {
// 复用add方法,则时间复杂度为O(n)
// set(size - 1, e);
// 使用tail节点实现,则时间复杂度为O(1)
tail.element = e;
}
/**
* 查询指定索引位置的元素 O(n)
* 特例:getFirst 和 getLast(tail实现) 为O(1)
*
* @param index
* @return
*/
public E get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Wrong index: " + index);
}
Node<E> cur = dummyHead.next;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
return cur.element;
}
public E getFirst() {
return get(0);
}
public E getLast() {
return tail.element;
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
/**
* 查询链表是否包含某个元素,如果包含返回索引,如果不包含返回-1 O(n)
*
* @param e
* @return
*/
public int contains(E e) {
if (e == null) {
return -1;
}
Node<E> cur = dummyHead.next;
for (int i = 0; i < size; i++) {
if (e.equals(cur.element)) {
return i;
}
cur = cur.next;
}
return -1;
}
/**
* 反向打印链表,递归思想
*/
public void printDesc() {
System.out.print("Linked tail[Null");
printDesc(dummyHead.next);
System.out.println("]head");
}
private void printDesc(Node<E> head) {
if (head != null) {
printDesc(head.next);
System.out.print("<-" + head.element);
}
}
public String toStringDesc(String before, String after) {
StringBuilder sb = new StringBuilder();
String middle = toStringDesc(dummyHead.next);
if (middle.endsWith(", ")) {
middle = middle.substring(0, middle.length() - 2);
}
sb.append(before).append("[").append(middle).append("]").append(after);
return sb.toString();
}
private String toStringDesc(Node<E> head) {
StringBuilder sb = new StringBuilder();
if (head != null) {
sb.append(toStringDesc(head.next));
sb.append(head.element);
sb.append(", ");
}
return sb.toString();
}
/**
* 反转链表
*/
public void reverse() {
// 非递归(效率高)
dummyHead.next = reverse(dummyHead.next);
// 递归
// dummyHead.next = reverseRecursion(dummyHead.next);
}
private Node<E> reverse(Node<E> head) {
Node<E> pre = null;
Node<E> cur = head;
Node<E> next = null;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 递归实现
private Node<E> reverseRecursion(Node<E> node) {
if (node == null) {
return null;
}
if (node.next == null) {
return node;
}
Node<E> next = node.next;
node.next = null;
Node<E> result = reverseRecursion(next);
next.next = node;
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Linked head[");
Node<E> cur = dummyHead;
while (cur.next != null) {
cur = cur.next;
sb.append(cur.element).append("->");
}
sb.append("NULL").append("]tail");
// sb.append(size);
return sb.toString();
}
}