链表的基本概念以及java实现单链表-循环链表-双向链表

本文详细介绍了线性表的概念,重点讲解了链表的三种类型:单链表、循环链表和双向链表。包括它们的定义、插入和删除操作,以及如何在Java中实现这些链表结构。通过实例展示了链表的遍历、清空和判断空操作。文章最后总结了单链表、循环链表和双向链表的特点和优缺点。
摘要由CSDN通过智能技术生成

前言

线性结构是非常简单且常用的数据结构,而线性表则是一种非常典型的线性结构。

本节代码传送门,欢迎star:https://github.com/mcrwayfun/java-data-structure

1. 线性表的定义

通常将线性表定义为n个元素的有限的序列,可以表为为
其中L为表名,a是表中不可再分割的原子数据,亦称为结点或者表项。n是表中表项的个数,也被称为表的长度。当n=0时叫做空表。

线性表的的第一个表项称为表头,最后一个项称为表尾。因为线性表是有序的,这就意味着每个相邻的表项之间都有直接前驱和直接后继的关系,也就是说,除了表头没有直接前驱,其他表项有且仅有一个直接前驱;除了表尾没有直接后继,其他表项有且仅有一个直接后继。

2. 线性表的数据结构

在类库中,java语言包含了一些普通数据结构的实现。该语言的这一部分通常叫做Collections API,表ADT是在Collections API中实现的数据结构之一,看一下其基本的方法:

    public interface Collection<AnyType> extends Iterable<AnyType>
    {
   
        // 返回表中元素个数
        int size();
        // 判断表是否为空
        boolean isEmpty();
        // 清空一张表的数据
        void clear();
        // 判断表是否含有数据项x
        boolean contains(AnyType x);
        // 向表中添加一个新的元素x
        boolean add(AnyType x);
        // 移除表中的元素x
        boolean remove(AnyType x);
    }

3. 链表

链表可以分为有序线性表和无序线性表,本小节仅考虑无序线性表,即链表。链表又分为单链表,环形链表和双向链表。下面将围绕接口Collection中的基本方法实现链表以及完成一些拓展。

3.1 单链表

为了克服顺序表的缺点(新增或删除元素开销大;需要事先分配连续的存储空间),采用链接方式来存储线性表,通常将链接方式存储的线性表成为链表。链表适用于插入或者删除频繁,存储空间需求不定的情形。

3.1.1 单链表的定义

单链表的存储结点包含两部分,一个是数据域(data),用于存储线性表的一个数据元素;一个是指针域(link),用于存放一个指针,该指针指向链表中下一个结点的开始存储地址。用图表示为:

用API可以表示为,其中item为数据域,next为指针域:

     class Node<E> {
        E item;
        Node<E> next;
     }

一个线性表的单链表结构可以用下图表示:

其中,单链表的表头可以通过头指针first找到,其他结点的地址则在前驱结点的link域中,表尾结点没有后继,其link域中存放了一个空指针NULL作为终结。因此,要访问单链表中的任一结点,都需要根据头指针first找到第一个结点,再按照各结点link域中存放的指针顺序往下寻找。因此,操作单链表最重要的便是维护一个头指针first

3.1.2 单链表插入和删除

利用单链表来表示线性表,使得插入和删除操作变得非常方便,只需要改变链表结点中的指针值,无需移动表中的元素,就能高效的完成插入和删除操作。现有单链表

首先来看下单链表的ADT,MyList是一个接口,定义了线性表的基本接口,会放在源码中,这里不作展示

    public class SinglyLinkedList<E> implements MyList<E> {
   

        // 表中元素个数
        int size = 0;
        // 表头指针
        Node<E> first;

        // 存储结点
        private static class Node<E> {
   
            E item;
            Node<E> next;

            public Node(E item, Node<E> next) {
                this.item = item;
                this.next = next;
         }
        }
    }
插入操作

对于插入算法,需要在数据项ai结点后插入一个新的元素x,那么可能会出现3种情况:

(1) 在表的表头插入一个新结点,那么新结点成为表头,并将first指针指向新结点

    // 新结点链向原表头
    newNode.next = first;
    // 新结点成为表头
    first = newNode;

(2) 若ai是链表的最后一个结点,则新结点应追加在表尾。那么新元素成为表尾,且指针域为NULL。定义检测指针cur,需要遍历链表,找到原来的表尾an,新结点则在表尾后插入

    // 循环找到表尾last,last指针域指向新结点
    cur.next = newNode;

(3) 若ai即不是表头,也不是表尾。此时,首先让一个检测指针cur指向ai所在的结点,新结点插入到ai所在结点后

    // 新结点指针域指向ai的下一个结点
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值