独立实现双向链表_LinkedList

目录

一、前言:

二、具体方法:

[2.1 addFirst](#2.1 addFirst)

[2.2 display](#2.2 display)

[2.3 size](#2.3 size)

[2.4 contains](#2.4 contains)

[2.5 addLast](#2.5 addLast)

[2.6 addIndex](#2.6 addIndex)

[2.7 remove](#2.7 remove)

[2.8 removeAllKey](#2.8 removeAllKey)

[2.9 clear](#2.9 clear)


一、前言:

这节课来学习一个重点:LinkedList

要想了解这个,我们很有必要先自己模拟实现一遍其中的方法:

前面我们学习了单向链表,双向链表也就是每个节点多了一个存放上一个节点地址的域,如下图所示:

先来定义一个接口:

java 复制代码
public interface ILinkedList {
    //头插法
    void addFirst(int data);
    
    //尾插法
    void addLast(int data);
    
    //任意位置插入,第一个数据节点为0号下标
    void addIndex(int index, int data);
    
    //查找是否包含关键字key是否在单链表当中
    boolean contains(int key);
    
    //删除第一次出现关键字为key的节点
    void remove(int key);
    
    //删除所有值为key的节点
    void removeAllKey(int key);
    
    //得到单链表的长度
    int size();
    
    void clear();
    
    void display();
}

然后创建一个类来具体实现方法:

java 复制代码
public class MyLinkedList implements ILinkedList{
    @Override
    public void addFirst(int data) {
        
    }

    @Override
    public void addLast(int data) {

    }

    @Override
    public void addIndex(int index, int data) {

    }

    @Override
    public boolean contains(int key) {
        return false;
    }

    @Override
    public void remove(int key) {

    }

    @Override
    public void removeAllKey(int key) {

    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public void clear() {

    }

    @Override
    public void display() {

    }
}

二、具体方法:

要想实现首先得定义一个:双向链表节点的静态内部类

java 复制代码
static class ListNode {
    public int val;
    public ListNode prev;
    public ListNode next;
    
    public ListNode(int val) {
        this.val = val;
    }
    
    public ListNode head;
    public ListNode last;
}

2.1 addFirst

头插法的思路如图:

代码如下:

java 复制代码
@Override
public void addFirst(int data) {
    ListNode node = new ListNode(data);
    if(head == null) {
        head = node;
        last = node;
    }else {
        node.next = head;
        head.prev = node;
        head = node;
    }
}

2.2 display

也就是展示双向链表元素,遍历即可:

java 复制代码
@Override
public void display() {
    ListNode cur = head;
    while (cur != null) {
        System.out.print(cur.val + " ");
        cur = cur.next;
    }
    System.out.println();
}

2.3 size

求链表长度:

java 复制代码
@Override
public int size() {
    int count = 0;
    ListNode cur = head;
    while (cur != null) {
        count++;
        cur = cur.next;
    }
    return count;
}

2.4 contains

java 复制代码
@Override
public boolean contains(int key) {
    ListNode cur = head;
    while (cur != null) {
        if(cur.val == key) {
            return true;  // 找到关键字,返回true
        }
        cur = cur.next;
    }
    return false;  // 遍历完链表没找到,返回false
}

2.5 addLast

在尾巴上插入一个元素:

java 复制代码
@Override
public void addLast(int data) {
    ListNode node = new ListNode(data);
    if(head == null) {
        head = node;
        last = node;
    }else {
        last.next = node;
        node.prev = last;
        last = node;
    }
}

2.6 addIndex

那如果要在双向链表的任意位置插入元素呢?

画图理解思路:

核心代码:

java 复制代码
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;

具体实现代码:

java 复制代码
@Override
public void addIndex(int index, int data) {
    // 1. 检查index的合法性(代码中未完全展示,需自行补充范围判断)

    // 2. 特殊位置处理
    if (index == 0) {
        addFirst(data);
        return;
    }

    if (index == size()) {
        addLast(data);
        return;
    }

    // 3. 中间节点插入逻辑
    ListNode cur = searchIndex(index);
    ListNode node = new ListNode(data);

    node.next = cur;
    cur.prev.next = node;
    node.prev = cur.prev;
    cur.prev = node;
}

private ListNode searchIndex(int index) {
    ListNode cur = head;
    while (index != 0) {
        cur = cur.next;
        index--;
    }
    return cur;
}

2.7 remove

如何删除节点呢,来看看画好的思路图:

也就是需要先找到要删除的那个节点,然后进行删除。

代码实现如下:

java 复制代码
@Override
public void remove(int key) {
    ListNode cur = head;
    while (cur != null) {

        if (cur.val == key) {
            // 开始删除
            if (cur == head) {
                // 删除的节点是头节点
                head = head.next;
                head.prev = null;
            } else {             
                // 删除的节点不是头节点
                if (cur.next == null) {
                    // 删除尾巴节点
                    cur.prev.next = cur.next;
                    last = last.prev;
                } else {
                    // 删除中间节点
                    cur.next.prev = cur.prev;
                    cur.prev.next = cur.next;
                }
            }
            return;
        }
        cur = cur.next;
    }
}

代码也可以写成:

java 复制代码
@Override
public void remove(int key) {
    ListNode cur = head;
    while (cur != null) {

        if (cur.val == key) {
            // 开始删除
            if (cur == head) {
                // 删除的节点是头节点
                head = head.next;
                head.prev = null;
            } else {
                cur.prev.next = cur.next;
                // 删除的节点不是头节点
                if (cur.next == null) {
                    // 删除尾巴节点
                    last = last.prev;
                } else {
                    // 删除中间节点
                    cur.next.prev = cur.prev;
                }
            }
            return;
        }
        cur = cur.next;
    }
}

2.8 removeAllKey

这个理解了2.7那就好做了,把2.7的代码中将 return关键字 删除即可!

代码:

java 复制代码
@Override
public void remove(int key) {
    ListNode cur = head;
    while (cur != null) {

        if (cur.val == key) {
            // 开始删除
            if (cur == head) {
                // 删除的节点是头节点
                head = head.next;
                head.prev = null;
            } else {
                cur.prev.next = cur.next;
                // 删除的节点不是头节点
                if (cur.next == null) {
                    // 删除尾巴节点
                    last = last.prev;
                } else {
                    // 删除中间节点
                    cur.next.prev = cur.prev;
                }
            }
            //return;
        }
        cur = cur.next;
    }
}

2.9 clear

清空链表:

java 复制代码
@Override
public void clear() {
    ListNode cur = head;
    while (cur != null) {
        ListNode curN = cur.next;
        cur.prev = null;
        cur.next = null;
        cur = curN;
    }
    head = null;
    last = null;
}

三、认识Java自带的LinkedList类

还是将这上面这幅图拿出来,LinkedList实现了List这个接口。所以可以如下图所示实现多态,父类引用指向子类对象:

LinkedList的底层是使用了双向链表的。

3.1 构造方法:

3.2 LinkedList其他常用方法介绍:

3.3 重要:LinkedList的遍历

for循环,foreach循环,Iterator迭代器,ListIterator反向迭代器:

java 复制代码
public static void main(String[] args) {
    LinkedList<Integer> list = new LinkedList<>();
    list.add(10);
    list.add(9);
    list.add(99);
    for (int i = 0; i < list.size(); i++) {
        System.out.print(list.get(i) + " ");
    }
    System.out.println();
    System.out.println("==========");

    for (Integer x : list) {
        System.out.print(x + " ");
    }
    System.out.println();
    System.out.println("==========");

    Iterator<Integer> it = list.iterator();
    while (it.hasNext()) {
        System.out.print(it.next() + " ");
    }
    System.out.println();
    System.out.println("==========");

    ListIterator<Integer> listIterator2 = list.listIterator(list.size());
    while (listIterator2.hasPrevious()) {
        System.out.print(listIterator2.previous() + " ");
    }
    System.out.println();
    System.out.println("==========");
}

3.4 ArrayList与LinkedList的区别

这里我直接放一张图在这里:

上图非常清晰了

相关推荐
·薯条大王5 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
白狐_7987 小时前
408数据结构第5章:二叉树遍历序列题——技巧、判断与真题型总结
数据结构
ZJH__GO8 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
程序员黑豆8 小时前
Windows 系统 Java 环境变量配置全攻略:解决“不是内部或外部命令”
java·前端·ai编程
命运之光9 小时前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
凤山老林9 小时前
Spring Boot @Async 线上实战:从默认配置到生产级线程池治理
java·spring boot·后端
Forever Nore9 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
marvelyu10 小时前
每天10分钟学会OceanBase系列(Day 20):跨机房容灾实战——构建多数据中心高可用架构
java·大数据·数据库
AI人工智能+电脑小能手11 小时前
大白话说Java设计模式-04-工厂方法模式(业务实战篇)
java·设计模式·工厂方法模式·架构设计·代码解耦
BUG指挥官11 小时前
Sa-Token和Spring Security对比
java·后端·spring