算法通关村第一关——链表青铜挑战笔记

1 在 Java 中构造单向链表

1.1 单向链表的结构

单向链表的结构如下所示:
在这里插入图片描述

其中,head表头指针 用来指向链表的第一个结点也就是 首结点 ,链表中每个 链表结点 都由 数据部分后继元素的 next 指针 组成,由于链表最后一个结点也就是 尾结点 没有直接后继,所以尾结点的 next 指针为 null

1.2 定义单向链表

根据单向链表的结构,在 Java 中定义单向链表的代码如下所示:

package com.lin.level1;

/**
 * @author lin
 * 单向链表结点
 */
public class LinkedListNode {
    /**
     * 数据部分
     */
    public int val;
    /**
     * 后继元素的 next 指针
     */
    public LinkedListNode next;

    /**
     * 构造方法,初始化单向链表结点对象时,用来给单向链表结点对象的数据部分赋值
     *
     * @param val 数据值
     */
    public LinkedListNode(int val) {
        this.val = val;
        this.next = null;
    }
}

注:为了能够 简化编码 和便于操作,在定义 LinkedListNode 时没有将属性设置为 private 而是设置为 public,这样能够直接使用 node.val 和 node.next 来操作,而不用再去编写 setter 和 getter 方法来操作。

1.3 通过数组初始化单向链表

使用 Java 编写的通过数组初始化单向链表的方法代码如下所示:

/**
 * 通过数组初始化单向链表
 *
 * @param array 数据数组
 * @return 链表首结点
 */
public static LinkedListNode initLinkedList(int[] array) {
    LinkedListNode head = null, cur = null;
    for (int i = 0; i < array.length; i++) {
        LinkedListNode newNode = new LinkedListNode(array[i]);
        newNode.next = null;
        if (i == 0) {
            head = newNode;
            cur = newNode;
        } else {
            cur.next = newNode;
            cur = newNode;
        }
    }
    return head;
}

初始化示例单向链表的代码如下:

int[] a = {10, 30, 50, 40, 20};
LinkedListNode head = initLinkedList(a);

通过 Debug 模式可以看到从首结点出发,通过结点的 next 指针依次访问下一个结点,直到尾结点,各个结点就像是链结在一条链上:
在这里插入图片描述

1.4 获取链表长度

使用 Java 编写的获取链表长度的方法代码如下所示:

/**
 * 获取链表长度
 *
 * @param head 链表首结点
 * @return 链表长度
 */
public static int getListLength(LinkedListNode head) {
    int length = 0;
    LinkedListNode node = head;
    while (node != null) {
        length++;
        node = node.next;
    }
    return length;
}

注:获取链表长度其实也是在遍历链表,从链表首结点开始遍历。

2 在单向链表中添加元素

在单向链表中添加元素时,我们需考虑以下三种情况:

  1. 在头部添加元素
  2. 在中间添加元素
  3. 在尾部添加元素

2.1 在头部添加元素

以在原链表的头部添加元素 LinkedListNode(60) 为例,在头部添加元素的过程如下图所示:
在头部添加元素

要想在原链表的头部添加元素 LinkedListNode(60) ,先要让 LinkedListNode(60) 指向原先的 head ,再让 LinkedListNode(60) 成为新的 head,即 先执行 LinkedListNode(60).next = head 再执行 head = LinkedListNode(60)

思考:为什么要先执行 LinkedListNode(60).next = head 再执行 head = LinkedListNode(60) ,如果顺序颠倒会怎么样?
答:如果顺序颠倒先执行了 head = LinkedListNode(60) ,则 LinkedListNode(60) 就成为了新的 head,这会导致丢失原先 head 中 next 指向的下一个结点的地址,进而导致后面结点的丢失。
在头部添加元素错误

需要注意的点:在头部添加元素后要记得让 head 重新指向新的首结点。如果忘记让 head 重新指向新的首结点,则会导致遍历时遗漏新添加的首结点。

注:本文中 LinkedListNode(60) 表示数据为 60 的链表结点,在程序中体现为: LinkedListNode newNode = new LinkedListNode(60); 。

2.2 在中间添加元素

以在原链表的中间添加元素 LinkedListNode(60) 为例,在中间添加元素的过程如下图所示:
在中间添加元素

这里要将 LinkedListNode(60) 插入到原先 LinkedListNode(50) 所在的位置上。首先需要在 LinkedListNode(50) 的 前一个位置停下来 ,也就是先停在 LinkedListNode(30) 的位置上,此时 cur 用来保存当前结点 LinkedListNode(30),然后要 先让 LinkedListNode(60).next = cur.next,再让 cur.next = LinkedListNode(60) ,这样就能将 LinkedListNode(60) 插入到原先 LinkedListNode(50) 所在的位置上。

思考一:为什么要在要插入位置的前一个位置停下来?
答:如果不在要插入位置的前一个位置停下来的话,直接到达要插入位置时会无法再获取要插入位置的前驱元素,这就导致要插入位置的前驱元素的 next 无法指向新结点。

思考二:为什么要先让 LinkedListNode(60).next = cur.next,再让 cur.next = LinkedListNode(60),如果顺序颠倒会怎么样?
答:如果顺序颠倒先让 cur.next = LinkedListNode(60) ,则原先 cur.next 的值就丢失了,这将导致原先链接在 LinkedListNode(30) 后的结点丢失。
在中间添加元素错误

2.3 在尾部添加元素

以在原链表的尾部添加元素 LinkedListNode(60) 为例,在尾部添加元素的过程如下图所示:
在尾部添加元素

要想在原链表的尾部添加元素 LinkedListNode(60) ,只需让原链表的尾结点 LinkedListNode(20) 指向 LinkedListNode(60),也就是 LinkedListNode(20).next = LinkedListNode(60)

2.4 链表添加元素代码

用 Java 编写的链表添加元素的代码如下所示:

/**
 * 链表插入
 *
 * @param head       链表首结点
 * @param nodeInsert 待插入结点
 * @param position   待插入位置,从1开始
 * @return 插入后得到的链表首结点
 */
public static LinkedListNode insertNode(LinkedListNode head, LinkedListNode nodeInsert, int position) {
    // head == null 时可认为 nodeInsert 为链表首结点
    if (head == null) {
        return nodeInsert;
    }

    int size = getListLength(head);
    if (position < 1 || position > size + 1) {
        System.out.println("位置参数错误");
        return head;
    }

    // 头部添加元素
    if (position == 1) {
        nodeInsert.next = head;
        head = nodeInsert;
        return head;
    }

    // 中间添加元素,当 position == size + 1 时,为尾部添加元素
    LinkedListNode pNode = head;
    int count = 1;
    while (count < position - 1) {
        pNode = pNode.next;
        count++;
    }
    nodeInsert.next = pNode.next;
    pNode.next = nodeInsert;

    return head;
}

3 总结

本文根据单向链表的结构,使用 Java 完成了单向链表结点的定义和构造,并分析了如何在单向链表中插入元素,在插入元素时分为了三种情况来讨论,并通过图例说明了需要注意的地方,最终给出了 Java 代码实现。综上所述,我们要理解单向链表的定义,在单向链表中插入元素时,要能够分情况来分析,在进行结点的链结时需要注意 head 指针的指向和结点间链结顺序的问题。

4 获取本文全部示例代码文件

本文全部示例代码文件可从我的 GitHub 仓库中获取:算法通关村第一关链表青铜挑战笔记代码

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值