美文网首页
2,常见数据结构-链表

2,常见数据结构-链表

作者: 数据结构和算法 | 来源:发表于2020-09-26 21:43 被阅读0次

基础知识
链表是一种物理存储单元上非连续的一种数据结构,看名字我们就知道他是一种链式的结构,就像一群人手牵着手一样。链表有单向的,双向的,还有环形的。

1,单向链表

我们先定义一个最简单的单向链表结点类

    class Node<E> {
        E data;
        Node<E> next;

        Node(E data, Node<E> next) {
            this.data = data;
            this.next = next;
        }
    }

这个类非常简单,他只有两个变量,一个是data值,一个是指向下一个结点的指针。我们先来看一下单向的链表是什么样的,


在这里插入图片描述

链表头是不存储任何数据的,他只有指向下一个结点的指针,当然如果我们不需要头结点,直接拿第一个结点当做头结点也是可以的,像下面这样


在这里插入图片描述

单向链表的增删

链表不像数组那样,可以通过索引来获取,单向链表查找的时候必须从头开始往后一个个找,而不能从中间找,也不能从后往前找。我们来看一下链表的添加

1,添加到尾结点

在这里插入图片描述

添加到尾结点比较简单,我们只需要找到之前链表的尾结点,然后让他的next指针指向新的结点即可。

2,添加到中间结点

在这里插入图片描述

添加到中间结点,分为两步,比如我们要在ab结点之间添加新结点n,第一步让新结点n的指针指向b,然后再让a的指针指向新结点n即可。

3,删除链表的尾结点

在这里插入图片描述

只需要让尾结点的上一个结点的指针指向null即可。

4,删除链表的中间结点

在这里插入图片描述

只需要把要删除结点的前一个结点的指针指向要删除结点的下一个结点即可,最好还要把要删除结点的数据清空,并且让他的指针指向null。

2,单向环形链表

环形链表一般分为两种,一种是单向环形链表,一种是双向环形链表。我们首先来看一下单向的环形链表是什么样的


在这里插入图片描述

他和单向非环形链表的区就是,单向非环形链表的尾结点的指针是指向null的,而环形的是指向头结点。关于他的增删和单向非环形的差不多,只不过在尾结点的时候会有点区别,我们主要来看下这两种

1,添加到尾结点

在这里插入图片描述

2,删除尾结点

在这里插入图片描述

3,双向链表

我们来定义一个双向链表结点的类

    class Node<E> {
        E data;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E data, Node<E> next) {
            this.data = data;
            this.next = next;
            this.prev = prev;
        }
    }

双向链表不光有指向下一个结点的指针,而且还有指向上一个结点的指针,他比单向链表多了一个指向前一个结点的指针,单向链表我们只能从前往后找,而双向链表我们不光可以从前往后找,而且还可以从后往前找。我们来看一下双向链表是什么样的。


在这里插入图片描述

双向链表我们可以从头到尾查找,也可以从尾到头查找,双向链表在代码中最常见的就是LinkedList了(java语言),双向链表的增删和单向链表的增删很类似,只不过双向链表不光要调整他指向的下一个结点,还要调整他指向的上一个结点。这里我们来结合图形和代码的方式来分析一下双向链表的增删。

1,添加到尾结点

我们结合着代码来看下

    void linkLast(Object e) {
        final Node<Object> last = tail;
        final Node<Object> newNode = new Node<>(last, e, null);
        tail = newNode;
        if (last == null)
            head = newNode;
        else
            last.next = newNode;
        size++;
    }

总共分为4步


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

2,添加到头结点

    private void linkFirst(Object e) {
        //用临时变量firt保存head结点
        final Node<Object> first = head;
        //创建一个新的结点,让他的pre指针指向null,next指针指向head结点
        final Node<Object> newNode = new Node<>(null, e, first);
        //让head指向新的结点
        head = newNode;
        //如果之前的first为空,说明之前链表是空的,让head和tial同时指向新结点即可
        if (first == null)
            tail = newNode;
        else//如果之前链表不为空,让之前first结点的pre指向新的结点
            first.prev = newNode;
        size++;
    }

添加到头结点和添加到尾结点很类似,图就不在画了,大家可以看下上面的代码。

3,添加到指定结点之前

比如我们在a结点之前添加一个指定的结点,先来看下代码

    void linkBefore(Object e, Node<Object> a) {
        final Node<Object> pred = a.prev;
        final Node<Object> newNode = new Node<>(pred, e, a);
        a.prev = newNode;
        if (pred == null)
            head = newNode;
        else
            pred.next = newNode;
        size++;
    }

假如我们在a结点之前添加一个结点,图就不在细画,简单看一下即可


在这里插入图片描述

4,删除链表的尾结点

 private Object unlinkLast(Node<Object> last) {
     final Object element = last.data;
     final Node<Object> prev = last.prev;
     last.data = null;
     last.prev = null;
     tail = prev;
     if (prev == null)//如果只有一个结点,把尾结点删除,相当于把链表清空了
         head = null;
     else
        prev.next = null;
    size--;
    return element;
}

如果链表只有一个结点的话,我们把它删除,相当于直接把链表清空了,这种很好理解,就不再画。下面画一个长度大于1的链表,然后删除最后一个结点


在这里插入图片描述

5,删除链表的头结点

    private Object unlinkFirst(Node<Object> first) {
        final Object element = first.data;
        final Node<Object> next = first.next;
        first.data = null;
        first.next = null;
        head = next;
        if (next == null)
            tail = null;
        else
            next.prev = null;
        size--;
        return element;
    }
在这里插入图片描述

6,删除链表的中间结点

    Object unlink(Node<Object> x) {
        final Object element = x.data;
        final Node<Object> next = x.next;//x的前一个结点
        final Node<Object> prev = x.prev;//x的后一个结点

        if (prev == null) {//前一个结点是空
            head = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {//后一个结点是空
            tail = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.data = null;
        size--;
        return element;
    }
在这里插入图片描述

4,双向环形链表

双向环形链表在代码中最常见的就是LinkedHashMap了,这个一般用于图片缓存的比较多一些,LRUCache这个类里面主要使用的就是LinkedHashMap(java语言中),通过上面的分析,如果对linkedList能理解的话,那么双向环形链表也就不难理解了,其实原理都差不多,这里就不在过多介绍,下面是双向环形链表的图。

在这里插入图片描述

相关文章

  • 常见数据结构和算法

    常见数据结构 线性数据结构(按顺序具有数据元素的数据结构):数组,堆栈,链表(单链表 双链表),队列非线性数据结...

  • 常见的数据结构

    常见的数据结构有: 数组 链表单链表、双向链表、循环链表、双向循环链表、静态链表 栈顺序栈、链式栈 队列普通队列、...

  • 常见数据结构之(数组、栈、链表、队列、树)

    常见的数据结构,有以下几种: 1、数组(Array) 2、栈(Stack) 3、链表(Linked List) 4...

  • 算法与数据结构知识汇总(二、链表)

    1、概念 2、链表的数据结构 单向链表的数据结构如下图: 上图数据结构为单向链表,简称单链表,该数据结构由若干个节...

  • 什么是链表?

    在了解完什么是数据结构之后,让我们一起来探索下数据结构中常见的一种—链表。 链表 链表是数据结构之一,其中的数据呈...

  • 数据结构——链表(C语言实现)

    提起链表,我们每个人都不会陌生,不管对数据结构的掌握如何,都或多或少的听过与用过链表这样的常见的数据结构。链表是线...

  • Java常用类库与技巧-集合

    一 数据结构常见问题 数组和链表的区别;链表的操作,如反转,链表环路检测,双向链表,循环链表相关操作;队列,栈的应...

  • 复习

    数据结构 数据结构 集合常见数据结构:集合,链表,队列,数组,栈,映射java中:List列表,Set集合,Map...

  • 数据结构笔记

    数据结构课程概览 ================== 1.顺序表 2.链表:单链表,单向循环链表,双链表...

  • 链表、递归、堆、Hashmap、归并排序算法

    java数据结构——链表 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的...

网友评论

      本文标题:2,常见数据结构-链表

      本文链接:https://www.haomeiwen.com/subject/yauhuktx.html