4.1.Java实现单向链表(完整代码及详细注释)

1.什么是单向链表?

单向链表由多个节点组成,每个 节点(用于存储数据) 通过next指针相互连接,
下一个节点的引用存放在上一个节点的next指针中, 从而构成了一个线性的链表(它与数组的区别就是它可以不具空间连续性)
在java中一般通过定义节点Node类和API类的方式来实现链表

JDK中对链表LinkedList的节点的实现结构如下:

可以看到链表节点组成分为三部分:
存储数据的元素item , 当前节点下一节点的引用next, 当前节点上一节点的引用prev

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

节点定义一般就放在API内部作为内部静态类使用,也就是我们使用链表数据结构都是通过API对外开放的接口进行调用的,
我们不允许直接对链表内部属性直接访问。

1.1 单向链表基本结构

单向链表节点的定义中没有上一节点的引用。

下面我们学习最基本的链表结构,我们默认链表中的元素就是int类型数字。

如图所示:

node1.next
node2.next
node3.next
node1
node2
node3
null

其中节点的数据结构为:

/**
 * 链表节点数据结构
 */
static class Node {
    /**
     * 存储节点数据
     */
    private int data;
    /**
     * 存储下一个节点引用
     */
    private Node next;
    /**
     * 本节点名称
     */
    private String nodeName;
    /**
     * 节点构造方法,仅构造出其存储的数据,并不构造下一节点的引用
     * @param data 节点数据
     */
    public Node(int data, String nodeName) {
        this.data=data;
        if(nodeName==null){
            nodeName=""+data;
        }
        this.nodeName=nodeName;
    }
}

我们该如何实现操作单向链表的方法来让我们正确单向链表存储数据呢?

1.2 实现对单向链表基本的增删改查

1.2.1 插入方法

给出一个节点nodeToInsert和指定位置,在链表指定位置插入该节点
主要思路是:

  • 首先判断链表是否为空,如果为空则直接放入第一个节点

  • 再先判断链表中存不存在position位置,

    若不存在输出错误信息并返回

    若存在则进行插入操作:从第一个节点开始

    1. 首先判断position是不是为0,因为这种情况不同于其他的,如果是则直接进行头节点插入
    2. 否则,先找到第position-1个节点和position个节点。
    3. 将前一个节点的下一节点设为nodeToInsert ,将nodeToInsert的下一个节点设置为position节点
  • 这样就完成了元素插入

代码实现如下:

class Test{
    /**
     * 链表节点插入
     * 主要思路是:先判断链表中存不存在position位置,若没有输出错误信息并返回头节点;
     *      若存在则进行插入操作:首先判断position是不是为1,因为这种情况不同于其他的。
     *      否则,先找到第position-1个节点和position个节点,将前一个节点的下一节点设为nodeToInsert
     *      将nodeToInsert的下一个节点设置为position节点,这样完成插入操作
     * @param head 链表头节点
     * @param insert 要插入的节点
     * @param position 指定插入的位置
     * @return 插入后的链表头节点
     */
    static Node insertInLinkedList(Node head, Node insert, int position) {
        if(head == null) {
            return insert;
        }
        //获得输入链表的长度
        int size = listLength(head);
        //判断链表内是否存在此位置
        if(position>size||position<0) {
            System.out.println("链表不存在该位置: "+ position +"链表最大位置索引: "+(size-1));
            return head;
        }
        //在链表开头插入
        if(position==0) {
            insert.next = head;
            return insert;
        }
        //在中间或末尾插入
        else{
            Node pre = head;
            //找到那个位置的前一个节点
            for(int index = 0;index < position-1;index++){
                //获得第position-1位置的节点
                pre = pre.next;
            }
            //插入操作
            insert.next = pre.next;
            pre.next = insert;
        }
        return head;
    }

    /**
     * 以输入节点为头,计算出链表长度
     * @param head 头节点
     * @return 链表长度
     */
    static int listLength(Node head) {
        int length = 0;
        Node current = head;
        while(current!=null){
            length++;
            current = current.next;
        }
        return length;
    }
}

1.2.2 如何删除链表的元素

主要思路是找到position的前一个节点和后一个节点,然后将他们连接。

代码实现:

class Test{
    /**
     * 方法和前面的插入方法有异曲同工之妙:
     *  主要思想是找到position的前一个节点和后一个节点,然后将他们连接
     * @param head 头节点
     * @param position 删除的位置
     * @return 删除后的链表头节点
     */
    static Node deleteNodeFromLinkedList(Node head, int position) {
        int size = listLength(head);
        if(position > size||position < 0) {
            System.out.println("Position of node to delete is invalid. The valid inputs are 1 to"+size);
            return head;
        }
        //删除表头
        if(position == 0){
            return head.next;
            //删除中间或结尾节点
        }else{
            Node pre = head;
            int index = 0;
            //获得目标节点的上一个节点
            while(index < position-1) {
                pre = pre.next;
                index++;
            }
            //要删除目标节点
            Node cur = pre.next;
            pre.next = cur.next;
        }
        return head;
    }

    /**
     * 以输入节点为头,计算出链表长度
     * @param head 头节点
     * @return 链表长度
     */
    static int listLength(Node head) {
        int length = 0;
        Node current = head;
        while(current!=null){
            length++;
            current = current.next;
        }
        return length;
    }
}

1.2.3 如何修改指定位置节点的值

class Test{

    /**
     * 修改指定位置的值
     * @param head
     * @param position
     * @param element
     * @return
     */
    static Node updateNode(Node head, int position,int element) {
        int size = listLength(head);
        if(position < 0 || position >= size) {
            System.out.println("链表不存在该位置: "+ position +"链表最大位置索引: "+(size-1));
        }
        Node cur = head;
        for(int index = 0;index < position;index++){
            cur = cur.next;
        }
        cur.data = element;
        return head;
    }
    
    
}

1.2.4 如何得到指定位置的值

class Test{
    /**
     * 获取链表指定位置的元素
     * @param head
     * @param position
     * @return
     */
    static Node get(Node head,int position) {
        int size = listLength(head);
        if(position<0||position>=size) {
            System.out.println("链表不存在该位置: "+ position +"链表最大位置索引: "+(size-1));
        }
        Node cur = head;
        for (int index = 0;index < position;index++){
            cur = cur.next;
        }
        return cur;
    }
    
}

项目地址

https://gitee.com/yan-jiadou/algorithm-study/tree/master/algorithmStudy/src/main/java/course/p4_list/s1_OneNextList

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值