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

链表

1.基本介绍:

  • 链表是以结点的方式来存储。

  • 每个节点包含data域,next域:指向下一个节点。

  • 如图:发现链表的各个节点不一定是连续存储

  • 外在这里插入图片描述
链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 链表分带头结点的和没有头节点的链表,根据需求来确定。

  • 链表可分为单链表和双链表

    • 单向链表结构图:

      • head
        结点1
        结点2
        结点3
        null
      • 这里就是一个 size 为3的单链表

      • 其中,在每一个结点类有两个东西:一个就是当前储存的值value,另一个就是指向下一个结点的指针—>注意这里先思考一下这个指针为啥能指向下一个元素呢?[思考完毕点这里🔜!](##2.Java 链表结点连接的原理) Ctrl+点击跳转


2.快速入门

  • 直接上代码 看不懂没关系混个眼熟

  • public class SingleList{
        private Node head = null; //创建一个头指针用来指向链表的第一个结点,当然你也可以不要,有这个头指针对一系列操作更方便。
        
        //创建一个类来封装结点
        //大家想想链表是不是由多个结点组成,他们之间是一种组合关系,所以做成外部类跟内部内的关系。
        //好处:对外隐藏细节,减轻调用者操作量。
        private static class Node {
            int value;
            Node next;
    
            public Node(int value, Node next) {
                this.value = value;
                this.next = next;
            }
        }
        
        //在头部添加
         public void addFirst(int value) {
            //1.链表为空
            //head = new Node(1,null);  下面的两种情况都能处理
            //2.链表不为空
            head = new Node(value, head);
        }
        
        //尾部添加
        //1.找到尾部元素
        private Node findLast() {
            if (head == null) {
                return null;
            }
            Node p = head; // 创建一个指针指向头结点去遍历。
            while (p != null) { 
                p = p.next;  
            }
            return p;
        }
    	 //2.创建按删除的方法
        public void addLast(int value){
            Node last = findLast();
            if (last == null){
                addFirst(value);
                return;
            }
    
            last.next = new Node(value,null);
        }
        //两种遍历方式
        //1.while循环
        public void loop(Consumer<Integer> consumer) {
            Node p = head;  //指向要处理的对象
            while (p != null) {
                consumer.accept(p.value);
                p = p.next;  //更新当前结点
            }
        }
    	//2.for循环
        public void loop2(Consumer<Integer> consumer) {
    
            for (Node p = head; p != null; p = p.next) {
                consumer.accept(p.value);
            }
        }
        
    }
    
  • 这只是在头部和尾部添加元素,这是基础入门,后面熟悉后再说插入。🛴

3.Java 链表结点连接的原理

  • 首先我们来看一个平时经常用到的表达

    • Person p = new Person; 这明细就是创建了一个Person类对象引用命名为p。 在这个=的左边是对象引用,所以存放在栈中,而右边才是真正new出来的对象所以在堆里面。我们可以通过p指向的地址来找到这个对象。

    • eg:

      SingleList list = new SingleList();
      list.addFirst(2);
      list.addLast(54);
      list.addLast(2322);
      
      list.loop2(value->{
                  System.out.println(value);
              });
      
      
    • 我们从第二句话开始看 当执行到了list.addFirst(2332);时候

      • 2
        54
        2322
      • 这个能称为链表吗? 很明显不能 ,因为它只有数字没有链子链接啊。那怎样才能链接起来呢?

      • 回到刚刚的``Person`实例来看

        • 栈里面的:person引用p
          堆里面的newPerson对象0x666
        • new Person在堆开辟的空间地址为0x666 这个时候p就会去指向0x666 。此时 Person p = new Person =0x666 。通过这个可以得出结论当我对象引用持有一个内存地址值,那么,此时这个对象引用就会指向下一个结点,并且还是同一个数据类型Person,在去看看上面,我们想让第一个结点指向下一个。

        • 此时会是这个样子

          • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

          • 我们在掉过头来看第一步SingleList list = new SingleList(); 会是这个样子

          • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

          • 在这里插入图片描述
            结合Person内存图实例来看 就会很快想清楚原因是什么了。

4.插入链表

  • 有了结点连接的原理的基础我们再来crud就很清晰了,只要思绪不乱。

  • 快速入门 中我们已经讲了头尾结点的插入,很简单就不再多做赘述。接下来讲一讲中间插入

  • 先思考:怎样才能在中间加一个元素呢?我们可以根据索引来,先查找到要添加的位置的上一个结点,然后再进行插入操作

    • 1.找到索引位置对应的方法

    •  private Node findNode(int index) {
              int i = 0;
              for (Node p = head; p != null; p = p.next,i++){
                  if (i == index){
                      return p;
                  }
              }
              return null;
          }
      
    • 2.往索引位置加入一个新节点

    • public void insert(int index,int value){
              if (index == 0){
                  addFirst(value); //这里表示如果索引为零代表链表还没有结点,我们就可以调用上面在头部添加结点的方法。
                  return;
              }
              Node prev = findNode(index - 1);//找到上一个结点
              if (prev == null){
                  throw new IllegalArgumentException(String.format("index [%d] 不合法%n", index));  //如果给的索引不合理就抛出一个异常。
              }
              prev.next=new Node(value,prev.next);   //这里让上一个结点指向新的结点
          }
      throw new IllegalArgumentException(String.format("index [%d] 不合法%n", index));  //如果给的索引不合理就抛出一个异常。
              }
              prev.next=new Node(value,prev.next);   //这里让上一个结点指向新的结点
          }
          
      

    差不多就这样了。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值