iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java如何实现一个单向非循环链表
  • 870
分享到

Java如何实现一个单向非循环链表

2023-07-04 16:07:42 870人浏览 独家记忆
摘要

这篇文章主要介绍“Java如何实现一个单向非循环链表”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java如何实现一个单向非循环链表”文章能帮助大家解决问题。1、什么是链表?链表是一种物理存储结构上

这篇文章主要介绍“Java如何实现一个单向非循环链表”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java如何实现一个单向非循环链表”文章能帮助大家解决问题。

1、什么是链表?

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

通俗点,就是每个元素是一个节点,然后用一个指针域给后面的节点连起来,第一个节点没有前驱,最后一个节点没有后继。

Java如何实现一个单向非循环链表

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

1. 单向、双向         2. 带头、不带头         3. 循环、非循环

我们重点讲解单向非循环链表和双向非循环链表,同时这两个也是笔试中考的比较多的。

2、实现一个单向非循环链表

2.1 实现前的约定

因为链表的每个元素是一个节点,所以我们采取内部类的方式,而我们还需要定义一个头节点的引用,来始终指向头节点。

public class MySingleList {    private Listnode head; //引用头节点    // 链表每个元素是一个节点    private class ListNode {        private int val; //存放数据元素        private ListNode next; //存放下一个节点地址        //构造方法        public ListNode(int val) {            this.val = val;        }    }}

注意:链表最少有两个域,分别是数据域和指针域,当然你也可以有多个数据域和指针域。

我们还需要实现以下几个常用的方法:

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

2.2 addFirst 方法

public void addFirst(int data) {    ListNode newNode = new ListNode(data); //把传过来的值放到新的节点中    newNode.next = this.head; //新节点的next指向头节点    this.head = newNode; //使新节点成为头节点}

因为head默认是指向空的,当链表为null,也不影响这个代码的执行,不信你下来画画图咯。

2.3 addList 方法

public void addLast(int data) {    ListNode newNode = new ListNode(data);    // 如果链表为空的情况    if (this.head == null) {        this.head = newNode;        return;    }    // 先找到最后一个节点    ListNode cur = this.head;    while (cur.next != null) {        cur = cur.next;    }    cur.next = newNode;}

2.4 addIndex 方法

//任意位置插入,第一个数据节点为0号下标private ListNode findIndexPrevNode(int index) {    ListNode cur = this.head;    while (index - 1 != 0) {        cur = cur.next;        index--;    }    return cur;}public boolean addIndex(int index,int data) {    // 判断index下标的有效性    if (index < 0 || index > size()) {        return false;    }    // 如果在0下标插入则是头插    if (index == 0) {        addFirst(data); //头插        return true;    }    // 如果在末尾插入则是尾插    if (index == size()) {        addLast(data); //尾插        return true;    }    ListNode newNode = new ListNode(data); //新节点    // 在中间插入    ListNode prevNode = findIndexPrevNode(index); //找到index下标的前一个节点    newNode.next = prevNode.next; //新节点的next被改为index的位置的节点    prevNode.next = newNode; //index位置前一个节点next被改成新节点    return true;}

这个代码我们首先需要找到index下标的前一个节点,先让新节点跟index位置的节点绑定起来,在把index的前一个节点与新节点连起来,这个地方说文字是不清楚的,小伙伴们可以下来按照我这个代码画图就能理解了,也可也直接看博主之前的C语言实现数据结构专栏,那里面有图解哈。

2.5 contains 方法

//查找关键字key是否在单链表当中public boolean contains(int key) {    // 当链表为空的情况    if (this.head == null) {        return false;    }    ListNode cur = this.head;    // 遍历列表    while (cur != null) {        if (cur.val == key) {            return true; //找到了返回true        }        cur = cur.next;    }    return false; //找不到返回false}

思路很简单,遍历一遍链表,找到 cur 为空位置,如果有返回true,没有返回false,交给小伙伴自己下来画图咯。

2.6 remove 方法

//删除第一次出现关键字为key的节点public void remove(int key) {    if (this.head == null) {        return;    }    ListNode cur = this.head;    // 如果删除的是key为头节点    if (this.head.val == key) {        this.head = head.next;        return;    }    // 这里不能是cur!=null, 不然会越界!!!    while (cur.next != null) {        // 找到 key 的前一个节点        if (cur.next.val == key) {            //当前的cur为key的前一个节点            cur.next = cur.next.next; //cur链接到key的后一个节点            return;        }        cur = cur.next;    }}

这里我们需要找到key的前一个节点,然后进行跟key后面的节点绑定即可,当key对应节点没人引用了,则会被自动回收掉。

2.7 removeAllKey 方法

//删除所有值为key的节点public void removeAllKey(int key) {    if (this.head == null) {        return;    }    // 采用前后指针的方法    ListNode cur = this.head;    ListNode prev = this.head;    while (cur != null) {        if (cur.val == key) {            prev.next = cur.next; //跳过key节点指向下一个节点        } else {            prev = cur;        }        cur = cur.next;    }    // 判断第一个节点是不是key    if (this.head.val == key) {        this.head = this.head.next; //head指向下一个节点    }}

这里大家伙先自己看看,后面讲解OJ题会有这道题详解的。

2.8 size 和 clear 方法

我相信这两个方法就不需要多说了吧?遍历?直接头指针置null?这不就简单了吗,这里就不写了哈,交给各位了!

3、单链表OJ题深度解剖

这个才是今天的重头戏,不是篮球哥不画图,是因为前面的图太简单了,小伙伴们结合着代码也能自己画出来,但是,对于OJ题,大家伙下去还是得画图的,相信看完这几道题,你会爱上数据结构的。

3.1 移除链表元素(来源:LeetCode 难度:简单)

题目:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

这个题我们可以用前后指针的思路来做,这样也比较通俗易懂,更适合初学者,大概的思路是这样的:我们可以定义一个cur和first的引用,如果碰到相等,也就是first.val == val,我们则让cur的next指向first的下一个节点,如果不相等,则让cur走到first的位置,最后first往后走一步,图解:

Java如何实现一个单向非循环链表

这里还没有完,如果第一个节点的值也是val呢?所以最后我们别忘了进行一个判断,那么最终的代码是这样的:

public ListNode removeElements(ListNode head, int val) {    if (head == null) {        return null;    }    ListNode cur = head;    ListNode first = head;    while (first != null) {        if (first.val == val) {            cur.next = first.next;        } else {            cur = first;        }        first = first.next;    }    // 判断头节点的值是否也是val    if (head.val == val) {        head = head.next;    }    return head;}

3.2 反转链表(来源:LeetCode 难度:简单)

题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

这个题我们可以先取到头节点,后续的节点都进行头插法即可?我们取到头节点,并且先将头节点的next置空,但是这样一来,就找不到后面的节点了,所以我们还需要有一个curNext引用来记录要反转节点的下一个节点:

我们的思路是这样的:首先找到头节点的next置空,cur走到curNext位置,curNext往前走,使得cur位置的next指向头节点,头节点cur再次成为新的头节点,当curNext走到null的时候循环结束。

public ListNode reverseList(ListNode head) {    // 空链表的情况    if (head == null) {        return null;    }    ListNode cur = head;    ListNode curNext = cur.next;    head.next = null;    while (curNext != null) {        cur = curNext;        curNext = curNext.next;        cur.next = head;        head = cur;    }    return head;}

3.4 链表中倒数第k个节点

题目:输入一个链表,输出该链表中倒数第k个结点。

这个题也是很简单的一道题,可以采用前后指针法,先让first指针走k步,走完之后slow和first一起走,这样slow和first之间就相差了k步,当first为null时,slow就是倒数第k个节点,在这个过程中,我们还要判断k的合法性,如果k小于等于0?或者k大于链表的长度呢?于是我们就能写出如下的代码:

public ListNode FindKthToTail(ListNode head,int k) {    // 判断k的合法性    if (k <= 0 || head == null) {        return null;    }    ListNode first = head;    ListNode slow = head;    // 先让first走k步    while (k != 0) {        // k的长度大于链表的长度        if (first == null) {            return null;        }        first = first.next;        k--;    }    // 一起走,当first为null,slow就是倒数第k个节点    while (first != null) {        first = first.next;        slow = slow.next;    }    return slow;}

3.6 链表分割(来源:牛客网 难度:较难)

题目:现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

这个题的思路我们可以这样做,既然是按照给定的值x进行分割,那么我们设定两个盘子,盘子A放小于x的节点,盘子B放大于x的节点,最后把这两个盘子的节点连起来,放回盘子A的头节点即可!

 public ListNode partition(ListNode pHead, int x) {        if (pHead == null) {            return null;        }        ListNode headA = null;        ListNode headB = null;        ListNode curA = null;        ListNode curB = null;        ListNode cur = pHead;        while (cur != null) {            if (cur.val < x) {                // 第一次放入A盘子                if (headA == null) {                    headA = cur;                    curA = cur;                } else {                    curA.next = cur;                    curA = cur;                }            } else {                // 第一次放入B盘子                if (headB == null) {                    headB = cur;                    curB = cur;                } else {                    curB.next = cur;                    curB = cur;                }            }            cur = cur.next;        }        // 如果A盘子为空        if (headA == null) {            return headB;        }        curA.next = headB;        // 避免B盘子尾节点形成环        if (headB != null) {            curB.next = null;        }        return headA;    }

3.7 链表的回文结构(来源:LeetCode 难度:较难)

题目:对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

这个题有要求的,要求空间复杂度为O(1),并且还得在O(n)的时间复杂度下,那我们就原地解决这个题,我们可以分为三个步骤,首先找到中间节点,然后把中间节点往后的节点进行反转,最后左右两个指针同时往中间走。如果光看下面代码看不懂,可以结合着代码画图才能理解更透彻哦!

public boolean chkPalindrome(ListNode A) {    if (A == null) {        return false;    }    // 只有一个节点的情况    if (A.next == null) {        return true;    }    // 首先找到中间节点    ListNode first = A;    ListNode slow = A;    while (first != null && first.next != null) {        first = first.next.next;        slow = slow.next;    }    // 走到这,slow是链表的中间节点,采用头插法反转slow后续的节点    first = slow.next;    ListNode cur = slow;    while (first != null) {        cur = first;        first = first.next;        cur.next = slow; //链接前一个节点        slow = cur; //更新头节点的位置    }    // 走到这,反转完毕,cur指向最后一个节点,让slow等于A,往中间找    slow = A;    while (slow != cur) {        if (slow.val != cur.val) {            return false;        }        // 偶数的情况下需要特殊判断        if (slow.next == cur) {            return true;        }        slow = slow.next;        cur = cur.next;    }    return true;}

3.8 相交链表(来源:LeetCode 难度:简单)

题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

这个题我们可以这样做,长链表先走两个链表的长度差的步数,因为相交之后的节点都是一样的个数,所以走了差值后,就两个链表一起往后走,相等了则就是相交节点。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {    if (headA == null || headB == null) {        return null;    }    ListNode longList = headA; //longList始终记录长的链表    ListNode shortList = headB;    // 分别求出两个链表的长度    int lenA = 0;    int lenB = 0;    ListNode cur = headA;    while (cur != null) {        lenA++;        cur = cur.next;    }    cur = headB;    while (cur != null) {        lenB++;        cur = cur.next;    }    int len = lenA - lenB;    // 如果B链表长于A链表    if (len < 0) {        // 修正相差长度        len = lenB - lenA;        longList = headB; //longList始终记录长的链表        shortList = headA;    }    // 让长链表先走差值len步,然后同步走,相等了即为相交节点    while (len != 0) {        longList = longList.next;        len--;    }    while (longList != shortList) {        longList = longList.next;        shortList = shortList.next;    }    // 如果两个链表走到了null,则没有中间节点返回null,如果有,返回任意一个即可    return longList;}

关于“Java如何实现一个单向非循环链表”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: Java如何实现一个单向非循环链表

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

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

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

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

下载Word文档
猜你喜欢
  • Java如何实现一个单向非循环链表
    这篇文章主要介绍“Java如何实现一个单向非循环链表”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java如何实现一个单向非循环链表”文章能帮助大家解决问题。1、什么是链表?链表是一种物理存储结构上...
    99+
    2023-07-04
  • python单向循环链表如何实现
    本篇内容主要讲解“python单向循环链表如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python单向循环链表如何实现”吧!单向循环链表将所有的链接在一起,每一个节点分为数据存储区和链...
    99+
    2023-07-06
  • python单向循环链表怎么实现
    单向循环链表将所有的链接在一起,每一个节点分为数据存储区和链接区,数据区存储数据,链接区链接下一个节点item: 存储数据的地方next: 链接下一个节点注意: 单向循环链表是首位链接,即尾部的节点要和头部的节点链接单向链表操作1、链表是否...
    99+
    2023-05-16
    Python
  • C语言如何实现双向链表和双向循环链表
    本文小编为大家详细介绍“C语言如何实现双向链表和双向循环链表”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言如何实现双向链表和双向循环链表”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。双向链表和双向循环链表...
    99+
    2023-06-16
  • java双向循环链表的实现代码
    例1:复制代码 代码如下:package com.xlst.util; import java.util.HashMap;import java.util.Map;import ja...
    99+
    2022-11-15
    java 双向循环链表
  • python单向循环链表实例详解
    使用python实现单向循环链表,供大家参考,具体内容如下 单向循环链表 将所有的链接在一起,每一个节点分为数据存储区和链接区,数据区存储数据,链接区链接下一个节点 item: 存储...
    99+
    2024-04-02
  • C++如何实现带头双向循环链表
    这篇文章主要为大家展示了“C++如何实现带头双向循环链表”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++如何实现带头双向循环链表”这篇文章吧。什么是带头双向循环链表什么是带头?双向?循环?(...
    99+
    2023-06-29
  • 利用Java如何实现一个双向链表
    利用Java如何实现一个双向链表?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java中双向链表详解及实例写在前面:  双向链表是一种对称结构,它克服了单链表上...
    99+
    2023-05-31
    java 双向链表 ava
  • python双向循环链表怎么实现
    本文小编为大家详细介绍“python双向循环链表怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“python双向循环链表怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。双向循环链表: 将所有的数据存...
    99+
    2023-06-30
  • C语言如何实现带头双向循环链表
    这篇文章主要介绍了C语言如何实现带头双向循环链表,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言在实际生活中最常用的就是这两种链表。无头单向非循环链表。和带头双向循环链表。...
    99+
    2023-06-29
  • C++中怎么实现一个单向链表
    C++中怎么实现一个单向链表,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。C++单向链表实现代码:#include < iostream>&...
    99+
    2023-06-17
  • C语言 超详细介绍与实现线性表中的无头单向非循环链表
    目录一、本章重点二、链表介绍三、无头单向非循环链表常用接口实现3.1动态申请一个节点3.2单链表打印3.3单链表尾插3.4单链表的头插3.5单链表的尾删3.6单链表头删3.7单链表查...
    99+
    2024-04-02
  • python如何实现单向链表及单向链表的反转
    链表的定义 链表中的每个节点会存储相邻节点的位置信息,单链表中的每个节点只存储下一关节点的位置信息 单向链表的实现 class ListNode: def __init_...
    99+
    2024-04-02
  • C++实现约瑟夫环的循环单链表
    约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知 n 个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。. 从编号为 k 的人开始报数,数到 m 的那个人出圈;他的下一个人...
    99+
    2024-04-02
  • C语言无头单向非循环链表的操作方法有哪些
    这篇文章主要介绍“C语言无头单向非循环链表的操作方法有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C语言无头单向非循环链表的操作方法有哪些”文章能帮助大家解决问题。链表引入问:上次我们看了顺序...
    99+
    2023-06-30
  • C语言实现带头双向循环链表
    目录前言1. 创建结构体2.malloc新节点3.创建哨兵位节点4.尾插5.打印6.尾删7.头插8.在指定位置pos的前面进行插入9. 删除指定位置pos节点10.销毁链表前言 在...
    99+
    2024-04-02
  • C++带头双向循环链表怎么实现
    这篇文章主要介绍“C++带头双向循环链表怎么实现”,在日常操作中,相信很多人在C++带头双向循环链表怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++带头双向循环链表怎么实现”的疑惑有所帮助!接下来...
    99+
    2023-06-29
  • C语言详解无头单向非循环链表各种操作方法
    目录链表引入链表介绍创建链表打印链表创建结点单链表尾插单链表头插单链表尾删单链表头删在pos位置之前插入数据在pos位置之后插入数据删除pos位置结点删除pos位置之后的结点销毁链表...
    99+
    2024-04-02
  • Java如何实现双向链表
    本篇内容介绍了“Java如何实现双向链表”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、双向链表1 双向链表的每个节点组成包含节点数据,上...
    99+
    2023-06-30
  • C语言详解如何实现带头双向循环链表
    目录创建链表存储结构创建结点链表的初始化双向链表的打印双向链表尾插双向链表尾删双向链表头插双向链表头删双向链表查找双向链表pos前插入结点双向链表删除pos位置的结点双向链表的销毁顺...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作