定義
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱爲結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。 相比於線性表順序結構,操作複雜。由於不必須按順序存儲,鏈表在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。
使用鏈表結構可以克服數組鏈表需要預先知道數據大小的缺點,鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。但是鏈表失去了數組隨機讀取的優點,同時鏈表由於增加了結點的指針域,空間開銷比較大。鏈表最明顯的好處就是,常規數組排列關聯項目的方式可能不同於這些數據項目在記憶體或磁盤上順序,數據的存取往往要在不同的排列順序中轉換。鏈表允許插入和移除表上任意位置上的節點,但是不允許隨機存取。鏈表有很多種不同的類型:單向鏈表,雙向鏈表以及循環鏈表。鏈表可以在多種編程語言中實現。像Lisp和Scheme這樣的語言的內建數據類型中就包含了鏈表的存取和操作。程序語言或面嚮對象語言,如C,C++和Java依靠易變工具來生成鏈表。
代碼實現
package com.company;
public class LinkedList<E> {
/**
* 內部類
*/
private class Node {
public E e;
public Node next;
public Node() {
this(null, null);
}
public Node(E e) {
this(e, null);
}
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
@Override
public String toString() {
return e.toString();
}
}
// 虛擬頭結點
private Node dummyHead;
// 節點數量
private int size;
// 構造
public LinkedList() {
dummyHead = new Node(null, null);
size = 0;
}
// 獲取節點數量
public int getSize() {
return size;
}
// 是否爲空
public boolean isEmpty() {
return size == 0;
}
// 頭插法添加節點
public void addFirst(E e) {
add(0, e);
}
// 插入節點
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed.Ill index.");
}
Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
prev.next = new Node(e, prev.next);
size++;
}
// 尾插法添加節點
public void addLast(E e) {
add(size, e);
}
// 查看頭結點的元素
public E getFirst() {
return get(0);
}
// 查看節點元素
public E get(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed.Ill index.");
}
Node cur = dummyHead;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
return cur.e;
}
// 查看尾節點的元素
public E getLast() {
return get(size - 1);
}
// 修改節點的元素
public void set(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed.Ill index.");
}
Node cur = dummyHead;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.e = e;
}
// 刪除頭結點
public E removeFirst() {
return remove(0);
}
// 刪除節點
public E remove(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Remove failed.Ill index.");
}
Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
Node delNode = prev.next;
prev.next = delNode.next;
E ret = delNode.e;
delNode = null;
size--;
return ret;
}
// 刪除尾節點
public E removeLast() {
return remove(size - 1);
}
// 是否存在元素
public boolean contains(E e) {
for (Node cur = dummyHead.next; cur != null; cur = cur.next) {
if (cur.e.equals(e)) {
return true;
}
cur = cur.next;
}
return false;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
Node cur = dummyHead.next;
while (cur != null) {
stringBuilder.append(cur + "->");
cur = cur.next;
}
stringBuilder.append("NULL");
return stringBuilder.toString();
}
}
移除鏈表元素
public class Solution {
public ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val) {
head = head.next;
}
if (head == null) {
return null;
}
ListNode listNode = head;
while (listNode.next != null) {
if (listNode.next.val == val) {
listNode.next = listNode.next.next;
} else {
listNode = listNode.next;
}
}
return head;
}
反轉鏈表
public class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
}
刪除鏈表中的節點
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}