链表的概念+MySingleList的实现

文章目录


链表

顺序存储:顺序表/ArrayList

  • 优点:给定下标的时候,查找速度快 o(1)
  • 缺点:插入和删除时要移动元素o(n) 、每次扩容会浪费资源

由于ArrayList的缺点,我们引入链式存储:链表

一、 链表的概念

1.概念

  • 链表在物理层面是非连续的存储结构,在逻辑上是连续的,通过引用链接次序来实现它的逻辑顺序
  • 链表由一个个结点组成,结点从堆上申请
  • 一个结点起码包含两个域,val域存储数组 、next域存储下一个结点的地址

2. 结构

链表由多种结构:由头、无头、单向、双向、循环、非循环

排列组合后有八种,重点了解无头单向非循环链表和无头双向链表

二、MySingleList的实现

无头单向非循环链表的实现

1 .定义内部类

java 复制代码
public class MySingleList {
    //链表是由一个一个的结点所组成的,可以把Node定义成一个内部类
    static class Node {
        public int val;//存储的数据
        public Node next;//存储下一个结点的地址
        public Node(int val) {//先不设置next,创建一个新的结点时,还不知道下一个结点是什么
            this.val = val;
        }
    }
}

链表是由一个个的结点所组成的,可以把Node定义成一个内部类

  • 定义一个val变量存储数据
  • 定义一个Node类型的next变量存储下一个结点的地址
java 复制代码
  public Node head;//代表当前链表的头结点的引用

head 代表当前链表的头结点的引用

  • 因为现在写的是不带头结点的单链表,通过一个变量head,来引用当前链表的头结点
  • head引用哪个结点,哪个就是当前链表的头结点

2 .创建链表

java 复制代码
public void creatList(){//创建一个链表
        Node node1 = new Node(12);
        Node node2 = new Node(86);
        Node node3 = new Node(33);
        Node node4 = new Node(45);
        node1.next =node2;
        node2.next =node3;
        node3.next =node4;
        head=node1;//创建头结点
    }

创建各个结点,给定val值,每个结点的next依次引用下一个结点的地址

确定头结点,head引用node1所引用的地址

3. 遍历链表并打印

java 复制代码
public void disPlay() {//不要改变head
        Node cur = head;//定义一个cur,让cur移动,head不动
        //链表遍历完,head==null
        //遍历到尾部,不打印最后一个,head.next==null
        while (cur!=null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

1.通过cur来代替head,保证head不会发生改变

2.循环的判断依据是cur!=null,这样能遍历完整

cur.next!=null会少打印最后一个

4.查找单链表中是否包含关键字key

java 复制代码
public boolean contains(int key) {
        Node cur = head;
        while (cur != null) {//当cur为空时,遍历完
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;//cur向后移动
        }
        return false;
    }

5.得到链表的长度

java 复制代码
 public int size(){
        int count = 0;
        Node cur = head;
        while (cur!=null) {//遍历一遍链表 o(n)
            count++;
            cur=cur.next;
        }
        return count ;
    }

遍历数组,直到cur为null跳出循环,说明已经走完整个链表,返回记录的次数

6.头插法

java 复制代码
 public void addFirst(int data){
        Node node = new Node(data);//新建一个结点
        node.next=head;
        head = node;
    }

1.创建新的结点

2.将新结点的next域存放原本头结点的地址值

3.让新结点成为新的头结点

这样就完成了头插法的实现

7. 尾插法

java 复制代码
 public void addList(int data) {
        Node node = new Node(data);
        if (head == null) {//判断头结点为空的情况
            head = node;//让新建的结点成为头节点
            return;//
        }

        Node cur = head;//让cur代替head
        while (cur.next != null) {
            cur = cur.next;
        }//当cur的next为null时,找到了最后一个结点
        //找到最后一个结点后,插入node结点
        cur.next = node;
    }

1.创建一个新结点

2.判断头结点是否为空

3.遍历链表找到当前最后一个结点

4.将新结点插到末尾
链表的插入只是修改指向

8.任意位置插入

java 复制代码
public void addIndex(int index, int data) throws IndexOutOfException {
        checkIndex(index);//先检查index的值是否合法
        if (index == 0) {//如果index=0,调用头插法
            addFirst(data);
            return;
        }
        if (index == size()) {//如果index的值为链表长度,调用尾插法
            addList(data);
            return;
        }
        Node cur = findIndexSubOne(index);//找到index的前一个元素
        Node node = new Node(data);
        node.next = cur.next;
        cur.next = node;
    }

    private void checkIndex(int index) {
        if (index < 0 || index > size()) {
            throw new IndexOutOfException("index位置不合法");
        }
    }

    //走index-1步,返回当前索引的地址
    private Node findIndexSubOne(int index) {
        Node cur = head;
        int count = 0;
        while (count != index - 1) {
            cur = cur.next;
            count++;
        }
        return cur;
    }

1.调用checkIndex方法先检查index的值是否合法,不合法抛出异常

2.判断索引,如果是0,调用头插法,如果等于链表长,调用尾插法

3.调用findIndexSubOne方法,找到index的前一个节点,返回地址值

4.创建一个新结点,使新结点的next域的值等于前一个结点next域的值

5.再让前一个结点的next域,引用新结点的地址值。

8.删除结点

删除第一次出现关键字为key的结点

java 复制代码
 public void remove(int key) {
        if (head == null) {//判断是否是空节点
            return; //一个结点都没有
        }
        if (head.val == key) {//如果当前头结点的元素等于要删除的元素
            head = head.next;//头结点向后移动
            return;
        }
        Node cur = searchPrev(key);//找到key的前驱结点
        if (cur == null) {//没有要删除的key
            return;
        }
        Node del = cur.next;//要删除的结点
        cur.next = del.next;
        //or cur.next = cur.next.next;
    }

    private Node searchPrev(int key) {//找到key的前一个结点

        Node cur = head;
        while (cur.next != null) { //cur.next==null,说明cur已经走到最后一个结点
            if (cur.next.val == key) {//如果cur下一个结点的值等于key
                return cur;//找到key的前一个结点
            }
            cur = cur.next;
        }
        return null;//没有你要删除的结点
    }

1.先定义searchPrev方法,遍历链表,如果cur的下一个结点的值=key,cur就为key的前驱结点

2.判断:如果头结点为空,链表中没有元素,直接返回

3.如果头结点的值,就是要删除的元素,头结点后移,直接返回

4.都不是,进入searchPrev方法,返回前驱结点cur;

5.如果返回的cur==null,说明遍历完链表,没有要删除的元素

6.要删除的结点del就是cur的下一个结点

7.让cur结点的next域引用del的下一个结点的地址;

完成删除

删除所有值为key的节点

java 复制代码
 public void removeAllKey(int key) {
        if (head == null) {//如果头结点为空,直接返回
            return ;
        }
        Node prev = head;
        Node cur = head.next;
        while (cur != null) {
            if (cur.val == key) {
                prev.next = cur.next;
                //cur = cur.next;
            } else {
                prev = cur;
                //cur = cur.next;
            }
            cur = cur.next;
        }
        if (head.val == key) {//最后处理头结点
            //如果头结点的值等于key,头结点后移
            head = head.next;
        }
    }

1.判断头结点是否为空

2.设置prev为头结点,cur为下一个结点(头结点key的情况最后考虑)

3.遍历链表,直到cur==null为止

4.如果cur的值等于key,prev的next域引用cur下一个结点的地址,cur后移一位

5.否则,prev移动到cur,cur后移一位

6.最后处理头结点,如果头结点刚好等于key,将头结点后移一位。

清空
java 复制代码
   public void clear(){//清空,让链表中所有的结点都不被引用
        head =null;
    }

清空,让链表中所有的结点都不被引用,head置为空

点击移步博客主页,欢迎光临~

相关推荐
云空4 分钟前
《解锁 Python 数据挖掘的奥秘》
开发语言·python·数据挖掘
HSunR4 分钟前
概率论 期末 笔记
笔记·概率论
秋意钟10 分钟前
Spring新版本
java·后端·spring
椰椰椰耶12 分钟前
【文档搜索引擎】缓冲区优化和索引模块小结
java·spring·搜索引擎
mubeibeinv13 分钟前
项目搭建+图片(添加+图片)
java·服务器·前端
青莳吖15 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
红色的山茶花15 分钟前
YOLOv9-0.1部分代码阅读笔记-loss_tal.py
笔记·深度学习·yolo
Buleall22 分钟前
期末考学C
java·开发语言
重生之绝世牛码24 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行30 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试