IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> java实现单链表 -> 正文阅读

[数据结构与算法]java实现单链表

目录

  • 单链表的实现
  • ArrayList的缺陷和与单链表的区别

1.单链表的实现

首先我们和ArrayList一样,将MySingleList单独定义为一个Java文件,然后每一个结点我们将它定义成一个静态内部类,这样就方便我们访问结点的成员,,还是和ArrayList一样,我们再定义一个Test类用来测试我们的单链表,写一个函数可以测试一下,这样在最后就不会眼麻手乱了,,

无头单向非循环链表的实现:

1.1MySingleList的大概实现框架

public class MySingleList {
    static class ListNode {
        public int value;
        public ListNode next;

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

    //简单的创建单链表
    public void createList() {
        ListNode listNode1 = new ListNode(23);
        ListNode listNode2 = new ListNode(22);
        ListNode listNode3 = new ListNode(23);

        listNode1.next = listNode2;
        listNode2.next = listNode3;

        this.head = listNode1;
    }

    public ListNode head;
    
    public void addFirst(int data){}
    
    public void addLast(int data){}
    
    public void addIndex(int index,int data){}
    
    public boolean contains(int key){return false;}
    
    public void remove(int key){}
    
    public void removeAllKey(int key){}
    
    public int size(){return -1;}
    
    public void display(){}
    
    public void clear(){}
}

?addFirst--头插

    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        node.next = head;
        head = node;
    }

?头插没啥细节点,以上图做辅助理解,我就不多赘述了,,


?addLast--尾插

//尾插法
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        //1.链表为空
        if(this.head == null) {
            this.head = node;
        }

        //2.链表不为空
        ListNode cur = this.head;
        while(cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
    }

?这里要注意链表为空的时候,只需要将head指向node即可;


addIndex--任意位置插

    public void addIndex(int index,int data) throws MySingleListIndexOutOfException{
        //1.先检查插入位置是否合法
        checkAddIndex(index);
        //2.分两种情况:1.头插 2.中间位置和尾插
        ListNode node = new ListNode(data);
        if(this.head == null) {
            this.head = node;
            return;
        }
        if(index == 0) {
            addFirst(data);
            return;
        }
        ListNode cur = findAddIndexSubOne(index);
        node.next = cur.next;
        cur.next = node;
    }
    private void checkAddIndex(int index) {
        if(index < 0 || index > this.size()) {
            throw new MySingleListIndexOutOfException("任意位置插入时,index不合法!");
        }
    }
    //找到待插入位置的前一个结点
    private ListNode findAddIndexSubOne(int index) {
        ListNode cur = this.head;
        while(index - 1 != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

?任意位置插的注意事项:1.先要判断下标是否合法;2.要分两种情况。


contains--查找

    public boolean contains(int key) {
        if(this.head == null) {
            System.out.println("链表为空!");
            return false;
        }
        ListNode cur = this.head;
        while(cur != null) {
            if(cur.value == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

remove--删除第一次出现的key

//删除第一次出现关键字为key的节点
    public void remove(int key) {
        //1.判断有无结点
        if(this.head == null) {
            System.out.println("链表为空,不能删除!");
            return;
        }

        //2.删第一个
        if(this.head.value == key) {
            this.head = this.head.next;
            return;
        }
        //3.删后面的
        ListNode cur = this.head;
        cur = removeSubOne(key,cur);
        if(cur == null) {
            System.out.println("链表中没有这个元素!");
            return;
        }
        cur.next = cur.next.next;
    }
    private ListNode removeSubOne(int key, ListNode cur) {
        while(cur.next != null) {
            if(cur.next.value == key) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

?

删除函数的注意事项:1.判空? 2.分两种情况:删头和删剩下的,,


?removeAllkey--删除所有key

public void removeAllKey(int key) {
        //1.判断有无结点
        if(this.head == null) {
            System.out.println("链表为空,不能删除!");
            return;
        }
        
        //处理中间和尾巴
        ListNode cur = this.head;
        while(cur != null) {
        //removeSubOne函数在上一个删除方法里头
            cur = removeSubOne(key,cur);
            if(cur != null) {
                cur.next = cur.next.next;
            }
        }
        
        //处理头
        if(this.head.value == key) {
            this.head = this.head.next;
        }

这里的辅助图,跟remove函数类似,,,?

注意事项:(判空和分情况我就不多赘述了)

1.如果先处理头,则需要写成循环,因为当链表所有结点都是待删除的情况时,一个if条件语句处? ? ?理不了

2.while循环里面的条件不能写成cur.next == null,因为removeSubOne函数如果没找到待删除? ? ? ?的结点,它返回的是一个null,如果写成cur.next != null,则可能会报空指针异常


接下来就是几个简单的函数,也很重要,大家都能看得懂:

1.求单链表的长度;2.打印单链表;3.清除单链表

    //得到单链表的长度
    public int size() {
        ListNode cur = this.head;
        int count = 0;
        while(cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }
    public void display() {
        ListNode cur = this.head;
        while(cur != null) {
            System.out.print(cur.value+" ");
            cur = cur.next;
        }
        System.out.println();
    }
    public void clear() {
        this.head = null;
    }

这里说说清除函数,我这种方式是比较暴力,也可以用温柔的方式:

用cur结点保存head的next,然后将head的val和next不断置为0或空,然后两个"指针"不断往后走

?


2.缺陷与区别(ArrayList&LinkedList)

我们之前学了顺序表,但是在某些方面,它存在着许多不足,由于其底层是一段连续的空间,当ArrayList任意位置插入或删除元素的时候,就需要将后续元素整体往前或者往后移动,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入删除比较多的场景,而这些问题链表都可以解决。

区别:

不同点ArrayListLinkedList
存储空间上物理上连续逻辑上连续,物理上不一定连续
随机访问支持O(1)不支持O(N)
头插需要移动元素,效率低O(N)只需要修改引用的指向O(1)
插入空间不够时需要扩容没有容量的概念
应用场景频繁访问+随机存取任意位置插入+频繁删除

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:54:13  更:2022-05-18 17:56:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:22:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码