我们都知道数据结构有顺序的和跳跃的,而链表就是一种跳跃,不是用顺序实现的,它是用指针实现,在内存中不连续。意思就是说,链表就是将一系列不连续的内存联系起来,将那种碎片内存进行合理的利用,解决空间的问题。链表有单向的,双向的。但是一般单向的链表是作为面试考察中最重要的一种,接下来我们通过本章节可以简单了解下单向链表的实现原理和一些考察的知识点。
手写链表
我们通过一个List,包含简单增删改查,来熟悉下链表的结构。
首先定义下List的简单节点,包括一个头节点head和一个静态内部类Node:
public class List<T> {
static class Node<T> {
Node<T> next = null;
T data;
public Node(T data){
this.data = data;
}
}
Node<T> head = null;
}
接下来我们来实现下这个链表的插入,很简单我们通过头节点插入:
public void insert(T data) {
Node node=new Node(data);
node.next=head;
head=node;
}
实现单向链表的删除和查找
public Node<T> find(Predicate<T> predicate) {
Node<T> p = head;
while (p != null) {
if (predicate.test(p.data)) {
return p;
}
p = p.next;
}
return null;
}
public void remove(Node<T> node){
if(node==null) return;
Node<T> prev=null;
Node<T> next=head;
while(next!=null){
if(next==node){
prev.next=next.next;
}
prev=next;
next=next.next;
}
}
删除我们需要解决的问题是找到待删除节点后,将此节点的前置节点指向它的后置节点。问题是我们不知道它的前置节点,所以需要我们来通过一个变量来保存它的前置节点。
链表的反转
有个问题是我们如何实现链表的反转,形成如下新链表:
其实实现方式有很多种,比如可以通过设置一个新的链表来接收,然后形成反转,我们可以通过设置三个变量或递归来实现,以下是几种实现方式
通过设置变量来实现:
public void reverse(){
if(head==null||head.next==null) {
return;
}
// 通过设置 prev | current | next变量来实现
// 1->2->3
Node<T> prev=null;
Node<T> current=head;
Node<T> next=head.next;
while(current!=null){
current.next=prev;
prev=current;
current=next;
if(next!=null) {
next = next.next;
}
}
head=p
通过递归来实现:
private Node<T> _reverse2(Node<T> head) {
if(head == null || head.next == null) {
return head;
}
// 通过递归来实现1->2->3
Node rest=_reverse2(head.next);
head.next.next=head;
head.next=null;
return rest;
}