链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:



无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如 哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。
无头单向链表的每一个节点有两个属性,分别是值val和存储下一个节点的地址。 我们来回顾内部类的定义:当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服 务,那么这个内部的完整结构最好使用内部类 这里我们把每个节点定义为内部类正合适
static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public ListNode head;//定义头节点此时的head:

注:这里的next中存储的下一个节点的位置,所以类型是ListNode; 使用构造方法初始化的时候,仅仅初始化val的值,next节点默认为null
这里我们模拟实现的是无头单向非循环链表
// 1、无头单向非循环链表实现
public class SingleLinkedList {
//头插法
public void addFirst(int data){
}
//尾插法
public void addLast(int data){
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
return false;
}
//删除第一次出现关键字为key的节点
public void remove(int key){
}
//删除所有值为key的节点
public void removeAllKey(int key){
}
//得到单链表的长度
public int size(){
return -1;
}
public void clear() {
}
public void display() {}
}解析: 假设有这样一组链表,我们想把node节点添加到该链表的头节点

实现效果:

public void addFirst(int val) {
ListNode node = new ListNode(val);
node.next = head;
head = node;
}解析: 实现效果:

思路:
操作:
public void addLast(int val) {
ListNode cur = head;
ListNode node = new ListNode(val);
if(head == null) {
head = node;
return;
}
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}此方法实现在任意位置插入节点

实现效果:

思路:
操作:
public void addIndex(int index, int val) {
//1.判断合法性
try {
checkIndex(index);
}catch (IndexNotLegalException e) {
e.printStackTrace();
}
//2.index == 0 || index == size()
if(index == 0) {
addFirst(val);
return;
}
if(index == size()) {
addLast(val);
return;
}
//找到前一个结点
ListNode cur = findIndexSubOne(index);
//4. 进行连接
ListNode node = new ListNode(val);
node.next = cur.next;
cur.next = node;
}
private ListNode findIndexSubOne(int index) {
ListNode cur = head;
int count = 0;
while (count != index-1) {
cur = cur.next;
count++;
}
return cur;
}
private void checkIndex(int index) throws IndexNotLegalException{
if(index < 0 || index > size()) {
throw new IndexNotLegalException("index不合法");
}
}IndexNotLegalException.java 文件
public class IndexNotLegalException extends RuntimeException {
public IndexNotLegalException() {
}
public IndexNotLegalException(String message) {
super(message);
}
}此方法判断链表中是否包含val值,包含则返回true,否则返回false 思路:
操作:
public boolean contains(int val) {
ListNode cur = head;
while (cur != null) {
if (cur.val == val) {
return true;
}
cur = cur.next;
}
return false;
}此方法是删除第一次出现关键字为val的节点 实现效果:

思路:
操作:

public void remove(int val) {
if(head == null) {
return;
}
if(head.val == val) {
head = head.next;
return;
}
ListNode cur = head;
while (cur.next != null) {
if (cur.next.val == val) {
ListNode del = cur.next;
cur.next = del.next;
return;
}
cur = cur.next;
}
}此方法是删除所有出现关键字为val的节点 操作:




先将头节点以外的删除再来考虑头节点位置即可 if(head.val == val) { head = head.next; }

也可先考虑头节点的情况,while循环判断

public void removeAllKey(int val) {
//1. 判空
if (head == null) {
head = head.next;
}
//2. 定义prev 和 cur
ListNode prev = head;
ListNode cur = head.next;
//3.开始判断并且删除
while (cur != null) {
if (cur.val == val) {
//找到了
prev.next = cur.next;
} else {
prev = cur;
}
cur = cur.next;
}
//4.处理头节点
if(head.val == val) {
head = head.next;
}
}遍历链表,用count计数即可
public int size() {
int count = 0;
ListNode cur = head;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}将每一个节点的next置空即可,注意这里需要单独把头节点置空
public void clear() {
ListNode cur = head;
while (cur != null) {
ListNode curN = cur.next;
//cur.val = null;
cur.next = null;
cur = curN;
}
head = null;
}