1、概念
鏈表是一種將一組不連續的內存塊串聯起來起來使用的線性表,其中內存塊稱爲鏈表的結點,記錄下個結點地址的“指針”稱爲後繼指針,雙鏈表中還有記錄上個結點地址的“指針”稱爲前驅指針
2、特點
2.1、空間結構
單鏈表 | 循環鏈表 | 雙向鏈表 | |
---|---|---|---|
結構 | 尾結點指針指向空地址null | 尾結點指針向頭結點 | 後繼指針指向後面的結點 前驅指針指向前面的結點 |
空間 | 結點數據、下一個元素的地址(尾結點爲null) | 結點數據、下一個元素的地址(尾結點爲第一個元素的地址) | 上一個元素的地址、結點數據、下一個元素的地址 |
2.2、高效的插入和刪除,低效的隨機訪問
插入和刪除的時間複雜度:O(1)
訪問的時間複雜度:O(n)
3、鏈表和數組對比
3.1、鏈表優勢
插入刪除高效
無拷貝的動態擴容
3.2、數組優勢
隨機訪問高效
內存佔用小
4、其他
4.1、手撕LinkedList
package com.company;
import java.util.NoSuchElementException;
/**
* 功能描述:
*
* @author liuchaoyong
* @version 1.0
* @date 2020/1/15 14:45
*/
public class MyLinkedList<E> {
/**
* 鏈表長度
*/
transient int size = 0;
/**
* 哨兵結點(頭),指向鏈表頭結點
*/
transient Node<E> first;
/**
* 哨兵結點(尾),指向鏈表尾結點
*/
transient Node<E> last;
public MyLinkedList() {
}
/**
* 獲取鏈表頭結點(爲空拋異常)
*/
public E getFirst() {
final Node<E> f = first;
if (f == null) {
throw new NoSuchElementException();
}
return f.item;
}
/**
* 獲取鏈表尾結點(爲空拋異常)
*/
public E getLast() {
final Node<E> l = last;
if (l == null) {
throw new NoSuchElementException();
}
return l.item;
}
/**
* 移除鏈表頭結點
*/
public E removeFirst() {
final Node<E> f = first;
if (f == null) {
throw new NoSuchElementException();
}
return unlinkFirst(f);
}
/**
* 移除鏈表尾結點
*/
public E removeLast() {
final Node<E> l = last;
if (l == null) {
throw new NoSuchElementException();
}
return unlinkLast(l);
}
/**
* 將元素添加至鏈表頭結點
*/
public void addFirst(E element) {
linkedFirst(element);
}
/**
* 將元素添加至鏈表尾結點
*/
public void addLast(E element) {
linkedLast(element);
}
/**
* 鏈表中是否包含某元素
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
}
/**
* 獲取鏈表擁有元素個數
*/
public int size() {
return size;
}
/**
* 將元素添加至鏈表尾結點,返回執行結果
*/
public boolean add(E element) {
addLast(element);
return true;
}
/**
* 從鏈表中移除指定元素
*/
public boolean remove(Object o) {
if (o == null) {
for (Node<E> node = first; node != null; node = node.next) {
if (node.item == null) {
unlink(node);
return true;
}
}
} else {
for (Node<E> node = first; node != null; node = node.next) {
if (o.equals(node.item)) {
unlink(node);
return true;
}
}
}
return false;
}
/**
* 獲取元素頭次出現的位置
*/
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> node = first; node != null; node = node.next) {
if (node.item == o) {
return index;
}
index++;
}
} else {
for (Node<E> node = first; node != null; node = node.next) {
if (o.equals(node.item)) {
return index;
}
index++;
}
}
return -1;
}
/**
* 獲取元素最後一次出現的位置
*/
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> node = last; node != null; node = node.prev) {
if (node.item == o) {
return index;
}
index--;
}
} else {
for (Node<E> node = last; node != null; node = node.prev) {
if (o.equals(node.item)) {
return index;
}
index--;
}
}
return -1;
}
/**
* 清空鏈表元素
*/
public void clear() {
for (Node<E> x = first; x != null; ) {
final Node<E> next = x.next;
x.prev = null;
x.item = null;
x.next = null;
x = next;
}
first = last = null;
size = 0;
}
/**
* 獲取鏈表某位置元素
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
/**
* 替換鏈表中指定位置的元素,並返回舊元素
*/
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E item = x.item;
x.item = element;
return item;
}
/**
* 向鏈表指定位置添加元素(範圍爲:鏈表頭~鏈表尾)
*/
public void add(int index, E element) {
checkPositionIndex(index);
Node<E> node = node(index);
Node<E> prev = node.prev;
Node<E> newNode = new Node<>(prev, element, node);
if (prev == null) {
first = newNode;
} else {
node.prev = newNode;
}
size++;
}
/**
* 移除鏈表指定位置元素
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
/**
* 獲取鏈表頭結點(爲空返空)
*/
public E peek() {
Node<E> first = this.first;
return (first == null) ? null : first.item;
}
/**
* 獲取鏈表頭結點(爲空拋異常),同getFirst()
*/
public E element() {
return getFirst();
}
/**
* 移除鏈表頭結點(爲空返空)
*/
public E poll() {
Node<E> first = this.first;
return (first == null) ? null : unlink(first);
}
/**
* 移除鏈表頭結點(爲空拋異常),同removeFirst()
*/
public E remove() {
return removeFirst();
}
/**
* 將元素添加至鏈表尾結點(同add)
*/
public boolean offer(E e) {
return add(e);
}
/**
* 將元素添加至鏈表頭結點,返回執行結果
*/
public boolean offerFirst(E e){
addFirst(e);
return true;
}
/**
* 將元素添加至鏈表尾結點,返回執行結果
*/
public boolean offerLast(E e){
addLast(e);
return true;
}
/**
* 獲取鏈表頭結點,同peek()
*/
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
/**
* 獲取鏈表尾結點
*/
public E peekLast(){
final Node<E> f = last;
return (f == null) ? null : f.item;
}
/**
* 移除鏈表頭結點
*/
public E pollFirst(){
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
/**
* 移除鏈表尾結點
*/
public E pollLast(){
final Node<E> f = last;
return (f == null) ? null : unlinkLast(f);
}
/**
* 將元素添加至鏈表頭結點,同addFirst()
*/
public void push(E e){
addFirst(e);
}
/**
* 移除鏈表頭結點,同removeFirst()
*/
public void pop(){
removeFirst();
}
/**
* 移除鏈表中第一個包含此元素的結點,返回執行結果
*/
public boolean removeFirstOccurence(Object o){
return remove(o);
}
/**
* 移除鏈表中最後一個包含此元素的結點,返回執行結果
*/
public boolean removeLastOccurence(Object o){
if (o == null) {
for (Node<E> node = last; node != null; node = node.prev) {
if (node.item == null) {
unlink(node);
return true;
}
}
} else {
for (Node<E> node = last; node != null; node = node.prev) {
if (o.equals(node.item)) {
unlink(node);
return true;
}
}
}
return false;
}
private static class Node<E> {
/**
* 上一結點地址(可見LinkedList是一個雙向鏈表)
*/
Node<E> prev;
/**
* 當前結點數據
*/
E item;
/**
* 下一結點地址
*/
Node<E> next;
Node(Node<E> prev, E item, Node<E> next) {
this.prev = prev;
this.item = item;
this.next = next;
}
}
/**
* 鏈接頭結點
*/
private void linkedFirst(E element) {
//備份哨兵結點(頭)
final Node<E> f = first;
//新建一個結點,並將哨兵結點(頭)指向該結點
final Node<E> newNode = new Node<>(null, element, f);
first = newNode;
//如果原來的頭結點爲null,說明鏈表爲空,此時添加的結點,既是頭結點又是尾結點,所以將哨兵結點(尾)指向該結點
//否則之前鏈表中已有數據,將原頭結點(也就是備份的哨兵結點(頭))的前驅指針指向新的頭結點
if (f == null) {
last = newNode;
} else {
f.prev = newNode;
}
size++;
}
/**
* 鏈接尾結點
*/
private void linkedLast(E element) {
//備份哨兵結點(尾)
final Node<E> l = last;
//新建一個結點,並將哨兵結點(尾)指向該結點
final Node<E> newNode = new Node<>(l, element, null);
last = newNode;
//如果原來的尾結點爲null,說明鏈表爲空,此時添加的結點,既是尾結點又是頭結點,所以將哨兵結點(頭)指向該結點
//否則之前鏈表中已有數據,將原尾結點(也就是備份的哨兵結點(尾))的後繼指針指向新的尾結點
if (l == null) {
first = newNode;
} else {
l.next = newNode;
}
size++;
}
/**
* 取消鏈接頭結點
*/
private E unlinkFirst(Node<E> f) {
//備份頭結點數據和下一結點的位置
final E item = f.item;
final Node<E> next = f.next;
//讓GC回收
f.item = null;
f.next = null;
//將哨兵結點(頭)指向下一結點
first = next;
//如果下一結點爲null,說明鏈表只有一個結點,此時要把哨兵結點(尾)也指向null
//否則就將下一結點的前驅指針從原來的結點指向null,表示該結點是頭結點
if (next == null) {
last = null;
} else {
next.prev = null;
}
size--;
return item;
}
/**
* 取消鏈接尾結點
*/
private E unlinkLast(Node<E> l) {
//備份尾結點和上一結點的位置
final E item = l.item;
final Node<E> prev = l.prev;
//讓GC回收
l.item = null;
l.prev = null;
//將哨兵結點(尾)指向上一結點
last = prev;
//如果上一結點爲null,說明鏈表只有一個結點,此時要把哨兵結點(頭)也指向null
//否則就將上一結點的後繼指針從原來的結點指向null,表示該結點是尾結點
if (prev == null) {
first = null;
} else {
prev.next = null;
}
size--;
return item;
}
/**
* 取消鏈接前驅結點和後繼結點
*/
E unlink(Node<E> x) {
//final保證變量不變
final E item = x.item;
final Node<E> prev = x.prev;
final Node<E> next = x.next;
//如果該結點的前驅結點爲空,說明該結點是鏈表頭結點,此時將哨兵頭結點指向該結點
//否則就將上一個結點的後繼結點指向該結點的後繼結點,並釋放該結點的前驅結點
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
//如果該結點的後繼結點爲空,說明該結點是鏈表尾結點,此時將哨兵尾結點指向該結點
//否則就將下一個即誒點的前驅結點指向該結點的前驅結點,並釋放該結點的後繼結點
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
size--;
return item;
}
/**
* 下標越界檢查(for set)
*/
private void checkElementIndex(int index) {
if (!(index >= 0 && index < size)) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
/**
* 下標越界檢查(for add)
*/
private void checkPositionIndex(int index) {
if (!(index >= 0 && index <= size)) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
/**
* 獲取指定下標結點
*/
Node<E> node(int index) {
//如果下標小於鏈表大小的一般,說明靠近頭結點,從頭結點遍歷
//否則從尾結點遍歷
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--) {
x = x.prev;
}
return x;
}
}
}