Java实现单链表

一、IList

IList 是一个链表操作规范接口,它只规定要实现什么函数,具体实现内容在别的地方,代码如下。

java 复制代码
public interface IList {
    void addFirst(int data);
    void addLast(int data);
    void addIndex(int index,int data);
    boolean contains(int key);
    void remove(int key);
    void removeAllKey(int key);
    int size();
    void clear();
    void display();
}

二、MySingleList

MySingleList是一个单链表实现类,实现了接口 IList 中规定的所有操作功能,包括头插、尾插、任意位置插入、查找、删除、统计长度、清空和遍历等。内部使用 ListNode 节点类,通过 next 指针把节点串成一条链。代码如下。

java 复制代码
public class MySingleList implements IList{

    static class ListNode{
        public int val;
        public ListNode next;

        public ListNode(int val){
            this.val=val;
        }
    }

    public ListNode head;

    public void creatList(){

        ListNode node1=new ListNode(12);
        ListNode node2=new ListNode(23);
        ListNode node3=new ListNode(34);
        ListNode node4=new ListNode(45);
        ListNode node5=new ListNode(56);

        node1.next=node2;
        node2.next=node3;
        node3.next=node4;
        node4.next=node5;

        this.head=node1;
    }
    @Override
    public void addFirst(int data) {
        ListNode node=new ListNode(data);
        if(this.head==null)
        {
            this.head=node;
        }else {
            node.next=this.head;
            this.head=node;
        }
    }

    @Override
    public void addLast(int data) {
        ListNode node=new ListNode(data);
        ListNode cur=this.head;
        if(this.head==null){
            this.head=node;
        }else{
            while(cur.next!=null){
                cur=cur.next;
            }
            cur.next=node;
        }
    }

    private ListNode searchPrev(int index){
        ListNode cur=this.head;
        int count=0;
        while(count!=index-1)
        {
            cur=cur.next;
            count++;
        }
        return cur;
    }
    @Override
    public void addIndex(int index, int data) {
        if(index<0||index>size()){
            return;
        }
        if(index==0){
            addFirst(data);
            return;
        }
        if(index==size()){
            addLast(data);
            return;
        }
        ListNode cur=searchPrev(index);
        ListNode node=new ListNode(data);
        node.next=cur.next;
        cur.next=node;
    }

    @Override
    public boolean contains(int key) {
        ListNode cur=this.head;
        while(cur!=null)
        {
            if(cur.val==key){
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

    private ListNode findPrev(int key){
        ListNode cur=this.head;
        while(cur.next!=null){
            if(cur.next.val==key){
                return cur;
            }
            cur=cur.next;
        }
        return null;
    }

    @Override
    public void remove(int key) {
        if(this.head==null){
            return;
        }
        if(this.head.val==key){
            this.head=this.head.next;
            return;
        }
        ListNode cur=findPrev(key);
        if (cur == null) {
            System.out.println("没找到");
            return;
        }
        ListNode del=cur.next;
        cur.next=del.next;
    }


    @Override
    public void removeAllKey(int key) {
        if(this.head==null){
            return;
        }
        if(head.val==key){
            head=head.next;
        }
        ListNode prev=head;
        ListNode cur=head.next;
        while(cur!=null){
            if(cur.val==key){
                prev.next=cur.next;
                cur=cur.next;
            }else{
                prev=cur;
                cur=cur.next;
            }
        }
    }

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

    @Override
    public void clear() {
        ListNode cur=head;
        while(cur!=null){
            ListNode curNext=cur.next;
            cur.next=null;
            cur=curNext;
        }
        head=null;
    }

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

creatList()通过手动创建多个节点对象,然后用 next 指针把它们依次连接起来,这样可以快速得到一条固定数据的链表。

addFirst(int data)用于头插新节点。首先创建一个新节点,如果链表为空,直接让 head 指向该节点即可;如果链表不为空,就先让新节点的 next 指向当前头节点,再让 head 指向新节点,这样新节点就成为新的第一个节点。

addLast(int data)用于尾插新节点。先创建新节点,如果链表为空,直接让 head 指向它;如果不为空,就从头节点开始遍历,找到最后一个节点,再让这个节点的 next 指向新节点,从而把新节点接到链表末尾。

searchPrev(int index)这个私有方法用于查找指定下标位置的前一个节点。从头节点开始遍历,用计数器记录当前位置,当计数器等于 index - 1 时停止,此时返回的节点正好是目标插入位置的前驱节点。

addIndex(int index, int data)该方法用于在指定下标位置插入新节点。首先判断下标是否合法,如果非法直接返回;如果插入位置是 0,就调用 addFirst();如果插入位置是链表长度,就调用 addLast();否则通过 searchPrev(index) 找到前驱节点,再把新节点插入到前驱节点与其后继节点之间。

contains(int key)该方法用于判断链表中是否存在指定值。从头节点开始遍历链表,只要发现某个节点的值等于 key,就立即返回 true;如果遍历完整个链表仍未找到,则返回 false

findPrev(int key)这个私有方法用于查找第一个值为 key 的节点的前驱节点。从头节点开始遍历,如果发现 cur.next.val == key,就返回当前节点 cur;如果遍历到尾部仍未找到,则返回 null,表示链表中不存在该值。

remove(int key)该方法用于删除链表中第一次出现的指定值节点。若链表为空直接返回;如果头节点的值等于 key,则直接让 head 指向第二个节点完成删除;否则通过 findPrev(key) 找到目标节点的前驱节点,然后让该前驱节点跳过目标节点,即 cur.next = cur.next.next,从而完成删除。

removeAllKey(int key)该方法用于删除链表中所有值为 key 的节点。先单独处理头节点为 key 的情况,然后使用 prevcur 两个指针遍历链表:当 cur.val == key 时,让 prev.next 指向 cur.next 实现删除;否则两个指针同时向后移动,直到遍历结束。

size()该方法用于统计链表长度。从头节点开始遍历链表,每访问一个节点就让计数器加一,直到遍历到 null,最终返回计数值,即链表中节点的个数。

clear()该方法用于清空链表。通过遍历链表,将每个节点的 next 置为 null,断开节点之间的引用关系,最后将 head 置为 null,使链表恢复为空状态。

display()该方法用于输出链表中所有节点的值。从头节点开始遍历,每访问一个节点就打印其 val,直到遍历结束并换行,用于直观查看链表当前结构。

三、Test

下面是测试代码。

java 复制代码
public class Test {
    public static void main(String[] args) {
        MySingleList list = new MySingleList();

        System.out.println("=== 1. 测试 creatList ===");
        list.creatList();
        list.display();   // 12 23 34 45 56

        System.out.println("=== 2. 测试 addFirst ===");
        list.addFirst(100);
        list.display();   // 100 12 23 34 45 56

        System.out.println("=== 3. 测试 addLast ===");
        list.addLast(200);
        list.display();   // 100 12 23 34 45 56 200

        System.out.println("=== 4. 测试 addIndex ===");
        list.addIndex(3, 999);
        list.display();   // 100 12 23 999 34 45 56 200

        System.out.println("=== 5. 测试 contains ===");
        System.out.println(list.contains(34));   // true
        System.out.println(list.contains(888));  // false

        System.out.println("=== 6. 测试 remove ===");
        list.remove(100);   // 删头
        list.display();
        list.remove(999);   // 删中间
        list.display();
        list.remove(200);   // 删尾
        list.display();

        System.out.println("=== 7. 测试 removeAllKey ===");
        list.addLast(34);
        list.addLast(34);
        list.display();
        list.removeAllKey(34);
        list.display();

        System.out.println("=== 8. 测试 size ===");
        System.out.println(list.size());

        System.out.println("=== 9. 测试 clear ===");
        list.clear();
        list.display();   // 空
        System.out.println(list.size()); // 0
    }
}
相关推荐
KJ_BioMed6 分钟前
从PDB到高亲和力分子:De novo生成式计算化学Pipeline剖析
算法·生物医药·生物科研·科研干货·化合物设计
一个王同学1 小时前
从零到一 | CV转多模态大模型 | week17 | LLM 推理优化 & vLLM 详解
人工智能·深度学习·算法·机器学习·计算机视觉·vllm
jimy11 小时前
C语言模拟对象、方法:“函数指针+结构体“复用函数指针指向的函数体
c语言·开发语言
程序员张31 小时前
SpringBoot集成BCrypt密码加密库
java·spring boot·后端
闲猫1 小时前
Spring AI Agentic 模式(第1部分):Agent Skills——模块化、可复用的能力
java·人工智能·spring
源图客1 小时前
云途物流API开发-鉴权认证(Java)
java·网络·python
天外天-亮2 小时前
HBuilder X 使用 uview-plus 方式
开发语言·javascript·hbuilder x·uview-plus
liguojun20252 小时前
篮球馆自动计时收费系统:从规则配置到自动结算的全流程拆解
java·大数据·运维·人工智能·物联网·1024程序员节
木木子222 小时前
[特殊字符] 音乐播放器——状态驱动的多媒体控制
android·开发语言·华为·php·harmonyos
旖-旎2 小时前
《LeetCode 53 最大子数组和 || LeetCode 918 环形子数组的最大和》
c++·算法·leetcode·动态规划