链表的原理
元素(element) :真实存在于线性表中的内容
节点(node):为了组织链表而引入的一个结构,除了保存元素之外,还会保存只想下一个结点的引用
class Node {
int val; // 保存我们的元素
Node next; // 保存指向下一个结点的引用;其中尾节点的 next == null
}
链表(Listed List):最终的线性表,表示逻辑上的 [1, 2, 3, 4]
当前结点(current / cur): 表示链表中某个结点。
前驱结点(previous / prev): 表示链表中某个结点的前一个结点;头结点没有前驱结点。
后继结点(next): 表示链表中某个结点的后一个结点;尾结点没有后继结点。
链表
链表的节点定义
public class Node {
int val;
Node next;
public Node(int val) {
this.val = val;
this.next = null;
}
@Override
public String toString() {
return "[" + val + "]";
}
}
创建一个链表
不带傀儡节点
Node a = new Node(1);
Node b = new Node(2);
Node c = new Node(3);
Node d = new Node(4);
a.next = b;
b.next = c;
c.next = d;
d.next = null;
return a;
带傀儡节点
public static Node createListWithDummy() {
Node dummy = new Node(0);
Node a = new Node(1);
Node b = new Node(2);
Node c = new Node(3);
Node d = new Node(4);
dummy.next = a;
a.next = b;
b.next = c;
c.next = d;
d.next = null;
return dummy;
}
创建一个空链表
Node head = null;
链表的遍历
不带傀儡节点
public static void print(Node head) {
for (Node cur = head; cur != null; cur = cur.next) {
System.out.println(cur.val);
}
}
带傀儡节点
public static void printWithDummy(Node head) {
for (Node cur = head.next; cur != null; cur = cur.next) {
System.out.println(cur.val);
}
}
遍历链表,找到最后一个元素
Node cur = head;
while (cur != null && cur.next != null){
cur = cur.next;
}
System.out.println(cur.val);
遍历链表,找到到倒数第二个元素
Node cur = head;
while (cur != null && cur.next != null && cur.next.next != null) {
cur = cur.next;
}
System.out.println(cur.val);
取链表的第 N 个节点. (从 1 开始算的)
int n = 1;
Node cur = head;
for (int i = 1; i < n; i++) {
cur = cur.next;
}
System.out.println(cur.val);
遍历链表, 查找链表上是否存在某个元素
int toFind = 10;
Node cur = head;
for (; cur != null; cur = cur.next) {
if (cur.val == toFind) {
break;
}
}
if (cur != null) {
System.out.println("找到了");
} else {
System.out.println("没找到");
}
获取链表的长度
int count = 0;
for (Node cur = head; cur != null; cur = cur.next) {
count++;
}
System.out.println(count);
头插
带傀儡节点
Node newNode = new Node(100);
Node prev = head;
newNode.next = prev.next;
head.next = newNode;
不带傀儡节点
尾插
public static Node insertTail(Node head, int val) {
Node newNode = new Node(val);
if (head == null) {
return newNode;
}
Node cur = head;
while (cur.next != null) {
cur = cur.next;
}
newNode.next = cur.next;
cur.next = newNode;
return head;
}
删除
删除节点, 此处是按照值来删除
public static Node remove(Node head, int val) {
if (head == null) {
return head;
}
if (head.val == val) {
head = head.next;
return head;
}
Node prev = head;
while (prev != null && prev.next != null && prev.next.val != val) {
prev = prev.next;
}
if (prev == null || prev.next == null) {
return head;
}
Node toDelete = prev.next;
prev.next = toDelete.next;
return head;
}
删除节点, 按照位置来删除.
public static Node remove2(Node head, Node toDelete) {
if (head == null) {
return head;
}
if (head == toDelete) {
head = head.next;
return head;
}
Node nextNode = toDelete.next;
toDelete.val = nextNode.val;
toDelete.next = nextNode.next;
return head;
}
给定节点下标来删除
public static Node remove3(Node head, int index) {
if (index < 0 || index > size(head)) {
return head;
}
if (index == 0) {
head = head.next;
return head;
}
Node prev = head;
for (int i = 0; i < index - 1; i++) {
prev = prev.next;
}
Node toDelete = prev.next;
prev.next = toDelete.next;
return head;
}
public static int size(Node head) {
int size = 0;
for (Node cur = head; cur != null; cur = cur.next) {
size++;
}
return size;
}
针对带傀儡节点的链表, 删除指定元素
public static Node removeWithDummy(Node head, int val){
Node prev = head;
while (prev != null && prev.next.val != val) {
prev = prev.next;
}
if (prev == null || prev.next == null) {
return head;
}
Node toDelete = prev.next;
prev.next = toDelete.next;
return head;
}
针对不带傀儡节点的链表, 进行尾删操作
public static Node removeTail(Node head) {
if (head == null) {
return null;
}
if (head.next == null) {
return null;
}
Node prev = head;
Node toDelete = prev.next;
while (prev != null && prev.next != null) {
toDelete =prev.next;
if (toDelete.next == null) {
break;
}
prev = prev.next;
}
prev.next = toDelete.next;
return head;
}