概念提要
链表:由同类型数据元素构成的有序线性序列,像一条铁链一样,一环接一环。结点和头结点:结点可以认为是一个数据+指向这个数据的指针构成的,多个这样的结点构成了链表,而位于单链表首位的结点称为头结点
虚拟节点:是头结点的前一个结点,称为
dummyNode
,dummyNode.next=head
,也就是说虚拟结点的next
指针指向头结点
-
Java是如何构造出链表的
栈区存引用即指针,堆区存对象
左边栈区存着指向Student对象的地址,根据引用找到右边堆区存储的Student1/2/3/4对象,每个对象结点又存了指向下一个对象的指针,由此构造出一个单链表。
Java当中规范的单向链表应该这样定义:
package ChapterOneListNode;
public class ListNode {
private int data;
private ListNode next;
public ListNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
-
链表增加元素,首部、中间和尾部分别会有什么问题,该如何处理?
向链表中插入新的元素,需要考虑三种情况,链表的头部、身部、尾部。
-
头部插入元素,只需创建一个新的结点再将其连接到原来的链表即可,即
newNode.next = head
,再让head = newNode
,这样头结点就变为新插入的结点 -
在链表中间位置插入,需要找到要插入位置的前面一个节点,给newNode架桥,先让
newNode.next = nextNode
,接着让cur.next = newNode
,桥就架好了
-
- 尾部插入直接将尾结点指向新结点即可,
tailNode.next = newNode
链表插入方法如下:
public static void 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;
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;
}
-
链表删除元素,首部、中间和尾部分别会有什么问题,该如何处理?
链表删除结点也需要考虑头部、身部、尾部三种情况
- 头部删除结点只需要将
head = head.next
即可 - 删除链表中间的结点也需要找到要删除结点的前一个结点位置,然后让
cur.next = cur.next.next
即可 - 删除尾部结点时也需要找到尾部结点的前一个结点,然后判断
cur.next
的值是否为尾部结点的值,如果是,只需要cur.next = null
即可
删除链表节点方法如下:
public static Node deleteNode(Node head, int position) { if (head == null) { return null; } int sizeOfNodeList = getListLength(head); if (position > size || position < 1) { System.out.println("输入的参数有误"); return head; } if (position == 1) { return head.next; } else { Node cur = head; int count = 1; while (count < position-1) { cur = cur.next; count++; } cur.next = cur.next.next; } }
- 头部删除结点只需要将
-
双向链表是如何构造的,如何实现元素的插入和删除
双向链表:和单向链表一样都是通过指针将一个个结点连接起来,和单链表不同的地方在于单链表每个结点的指向只有一个,双向链表每个结点都有两个指针,
prev
和next
双向链表构造如下:
package ChapterOneListNode;
public class DulDirectionListNode {
private int data;
private DulDirectionListNode next;
private DulDirectionListNode prev;
public DulDirectionListNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DulDirectionListNode getNext() {
return next;
}
public void setNext(DulDirectionListNode next) {
this.next = next;
}
public DulDirectionListNode getPrev() {
return prev;
}
public void setPrev(DulDirectionListNode prev) {
this.prev = prev;
}
}
实现元素的插入和删除都需要考虑结点的两个指针指向的改变,基于单向链表的插入和删除再进行双向列表的插入和删除就比较容易理解了,不再赘述。