数据结构篇 链表

单链表

大纲[脑图]

lianbiao

1.链表是什么

链表的定义我一看还有点懵,我的理解链表就是链表。我从百度百科找到其定义:

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

其实就是一种非线性存储结构,动态申请空间,不连续(数组是连续的一块空间)。可以通过头结点找到所有节点

2.链表分类

  • 单链表: 每个节点含有当数据和下个节点地址的指针
  • 双链表: 每个节点含有当前数据和下个节点,上个节点地址的指针
  • 循环链表: 收尾节点链接在一起的链表

Q1: 什么是指针?
突然想到这个问题,仔细想想好像我们理所当然就知道指针是什么,但是仔细想一想,指针的定义是什么却又不是很清楚。

3.链表的特点

  • 非连续,空间不固定的存储结构,与数组相比,链表不需要一整块大的存储空间,因为自身带有下个节点地址的指针,链表是线性的存储结构,能从一个节点找到下一个节点,但是无法找到下下个节点的
  • 但是相对数组来说,随机查询代价很高了,链表只能one by one的便利,数组可以指定查询那个位置的数据
  • 相对数组来说,链表的删除和插入代价比较低,因为最多影响到相邻的两个节点,如果是首尾节点,代价更低了。数组就需要移位,成本比较大
  • 因为链表的每个节点都要存储下个节点的地址指针,其空间利用率是没有数组高的,其数据域占用空间的比例越高,空间利用率就越大

4.链表的应用场景

链表是一种基础数据结构,一般用来实现队列(先进先出)和栈(先进后出)。然后因为这个我发现我的脑图有东西画错了。队列和栈是可以同数组实现。没有用数组实现链表这种说法。
具体的应用场景有消费者-生产者场景里面的消息中间件,还有线程池里面的存放线程的容器

相关知识点:
数组,线程池,消息中间件Redis(还没写,后续写可再补超链接)

5.简单 单链表Java

仅实现了单链表,而且不是泛型,用的Integer
代码如下
主结构是MySingleLinkedList
测试类

package com.java.datastructure;

//手动实现单链表
public class MySingleLinkedList {
   //链表头结点 头结点不是第一个节点,头节点指向第一个节点
   public Node head;
   //链表的长度
   public int size;

   //构造器
   public MySingleLinkedList(){
       size = 0;
       head = new Node();
   }
   //内部类,构造链表节点
   private class Node{
       //数据域
       Integer data;
       //下个节点的指针
       Node next;

       public Node(){}
       //链表构造函数
       public Node(Integer data,Node next){
           this.data = data;
           this.next = next;
       }
   }
   //获取链表长度
   public int getSize(){
       return size;
   }
   //添加元素 尾部添加
   public boolean add(Integer data){
       //初始化新来的数据
       Node tailNode = new Node(data, null);
       Node temp=head;
       while(temp.next != null){
           temp = temp.next;
       }
       temp.next = tailNode;
       size++;
       return true;
   }
   //插入元素 链表任意位置添加
   public boolean insert(int index, Integer data){
       //异常判断
       if(index>size || index < 1){
           System.out.println("index输入不和规范");
           return false;
       }
       //插入逻辑,往index个数据里面插入,相当于在原index之前,index-1之后插入数据
       if(index>=1 && index <= size){
           int i = 1;
           Node newNode = new Node(data,null);
           Node temp = head;
           while(i < index){
               temp = temp.next;
               i++;
           }
           newNode.next=temp.next;
           temp.next = newNode;
           size++;
           return true;
       }
       System.out.println("有其他未知异常");
       return false;
   }
   //移除元素 尾部移除 记得长度-1
   public boolean remove(){
       if (head.next == null){
           System.out.println("链表没有数据,不允许移除元素");
           return false;
       }
       Node temp = head;
       for (int i = 1; i < size; i++){
           temp = temp.next;
       }
       //这个时候自己就是最后一个元素了,将自己置为空就结束
       temp.next = null;
       size--;
       return true;
   }
   //移除元素 任意位置移除 记得长度-1
   public boolean remove(int index){
       if (index>size || index <=0 || size < 1){
           System.out.println("下标错误或数组为空,请检查");
           return false;
       }
       if (index>=1 && index <= size){
           Node temp = head;
           for (int i = 1; i < index; i++){
               temp = temp.next;
           }
           //当前节点的下个先点被移除,即当前节点指向下下个节点
           temp.next = temp.next.next;
           size--;
           return true;
       }
       System.out.println("出现未知错误");
       return false;
   }
   //获取某个位置的元素
   @Deprecated
   public Integer get(int index){
       if (index > size || index < 1 || size < 1){
           System.out.println("链表长度为空,或者该下标不在范围内,请检查");
           return null;
       }
       if (index <= size && index >= 1){
           Node temp = head;
           for (int i = 1; i <= index; i++){
               temp = temp.next;
           }
           return temp.data;
       }
       System.out.println("未知异常");
       return null;
   }
   //修改某个位置的元素 并返回旧的元素
   @Deprecated
   public boolean modify(int index, Integer data){
       if (index < 1 || index > size || size < 1){
           System.out.println("下标异常或链表长度为空,请检查");
           return false;
       }
       if (index >=1 && index < size){
           Node temp = head;
           for (int i = 1; i <= index; i++){
               temp = temp.next;
           }
           temp.data = data;
           return true;
       }
       System.out.println("未知异常");
       return false;
   }
   //查询 查询是否包含某一元素
   public boolean contains(Integer data){
       Node temp = head;
       while (temp.next != null){
           temp = temp.next;
           if (temp.data.equals(data)) return true;
       }
       System.out.println("该元素不存在");
       return false;
   }
   //遍历 打印链表所有元素
   public String toString(){
       System.out.println("五更依旧朝花落-打印开始:长度为"+getSize());
       if(head.next == null){
           System.out.println("该链表没有数据");
           System.out.println("打印结束");
           return null;
       }
       int i=0;
       Node temp = head;
       while (temp.next != null) {
           temp = temp.next;
           i++;
           System.out.print("    这是第" + i + "个元素:" + temp.data);

       }
       System.out.println("\n本次打印结束");
       return null;
   }

}

测试代码

package com.java.datastructure;

public class TestSingleLinkedList {
    public static void main(String[] args) {
        //测试1 往空链表添加元素
        MySingleLinkedList mySingleLinkedList = new MySingleLinkedList();
        mySingleLinkedList.toString();
        //System.out.println("测试1 往空链表添加元素");
        for (int i = 1; i < 10; i++){
            mySingleLinkedList.add(i);
        }
        //mySingleLinkedList.toString();

        //测试2 往非空链表添加元素
        System.out.println("测试2 往非空链表添加元素");
        for (int i = 10; i< 20;i++){
            mySingleLinkedList.add(i);
        }
        mySingleLinkedList.toString();
        //测试4 中间添加元素
        System.out.println("测试3 中间添加元素");
        mySingleLinkedList.insert(3, 30);
        mySingleLinkedList.toString();
        //测试5 往不存在的位置添加元素
        System.out.println("测试4 往不存在的位置添加元素");
        mySingleLinkedList.insert(-1, 00);
        mySingleLinkedList.toString();
        //测试6 修改某个位置元素,但是这个位置不存在
        System.out.println("测试6 末尾元素删除");
        mySingleLinkedList.remove();
        mySingleLinkedList.toString();
        //测试7 删除不存在的元素
        System.out.println("测试7 删除不存在的元素");
        mySingleLinkedList.remove(-1);
        mySingleLinkedList.toString();
        //测试8 删除第3个元素
        System.out.println("测试8 删除第三个元素");
        mySingleLinkedList.remove(3);
        mySingleLinkedList.toString();

        System.out.println("测试9 改第3个元素为33");
        mySingleLinkedList.modify(3,33);
        mySingleLinkedList.toString();
        System.out.println("测试10 改一个不存在的元素");
        mySingleLinkedList.modify(-1,0);
        mySingleLinkedList.toString();

        System.out.println("测试11 查询18号元素");
        System.out.println("18号元素为"+mySingleLinkedList.get(18));
        System.out.println("测试12 查询不存在的元素19号");
        mySingleLinkedList.get(19);
    }
}

6.总结

  • 写代码总能发现各种各样的问题
  • 边界值是否注意到了,是否注意到空指针异常
  • 链表本身其实非常简单,但是写起来还是费了点时间,一方面是好久没写代码了,有点手生
  • 我写的那个head不是第一个节点,其next指向第一个节点
  • 本来计划今天搞链表,泛型,集合,在看看泛型链表怎么搞。结果一个链表搞到现在22点多。主要是开始大环境还费了点时间
  • 如果一个问题当时没有想通,暂时不要去想,去干点别的,说不定突然灵机一动至知道怎么做了,我吃饭的时候就突然想明白了一个空指针异常的问题
    脑图也更新下
    开始的图片有错误,后面写博客时又更新了下

题外话

  • 发现自己之前写的博客都是什么垃圾,那篇拆机以及解决idea的黄标还是可以的,可以个自己留个纪念,看看之前的
  • 很多东西自己理解了,然后不参考任何其他东西,凭借自己大脑理解写出来的印象更深刻
  • 写文字也是一个技术活,有些东西知道但是不见得写的出来,而且排版也不一定排的好
  • 算是这个这个复习第一篇博客,后序可能会回头来改
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值