1.什么是链表
什么是链表 链表一种线性的数据结构,将多个结点连接起来,每个结点都存在一个指向下一个结点的next指针。如若是单向列表的话,最末端的那个结点的next指针则指向null;如若是循环链表,最末端结点的next指针则指向head头结点。
2.链表的分类
单链表
- 单链表的每个结点除了存储数据data外,还需要记录下个结点的地址,称为后继指针next。
双向链表
- 双向链表的每个结点在单链表的基础上增加了前驱指针prev,指向上一个结点。
循环列表
- 循环链表仅仅是将单链表最末端的尾结点从指向null改成指向头结点head,进而实现了一个类似环形的结构。
3.创建链表
public class ListNode {
// 节点的值
public int val;
// 下一个节点
public ListNode next;
// 有参构造函数
public ListNode(int val) {
this.val = val;
}
//下面的是结点的get,set方法
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
4.链表的插入
-
如果插入的位置position = 1,则只需将新建结点new的next指针指向当前head所指向的结点,再将head指向新建结点,使得新建结点new变成头结点。
-
如果插入位置position > 1,要先遍历链表到当前position的前一个结点,先要将new结点的next指针指向位于position位置的结点,再将前一个结点的next指针指向新建的new结点,从而使得整个链表重新链接起来。由于java的new Node结点后,改结点的next指针会自动置为null值。所以如果插入的位置是末尾的话,只需遍历到尾结点,后将其的next指针指向new的新结点即可。
/**
* 链表插入
*
* @param head 链表头节点
* @param nodeInsert 待插入节点
* @param position 待插入位置,取值从2开始
* @return 插入后得到的链表头节点
*/
public static Node insertNode(Node head, Node nodeInsert, int position) {
// 需要判空,否则后面可能会有空指针异常
if (head == null) {
return nodeInsert;
}
//越界判断
int size = getLength(head);
if (position > size + 1 || position < 1) {
System.out.println("位置参数越界");
return head;
}
//在链表开头插入
if (position == 1) {
nodeInsert.next = head;
// return nodeInsert;
//上面return还可以这么写:
head = nodeInsert;
return head;
}
Node pNode = head;
int count = 1;
while (count < position - 1) {
pNode = pNode.next;
count++;
}
nodeInsert.next = pNode.next;
pNode.next = nodeInsert;
return head;
}
5.链表的删除
-
删除头结点
- 删除头结点只需将head指针指向当前头结点的next,原本的结点由于访问不到,则会被JVM回收释放掉。
-
删除尾结点
- 遍历链表,找到尾结点的前驱结点,直接将前驱结点的next指针指向null即可。原本的尾结点也会由于访问不到,被JVM回收。
-
删除中间结点
- 也是遍历链表,找到要删除的结点的前驱结点,将前驱结点的next指针指向要删除结点的next即可。
/**
* 删除节点
*
* @param head 链表头节点
* @param position 删除节点位置,取值从1开始
* @return 删除后的链表头节点
*/
public static Node deleteNode(Node head, int position) {
if (head == null) {
return null;
}
int size = getLength(head);
//思考一下,这里为什么是size,而不是size+1
//这里如果是size+1的话,那么position就可以取到size
//后面cur就会为尾结点,使得curNode为尾结点指向的null
//当调用curNode.next时则会出现空指针异常
if (position > size || position <1) {
System.out.println("输入的参数有误");
return head;
}
if (position == 1) {
//curNode就是链表的新head
return head.next;
} else {
Node cur = head;
int count = 1;
while (count < position - 1) {
cur = cur.next;
count++;
}
Node curNode = cur.next;
cur.next = curNode.next;
}
return head;
}