- 写在前面:记录学习《恋上数据结构与算法》的过程。
- 课程链接地址:https://ke.qq.com/course/385223
目录
双向链表
获取index位置对应的节点对象
清空 clear
添加 add(int index , E element)
- 一般情况
- 头部插入
- 尾部插入
- 只有一个元素
删除 remove(int index)
重写toString
代码
package com.mj; import com.mj.AbstractList; public class LinkedList<E> extends AbstractList<E> { private Node<E> first; private Node<E> last; private static class Node<E> { E element; Node<E> prev; Node<E> next; public Node(Node<E> prev, E element, Node<E> next) { this.prev = prev; this.element = element; this.next = next; } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (prev != null) { sb.append(prev.element); } else { sb.append("null"); } sb.append("_").append(element).append("_"); if (next != null) { sb.append(next.element); } else { sb.append("null"); } return sb.toString(); } } @Override public void clear() { size = 0; first = null; last = null; } @Override public E get(int index) { return node(index).element; } @Override public E set(int index, E element) { Node<E> node = node(index); E old = node.element; node.element = element; return old; } @Override public void add(int index, E element) { rangeCheckForAdd(index); // size == 0 // index == 0 if (index == size) { // 往最后面添加元素 Node<E> oldLast = last; last = new Node<>(oldLast, element, null); if (oldLast == null) { // 这是链表添加的第一个元素 first = last; } else { oldLast.next = last; } } else { Node<E> next = node(index); Node<E> prev = next.prev; Node<E> node = new Node<>(prev, element, next); next.prev = node; if (prev == null) { // index == 0 first = node; } else { prev.next = node; } } size++; } @Override public E remove(int index) { rangeCheck(index); Node<E> node = node(index); Node<E> prev = node.prev; Node<E> next = node.next; if (prev == null) { // index == 0 first = next; } else { prev.next = next; } if (next == null) { // index == size - 1 last = prev; } else { next.prev = prev; } size--; return node.element; } @Override public int indexOf(E element) { if (element == null) { Node<E> node = first; for (int i = 0; i < size; i++) { if (node.element == null) return i; node = node.next; } } else { Node<E> node = first; for (int i = 0; i < size; i++) { if (element.equals(node.element)) return i; node = node.next; } } return ELEMENT_NOT_FOUND; } /** * 获取index位置对应的节点对象 * @param index * @return */ private Node<E> node(int index) { rangeCheck(index); if (index < (size >> 1)) { Node<E> node = first; for (int i = 0; i < index; i++) { node = node.next; } return node; } else { Node<E> node = last; for (int i = size - 1; i > index; i--) { node = node.prev; } return node; } } @Override public String toString() { StringBuilder string = new StringBuilder(); string.append("size=").append(size).append(", ["); Node<E> node = first; for (int i = 0; i < size; i++) { if (i != 0) { string.append(", "); } string.append(node); node = node.next; } string.append("]"); return string.toString(); } }
单元测试
双向链表 VS 单向链表
双向链表 VS 动态数组
- 有了双向链表,单向链表是否就没有任何用处了?
- 并非如此,在哈希表的设计中就用到了单链表。后面讲解。
源码分析clear
单向循环链表
- 只有一个节点
- 添加元素 add(int index, E element)
- 删除元素 remove(int index)
双向循环链表
添加元素
- 只有一个节点
删除元素
案例练习:约瑟夫问题
静态链表
ArrayList优化思路
- 删除首元素
- 添加首元素