算法通关村第一关[青铜挑战]-链表

1.链表的概念

链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。
链表的第1个节点被称为头节点,最后1个节点被称为尾节点,尾节点的next指针指向空。
注意:单链表只指向一个结点,不能指向多个
两个结点值相同,引用也相同的,不一定是同个结点

在这里插入图片描述

2.链表的相关概念

节点
每个点都由值和指向下一个结点的地址组成的独立的单元,称为一个结点,有时也称为节点,含义都在链表中,是一样的

头节点
对于单链表,如果知道了第一个元素,就可以通过遍历访问整个链表,因此第一个结点最重要,,一般称为头结点

虚拟节点
虚拟结点其实就是一个结点dummyNode,其next指针指向head,也就dummyNode.next=head.
因此,如果在算法里使用了虚拟结点,则要注意如果要获得head结点,或者从方法(函数)里返回的时候,则应使用dummyNode.next.
另外,dummyNode的val不会被使用,初始化为0或者-1等都是可以的。既然值不会使用,那虚拟结点有啥用呢?简单来说,就是为了方便处理首部结点,否则需要在代码里单独处理首部结点的问题。在链表反转里,该方式可以大大降低解题难度。

3.链表的创建和结点CRUD

3.1链表的创建

JVM中有栈区和堆区,栈区主要存引用,也就是一个指实际对象的地址,而堆区存的是创建的对象,一个结点存储的就是value和next引用(下一个结点的地址值)

//链表的初始化
private static Node initLinkedList(int[] array) {
    Node head = null, cur = null;
    for (int i = 0; i < array.length; i++) {
        Node newNode = new Node(array[i]);
        newNode.next = null;
        //头节点
        if (i == 0) {
            head = newNode;
            cur = newNode;
            //添加后续节点,让当前节点指向新节点,当前节点再变为新节点
        } else {
            cur.next = newNode;
            cur = newNode;
        }
    }
    return head;
}
//结点
static class Node {
    public int val;
    public Node next;

    Node(int x) {
        val = x;
        next = null;
    }
}

3.2获取链表长度

对于单链表,不管进行什么操作,一定是从头开始逐个向后访问,所以操作之后是否还能找到表头非常重要。一定要注意”狗熊掰棒子"问题,也就是只顾当前位置而将标记表头的指针丢掉了。

/**
 * 获取链表长度
 *
 * @param head 链表头节点
 * @return 链表长度
 */
public static int getLength(Node head) {
    int length = 0;
    Node node = head;
    while (node != null) {
        length++;
        node = node.next;
    }
    return length;
}

3.3链表插入

链表插入结点分为三种情况:头部插入、中间插入,尾部插入

1)头部插入
1.让新结点指向头结点
2.把新结点变成链表的头结点

在这里插入图片描述

2)中间插入
1.先让插入元素指向插入元素后的结点
2.让插入元素前的结点指向插入元素

在这里插入图片描述

3)尾部插入,将尾部结点指向新插入结点即可

在这里插入图片描述

/**
 * 链表插入
 *
 * @param head       链表头节点
 * @param nodeInsert 待插入节点
 * @param position   待插入位置,取值从2开始
 * @return 插入后得到的链表头节点
 */
public static Node insertNode(Node head, Node nodeInsert, int position) {
    //首先,链表如果为空,传进去的就是第一个节点
    if (head==null){
        return nodeInsert;
    }
    //已经存放的元素个数,position==length+1时,代表可以在位置为null处添加一个结点
    int length = getLength(head);
    if (position>length+1||position<1){
        System.out.println("位置参数越界");
        return head;
    }
    //1.插入的是头节点情况
    if (position==1){
        nodeInsert.next=head;
        head=nodeInsert;
        return head;
    }
    //2.插入的是中间元素,找出要插入的前一个节点的位置
    int count=1;
    Node cur=head;
    while (position-1>count){
        cur=cur.next;
        count++;
    }
    //3.如果是最后一个元素,也是走这个,找到最后一个节点之前的元素,然后让要插入的元素指向这个元素的next,让这个元素再指向它
    nodeInsert.next=cur.next;
    cur.next=nodeInsert;
    return head;
}

3.4链表删除

链表删除结点也分为三种情况:头结点删除、中间结点删除、尾结点删除

1)头结点删除,让链表头节点的next指向原先头节点的next

在这里插入图片描述

2)中间结点删除,让删除元素前的结点next指向删除后结点的next

在这里插入图片描述

3)尾结点删除,让删除元素前的结点next指向null

在这里插入图片描述

/**
 * 删除节点
 *
 * @param head     链表头节点
 * @param position 删除节点位置,取值从1开始
 * @return 删除后的链表头节点
 */
public static Node deleteNode(Node head, int position) {
    if (head==null){
        return null;
    }
    int length = getLength(head);
    //todo 这里为什么是position>length,因为大于length的结点为null,不能删
    if (position<1||position>length){
        System.out.println("位置越界");
        return head;
    }
    //1.删除头节点
    if (position==1){
        head=head.next;
        return head;
    }
    //2.删除某个位置的节点
    Node cur=head;
    int count=1;
    while (position-1>count){
        cur=cur.next;
        count++;
    }
    cur.next=cur.next.next;
    return head;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值