单链表简介
单链表的结构如上,有别于连续存储在内存中的数组,是一种以链式形式的存储结构。下面详细介绍下该链表中存在的元素:
结点:构成单向链表的基本单元我们称为结点,其中每个结点都有一个data区和一个结点指向区。data区就是存放数据的地方,一般存储基本类型数据或者引用对象的地址,结点指向区存储下一个结点的地址。
头结点:指向单链表中的第一个结点,即首结点。
尾结点:指向单链表中的最后一个结点。
链表长度:记录链表中存在的结点个数,即我们存储的数据个数。
单链表的实现
链表的基本介绍如上,下面我们需要根据代码来进行说明。本博客主要流程示例代码使用java语言,每块代码前都标示是属于哪个java文件下的哪个类。废话不多开始!!!
结点类的创建
创建链表的基本单元结点类如下,该类提供了数据存储区和接点指向区,还提供了便捷的构造函数,以及结点操作的相关方法:
单链表类的创建
单链表类SingleLinkedList
主要用于对数据的添加、删除、打印,反转等功能,下面是SingleLinkedList
的主要成员变量的介绍:
添加功能
上面是SingleLinkedList
数据成员的代码,这里我们给它加入添加功能的方法,添加方法分为了两种,一种是直接在链表尾部添加一个数据,另一个是在指定位置结点的后面添加一个数据。
我们来详细的来看下这三个方法:
1.private void addElement(Node<E> frontElement,Node<E> element)
:这个是添加数据的核心处理方法,该方法接收要添加的结点的前一个结点,以及要添加的结点,如果链表为空,或者想再链表的头部添加结点时frontElement
为空。这种情况的添加要操作header的指向;还有种情况是frontElement
有值,说明是在链中或者链尾添加数据,那就将frontElement.next
给到新结点的next,然后新结点追加上在frontElement.next
上即可。这里面还有个注意点是关于尾结点的更改,如过新添加的结点的next是null值的话,说明该添加的结点取代了原来的尾结点,需要重设footer的引用对象。
2.public void add(E e)
:这个是在链表的尾部添加e数据,调用addElement方法传递的尾结点的引用以及新值。
3.public void add(int index,E e)
:该方法是在index位置的结点后面添加新的元素,里面主要是获取了index所在的结点,然后传值给核心方法addElement
。
删除功能
删除功能也提供了两种方式:一个将index所在的数据删除,另一种是将对象地址相同的对象删除。除了这两个方法还提供了一个集中处理删除操作的方法,以下是代码的展示。
现在对这三个方法进行详细介绍:
1.private Node<E> deleteElement(Node<E> frontElement,Node<E> element)
:该方法是删除功能的核心方法,跟添加功能的核心方法类似都有两个参数,分别对应要删除的结点的前一个结点和要删除的结点。删除功能相对于添加要容易一点把删除头结点的区分开来就ok,即frontElement
为null时表示要删除头结点,操作header
的指向为header.next
即可。frontElement
有值时执行frontElement.next
为要删除结点的下一个element.next
即可。还有就是删除的结点如果next
为空时说明删除的是尾结点,需要调整footer的引用为frontElement
。
2.public E delete(int index)
:删除index处的数据,并将这个数据返回。主要是获取删除方法需要的两个参数。
3.public E delete(E e)
:删除数据e,如果e不存在该方法的调用不会骑任何作用。
链表的反转
链表的反转即将链表原有的数据顺序以及指向颠倒下,请先看源码实现:
单链表的反转其实可以看做是数据上的逆序,举个列子列表内有四个数据分别是[A->B->C->D->null]逆序后为[D->C->B->A->null]。下面我们看看上面的两个方法都做了什么事情:
1.private void reverse(Node<E> currentElement)
:该方法内部采用递归方式将数据分散开为A、B、C、D。然后进行逆序指向,即D->C->B->A->B。这个是调用完该方法后的指向。其中存在的问题是header指向的是A,footer指向的是D,还有A的下一个指向为B。
1.public void reverseSingleLinkedList()
:这个方法除了调用reverse
方法外还要对上面的存在的问题进行处理,先进行header和footer的更改,然后将footer的下一个指向null。最终将变成D->C->B->A->null的顺序。
其它的方法
单链表的核心方法上面已经介绍过了,下面把剩下的其它代码贴出来分别是获取指定index上的实例数据public E getObject(int index)
、结点数据private Node<E> getNode(int index) throws Exception
以及遍历链表的方法public void printSingleLinkedList()
。
总结
单向链表是由一个个结点有顺序的链接而成的结点列表,第一个结点有header指向是头结点最后一个结点由footer指向是尾结点。更普通的线性结构的数组比较起来具有以下的优点:结点的添加(插入)、删除比较方便,不需要移动数据只需要更新下一个结点指向即可;除此之外链表在空间利用上更好点不需要占用较大的连续存储空间;当然也会有缺点:查询的操作没有线性表的效率高。所以在使用这两种结构时要根据需求决定,如果插入和删除数据比较多的用单链表比较合适,查询比较多的用线性数组要好点。
附加
更多相关内容请前往内功修炼系列!!!