iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java数据结构之单链表的实现与面试题汇总
  • 917
分享到

Java数据结构之单链表的实现与面试题汇总

Java 数据结构 单链表Java 单链表 2022-11-13 18:11:16 917人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录1 单链表1.1 单链表介绍1.2 单链表的实现思路分析1.3 实现代码2 单链表的面试题2.1 统计单链表中有效节点数量2.2 新浪–倒数第k个节点2.3 腾讯&n

1 单链表

1.1 单链表介绍

由于顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它 不要求在逻辑上相邻的两个元素在物理位置上也相邻。

物理结构示意图:

逻辑结构示意图:

关于单链表的一些说明:

  • 链表是以节点的方式存储的,每个节点包含data和next域,分别表示存储的数据和指向下一个节点;
  • 链表的各个节点不一定是连续存储的;
  • 可以根据实际需求来构造是否带有头节点的链表。

1.2 单链表的实现思路分析

1.2.1 单链表的创建与遍历

单链表的创建:

先创建一个 head 头节点,表示单链表的头;

每添加一个节点就直接加入链表的最后;

遍历的思路:

创建一个辅助指针,用于帮助遍历整个链表;

当指针指向的节点的next域为null,说明当前节点为最后一个,遍历完成。 1.2.2 单链表节点的插入与修改

示意图如下:

  • 首先需要通过遍历找到需要添加节点的位置,图中示意的为a1的位置;
  • 新的节点的next指向a1.next;
  • 将该位置,即a1.next指向新的节点。

修改操作相当于上述过程的简化,只需要找到对应的节点直接修改节点对应的属性即可,这里不再赘述。

1.2.3 单链表节点的删除

删除序号为 “2” 的节点示意图如下:

思路如下:

  • 找到待删除节点的前一个节点,示例中则找到序号为1的节点;
  • 让该节点的 temp.next = temp.next.next,即可;
  • 由于被删除的节点没有其他的指向,则会由Java的垃圾回收机制进行回收,无需处理。

1.3 实现代码

StudentNode.java 节点类:


public class Studentnode {
    public String no; //学号
    public String name; //姓名
    public int age; //年龄
    public StudentNode next; //指向下一个节点

    //构造器
    public StudentNode(String no, String name, int age ){
        this.no = no;
        this.name = name;
        this.age = age;
    }

    //为了显示方便
    @Override
    public String toString() {
        return "StudentNode{" +
                "no='" + no + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

StudentLinkedList.java 链表的实现类:


public class StudentLinkedList {
    //初始化头节点
    private StudentNode head = new StudentNode("", "", 0);

	  //获取头节点
    public StudentNode getHead() {
        return head;
    }

    //添加节点
    //1.找到当前链表的最后节点
    //2.将最后节点的next指向新的节点
    public void add(StudentNode studentNode) {
        StudentNode temp = head;
        //遍历链表找到最后的节点
        while (temp.next != null) {
            //没有找到,就后移
            temp = temp.next;
        }
        //最后的节点的next指向新节点
        temp.next = studentNode;
    }

    //遍历 显示链表
    public void showList(){
        //判断链表是否为空
        if (head.next == null){
            System.out.println("当前链表为空");
            return;
        }
        //遍历 使用辅助指针
        StudentNode temp = head;
        while (temp != null){
            //更新指针
            temp = temp.next;
            if (temp.next == null){
                System.out.print(temp);
                break;
            }
            System.out.print(temp + "--->");
        }
    }

    //插入节点
    //根据学号顺序查找添加的位置, 如果存在, 则提示错误信息
    public void addByOrder(StudentNode studentNode){
        //寻找的temp应该为添加位置的前一个节点
        StudentNode temp = head;
        boolean flag = false; //标识新添加的no是否已经存在
        while (true){
            if (temp.next == null){
                //已经在链表的尾部
                break;
            }
            if (Integer.parseInt(temp.next.no) > Integer.parseInt(studentNode.no)){
                //位置找到 插入到temp后
                break;
            }else if (Integer.parseInt(temp.next.no) == Integer.parseInt(studentNode.no)){
                //已经存在
                flag = true;
                break;
            }
            //移动指针
            temp = temp.next;
        }
        if (flag){
            System.out.println("\n准备插入的学生信息: " + studentNode.no + ",该学号已经存在,不可添加!");
        }else {
            studentNode.next = temp.next;
            temp.next = studentNode;
        }
    }

    //根据no学号修改学生信息
    public void update(StudentNode studentNode){
        if (head.next == null){
            System.out.println("当前链表为空, 无法修改");
            return;
        }
        StudentNode temp = head.next;
        boolean flag = false; //表示是否找到节点
        while (true){
            if (temp == null){
                break;
            }
            if (temp.no == studentNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.name = studentNode.name;
            temp.age = studentNode.age;
        }else {
            System.out.println("没有找到");
        }
    }

    //删除节点
    public void delete(String no){
        StudentNode temp = head;
        boolean flag = false; //标志是否找到
        //查找到待删除节点的前一个节点进行删除操作
        while (true){
            if (temp.next == null){
                //到达尾部
                break;
            }
            if (temp.next.no == no){
                //找到了
                flag = true;
                break;
            }
            //遍历
            temp = temp.next;
        }
        //删除操作
        if (flag){
            temp.next = temp.next.next;
            System.out.println("删除成功!");
        }else {
            System.out.println("要删除的节点不存在!");
        }
    }
}

测试类:


public class StudentListTest {

    public static void main(String[] args) {
        StudentNode node1 = new StudentNode("1", "黄小黄", 21);
        StudentNode node2 = new StudentNode("2", "懒羊羊", 21);
        StudentNode node3 = new StudentNode("3", "沸羊羊", 22);
        //创建单链表 录入数据 输出
        StudentLinkedList list = new StudentLinkedList();
        list.add(node1);
        list.add(node2);
        list.add(node3);
        System.out.println("遍历链表:");
        list.showList();
        //测试插入数据方法
        StudentNode node5 = new StudentNode("5", "美羊羊", 19);
        StudentNode node4 = new StudentNode("4", "暖羊羊", 19);
        list.addByOrder(node5);
        list.addByOrder(node4);
        System.out.println("\n依次插入学号为5、4的学生后:");
        list.showList();
        //测试修改方法
        System.out.println("\n测试修改方法:");
        list.update(new StudentNode("1", "祢豆子", 10));
        list.showList();
        //测试删除方法
        System.out.println("\n测试删除方法:");
        list.delete("1");
        list.delete("5");
        list.showList();
    }
}

实现结果:

遍历链表:
StudentNode{no='1', name='黄小黄', age=21}--->StudentNode{no='2', name='懒羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}
依次插入学号为5、4的学生后:
StudentNode{no='1', name='黄小黄', age=21}--->StudentNode{no='2', name='懒羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}--->StudentNode{no='4', name='暖羊羊', age=19}--->StudentNode{no='5', name='美羊羊', age=19}
测试修改方法:
StudentNode{no='1', name='祢豆子', age=10}--->StudentNode{no='2', name='懒羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}--->StudentNode{no='4', name='暖羊羊', age=19}--->StudentNode{no='5', name='美羊羊', age=19}
测试删除方法:
删除成功!
删除成功!
StudentNode{no='2', name='懒羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}--->StudentNode{no='4', name='暖羊羊', age=19}
Process finished with exit code 0

2 单链表的面试

2.1 统计单链表中有效节点数量

 
    public static int getLength(StudentNode head){
        if (head.next == null){
            return 0;
        }
        int length = 0;
        StudentNode temp = head.next;
        while (temp != null){
            length++;
            temp = temp.next;
        }
        return length;
    }

2.2 新浪–倒数第k个节点

查找链表中倒数第k个节点

思路分析:

  • 编写一个方法,接收head头节点和index,index表示k;
  • 链表从头到尾遍历,求出长度(链表节点个数)size;
  • 从第一个节点,遍历size-length次,即可找到倒数第k个节点。

参考代码:


    public static StudentNode findLastIndexNode(StudentNode head, int index){
        //如果链表为空
        if (head.next == null){
            return null;
        }
        //得到链表的长度(节点个数)
        int size = getLength(head);
        //遍历 size-index次 得到倒数第index个节点
        //数据校验
        if (index <= 0 || index > size){
            return null;
        }
        //遍历
        StudentNode current = head.next;
        for (int i = 0; i < size - index; i++) {
            current = current.next;
        }
        return current;
    }

2.3 腾讯–单链表的反转

反转单链表

思路分析:

  • 可以使用头插法;
  • 以原链表为模板,每遍历一个节点,取出,并接在新链表的最前端
  • 原head头节点,指向新的节点;
  • 直到遍历完为止。

参考代码:

	
    public static StudentLinkedList reverseList(StudentNode head){
        if (head.next == null){
            return null;
        }
        StudentNode old = head.next; //用于遍历旧链表
        //创建新链表,新链表根据原链表遍历得到
        StudentLinkedList newList = new StudentLinkedList();
        StudentNode newHead = newList.getHead(); //新链表的头节点
        //遍历构造
        boolean flag = true; //标记是否为第一次添加
        while (old != null){
            //头插法加入到新链表中
            StudentNode newNode = new StudentNode(old.no, old.name, old.age);
            if(flag){
                newHead.next = newNode;
                newNode.next = null;
                flag = false;
            }else {
                newNode.next = newHead.next;
                newHead.next = newNode;
            }
            old = old.next;
        }
        return newList;
    }

以上方式虽然可以实现链表的反转,但是是以返回一个新的反转链表的形式,并没有真正意义上实现原地反转,下面介绍另一种方式:

双指针:

	
    public static void reverse(StudentNode head){
        //如果当前链表为空 或者只有一个节点 直接返回即可
        if (head.next == null || head.next.next == null){
            return;
        }
        //辅助指针遍历原来的链表
        StudentNode cur = head.next; //当前节点
        StudentNode next = null; //指向cur的下一个节点
        StudentNode reverseHead = new StudentNode("", "", 0);
        //遍历原来的链表,每遍历一个节点,就取出,放在新链表的最前端
        while (cur != null){
            next = cur.next; //暂时保存当前节点的下一个节点
            cur.next = reverseHead.next; //讲cur下一个节点放在链表最前端
            reverseHead.next = cur;
            cur = next; //cur后移动
        }
        head.next = reverseHead.next;
        return;
    }

2.4 百度–逆序打印单链表

从尾到头打印单链表

方式一: 先将单链表反转,然后再打印。但是这样会破坏掉原有单链表的结构,而题目要求仅仅是打印,因此不建议!

方式二: 利用栈模拟

将单链表的各个节点压入栈中,利用栈先进后出的特点,实现逆序打印。

参考代码:

    
    public static void reversePrintList(StudentNode head){
        if (head.next == null){
            return; //空链表无法打印
        }
        //创建栈模拟逆序打印
        Stack<StudentNode> stack = new Stack<>(); //栈
        StudentNode cur = head.next;
        //将链表的所有节点压入栈
        while (cur != null){
            stack.push(cur);
            cur = cur.next;
        }
        //逆序打印
        while (!stack.empty()){
            //出栈
            System.out.println(stack.pop());
        }
        return;
    }

以上就是Java数据结构之单链表的实现与面试题汇总的详细内容,更多关于Java单链表的资料请关注编程网其它相关文章!

--结束END--

本文标题: Java数据结构之单链表的实现与面试题汇总

本文链接: https://www.lsjlt.com/news/170097.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java数据结构之单链表的实现与面试题汇总
    目录1 单链表1.1 单链表介绍1.2 单链表的实现思路分析1.3 实现代码2 单链表的面试题2.1 统计单链表中有效节点数量2.2 新浪–倒数第k个节点2.3 腾讯&n...
    99+
    2022-11-13
    Java 数据结构 单链表 Java 单链表
  • C++数据结构之单链表的实现
    目录一、单链表的定义二、单链表的基本操作的实现1.初始化2.取值3.查找4.插入5.删除三、完整代码四、测试一下代码一、单链表的定义 线性表的链式存储又称为单链表,它是指通过一组任意...
    99+
    2024-04-02
  • java数据结构中单链表与双向链表的实现方法
    这篇文章主要介绍“java数据结构中单链表与双向链表的实现方法”,在日常操作中,相信很多人在java数据结构中单链表与双向链表的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java数据结构中单链表与...
    99+
    2023-06-20
  • Java数据结构之链表实现(单向、双向链表及链表反转)
    前言 之前学习的顺序表查询非常快,时间复杂度为O(1),但是增删改效率非常低,因为每一次增删改都会元素的移动。可以使用另一种存储方式-链式存储结构。 链表是一种物理存储单元上非连续、...
    99+
    2024-04-02
  • Java数据结构之单链表详解
    目录一、图示二、链表的概念及结构 三、单链表的实现四、完整代码的展示 一、图示 二、链表的概念及结构 链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的...
    99+
    2024-04-02
  • C++数据结构之单链表如何实现
    这篇文章主要介绍了C++数据结构之单链表如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++数据结构之单链表如何实现文章都会有所收获,下面我们一起来看看吧。一、单链表的定义线性表的链式存储又称为单链表,...
    99+
    2023-06-30
  • Java数据结构之链表相关知识总结
    一、链表 1.1 概述 链表是真正动态的数据结构,最简单的动态数据结构,基本用于辅助组成其他数据结构。 数据存储在“节点”(Node)中 优点:真正的动态,不需要处理固定容量的问题...
    99+
    2024-04-02
  • C语言数据结构之单链表的实现
    目录一.为什么使用链表二.链表的概念三.链表的实现3.1 创建链表前须知3.2 定义结构体3.3 申请一个节点3.4 链表的头插3.5 链表的尾插3.6 链表的尾删3.7 链表的头删...
    99+
    2024-04-02
  • Java数据结构之双向链表的实现
    目录1 双向链表1.1 双向链表介绍1.2 双向链表实现思路2 双向链表实现完整代码2.1 节点类 Student.java2.2 双向链表实现类 StudentDoubleLink...
    99+
    2022-11-13
    Java 数据结构 双向链表 Java 双向链表
  • Java数据结构之单链表是什么
    这篇文章给大家分享的是有关Java数据结构之单链表是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、图示二、链表的概念及结构 链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接...
    99+
    2023-06-15
  • 数据结构(Java实现)LinkedList与链表(上)
    链表 逻辑结构 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。 无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。 ...
    99+
    2023-08-30
    数据结构 java 链表
  • java数据结构基础:单链表与双向链表
    目录单链表:实现思路:代码实现:双向链表:实现思路:代码实现:总结单链表: 每个数据是以节点的形式存在的 每个节点分为数据域和指针域 数据域中保存该节点的数据 指针域中保存指向下一个...
    99+
    2024-04-02
  • Java数据结构之LinkedList从链表到实现
    目录1.ArrayList的缺陷2.LinkedListLinkedList概念LinkedList的使用3.链表的概念及结构4.ArrayList和LinkedList的区别1.A...
    99+
    2023-05-18
    Java LinkedList Java 链表
  • Java数据结构与算法之单链表深入理解
    目录一、单链表(Linked List)简介二、单链表的各种操作1.单链表的创建和遍历2.单链表的按顺序插入节点 以及节点的修改3.单链表节点的删除4.以上单链表操作的代码实现 (通...
    99+
    2024-04-02
  • Java数据结构之双端链表原理与实现方法
    本文实例讲述了Java数据结构之双端链表原理与实现方法。分享给大家供大家参考,具体如下:一、概述:什么时双端链表:链表中保持这对最后一个连点引用的链表从头部插入要对链表进行判断,如果为空则设置尾节点为新添加的节点从尾部进行插入如果链表为空,...
    99+
    2023-05-30
    java 数据结构 双端链表
  • 用Python实现数据结构之链表
    链表与栈,队列不一样,它是由一个个节点构成的,每个节点存储着本身的一些信息,也存储着其他一个或多个节点的引用,可以从一个节点找到其他的节点,节点与节点之间就像是有链连在一起一样,这种数据结构就叫做链表 单向链表是链表的最简单形式,链表...
    99+
    2023-01-30
    数据结构 链表 Python
  • C语言数据结构之单链表怎么实现
    本文小编为大家详细介绍“C语言数据结构之单链表怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言数据结构之单链表怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一.为什么使用链表在学习链表以前,...
    99+
    2023-07-02
  • Java数据结构之双向链表如何实现
    这篇文章主要讲解了“Java数据结构之双向链表如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java数据结构之双向链表如何实现”吧!双向链表(Doubly linked list)什...
    99+
    2023-06-30
  • C语言数据结构与算法之单链表
    目录基本概念读取数据元素获取第i个结点的数据元素插入数据元素 初始化链表打印链表顺序表查空顺序表的删除 删除第i个结点及其数据元素情况1:当删除的是第一个元素情况2:除第一个结点外完...
    99+
    2024-04-02
  • Java 数据结构与算法系列精讲之单向链表
    目录概述链表单向链表单向链表实现Node 类add 方法remove 方法get 方法set 方法contain 方法main完整代码概述 从今天开始, 小白我将带大家开启 Jave...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作