单链表,带头单链表---(上)

什么是单链表?

在这里插入图片描述

元素之间逻辑连续,物理上不连续的线性表。
所谓的单链表叫单向链表只能从链表的第一个节点走到最后节点。
链表中最重要的四句代码:

Node node = new Node(1);
node.next = head
//当链表为空时,仍然可以这样写; node就是第一个节点,node.next = null
head = node
size ++;

一、单链表的增删查改

插入

头插:
在这里插入图片描述

//在当前链表的头部添加元素
    public  void addFirst(E val){
         Node node = new Node(val);
         node.next = head;
         head = node;
         size ++;
    }

尾插(默认插入):

public void add(E element) {

         add(size,element);
    }

中间插入:
在这里插入图片描述

 public void add(int index, E element) {
        // 1.base case,边界判断
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("add index illegal!");
        }
        // 2.判断没有前驱的情况
        if (index == 0) {
            addFirst(element);
            return;
        }
        // 3.确实是中间位置的插入,寻找待插入位置的前驱!
        Node prev = head;
        for (int i = 0; i < index - 1; i++) {
            prev = prev.next;
        }
        // prev走到待插入位置的前驱
        Node node = new Node(element);
        node.next = prev.next;
        prev.next = node;
        size ++;
    }

删除

用索引删除
在这里插入图片描述
在这里插入图片描述

   public E removeByIndex(int index) {
        // 1.base case
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("remove index illegal!");
        }
        // 2.判断头节点的删除问题
        if (index == 0) {
            Node node = head;
            head = head.next;
            node.next = null;
            size --;
            return node.val;
        }
        // 3.现在确实是中间位置的删除
        Node prev = head;
        for (int i = 0; i < index - 1; i++) {
            prev = prev.next;
        }
        Node node = prev.next;
        prev.next = node.next;
        node.next = null;
        size --;
        return node.val;
    }

删除某一元素(有重复删除第一个)
待删除元素在链表头部
在这里插入图片描述
待删除元素在链表的中间位置
在这里插入图片描述

 public void removeByValue(E element) {
        // 1.base case
        if (head == null) {
            return;
        }
        // 2.判断头节点恰好是待删除的节点
        if (head.val.equals(element)) {
            head = head.next;
            size --;
            return;
        }
        // 3.此时头节点不为空其一定不是待删除的结点
        Node prev = head;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // prev走到了待删除节点的前驱位置
                prev.next = prev.next.next;
                size --;
                return;
            }
            prev = prev.next;
        }
        // 4.链表中没有待删除的节点
        System.out.println("当前链表中不存在值为" + element + "的节点");
    }

删除某一元素(有重复全部删除)
重复元素出现在头节点位置
在这里插入图片描述
重复元素出现在链表中间位置
在这里插入图片描述

  public void removeAllValue(E element) {
        // 1.base case
        if(head == null) {
            return;
        }
        // 2.若头节点就是待删除的节点且出现连续的待删除节点
        while (head != null && head.val.equals(element)) {
            head = head.next;
            size --;
        }
        if (head == null) {
            // 整个链表已经删除完了
            return;
        }
        // 3.头节点一定不是待删除的节点且链表不为空!
        // prev一定指向的不是待删除的结点~
        Node prev = head;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // 此时prev就是待删除节点的前驱
                prev.next = prev.next.next;
                size --;
            }else {
                // 只有后继节点不是待删除的结点才能移动prev引用!
                prev = prev.next;
            }
        }
    }

修改

 public E set(int index, E element) {
        // 合法性校验
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("set index illegal!");
        }
        // 遍历走到index对应的元素
        Node x = head;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        // 此时x就落在了待修改的节点位置
        E oldVal = x.val;
        x.val = element;
        return oldVal;
    }

查询

public E get(int index) {
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("get index illegal!");
        }
        Node x = head;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return x.val;
    }

二、带头单链表

通过上述代码发现,单链表的核心操作都在找前驱!但是头节点没有前驱,因此在各项操作之前都在处理头结点的情况。
所谓的带头单链表指的是,链表的头部节点不存储具体元素,就只是作为链表的头来使用,所有的存储具体值的结点一定都在这个头结点的后面。
不带头单链表指的是,链表头结点若存在,则头结点也存储具体元素,而带头单链表的头结点不存储具体元素。

增删查改

插入

//头插
    public void addFirst(E element){
         add(0,element);
}
//默认尾插
    @Override
    public void add(E element) {
        add(size,element);
    }

//中间位置插入
    @Override
    public void add(int index, E element) {
        //合法性校验
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("add index illegal!");
        }
        //定义前驱节点为虚拟头节点
        Node prev = dummyHead;
        //遍历链表,确定前驱节点位置,prev一定不指向代操作节点
        for (int i = 0; i < index; i++) {
            prev = prev.next;
        }
        //创建新节点,存放待插入元素
        Node node = new Node(element);
        node.next = prev.next;
        prev.next = node;
        size ++;
    }

删除

  //删除索引为index的元素
    @Override
    public E removeByIndex(int index) {
        // 1.base case
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("remove index illegal!");
        }
        SingleHeadList.Node prev = dummyHead;
        for (int i = 0; i < index; i++) {
            prev = prev.next;
        }
        SingleHeadList.Node node = prev.next;
        prev.next = node.next;
        node.next = null;
        size --;
        return (E) node.val;
    }



    //删除元素值为element的第一个元素
    @Override
    public void removeByValue(E element) {
        // 1.base case
        if (dummyHead.next == null) {
            return;
        }
        SingleHeadList.Node prev = dummyHead;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // prev走到了待删除节点的前驱位置
                prev.next = prev.next.next;
                size --;
                return;
            }
            prev = prev.next;
        }
        // 链表中没有待删除的节点
        System.out.println("当前链表中不存在值为" + element + "的节点");
    }


//删除元素值为element的所有元素
    @Override
    public void removeAllValue(E element) {
        // prev一定指向的不是待删除的节点
        Node prev = dummyHead;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                prev.next = prev.next.next;
                size --;
            }else {
                prev = prev.next;
            }
        }
    }

修改

//修改索引为index位置的元素为element
    @Override
    public E set(int index, E element) {
        // 合法性校验
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("set index illegal!");
        }
        // 遍历走到index对应的元素
        SingleHeadList.Node x = dummyHead.next;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        // 此时x就落在了待修改的节点位置
        E oldVal = (E) x.val;
        x.val = element;
        return oldVal;
    }

查询

//获取索引为index位置的元素
    @Override
    public E get(int index) {
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("get index illegal!");
        }
        SingleHeadList.Node x = dummyHead.next;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return (E) x.val;
    }

总结

对于单链表的学习主要在于理解,多画图有利于加深理解!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小杨爱喝橙汁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值