数据结构和算法 – 8.链表

时间:2023-03-10 07:25:37
数据结构和算法 – 8.链表

8.1.数组存在的问题

在处理列表的时候数组是常用的数据结构。数组可以对所存储的数据项提供快速地存取访问,而且它很易于进行循环遍历操作。当然,数组已经是语言的一部分了,用户不需要使用额外的内存,也不需要花费因使用用户自定义的数据结构所需的处理时间。
然而正如所见,数组不是一种最佳的数据结构。在无序数组中查找一个数据项是很慢的,这是因为在找到要查找的元素之前需要尽可能地访问到数组内的每一个元素。有序(排序)数组对查找而言会更加高效一些,但是插入和删除操作还是很慢的,因为需要向前或向后移动元素来为插入留出空间,或者为删除移除空间。更别提在有序数组内还需要为插入元素查找到合适的位置了。

 

8.2.定义

链表是被称为节点的类对象的群集。每一个节点通过一个引用链接到列表内的后继节点上。节点包括存储数据的字段和节点引用的字段。到另外一个节点的引用被称为是链接。

数据结构和算法 – 8.链表

数组:元素是通过位置(索引)进行引用

链表:元素是通过它们与数组其他元素的关系进行引用

大家会说“ Bread”跟在“ Milk”的后面,而不会说“ Bread”是在第二个位置上。遍历链表是从链表的起始节点一直到末尾节点。

还需要注意的一点就是对链表结尾的标记是通过指向空( null)值实现的。既然是在内存中处理类对象,所以就用空( null)对象来表示列表的末尾。

 

在许多链表的实现中通常会包含一个被称为“头节点”的特殊节点来作为链表的起始位置。

数据结构和算法 – 8.链表

插入操作成为一种非常有效的工作。所要做的就是

1.把要插入节点之前节点的链接改为指向要插入的节点,

2.并且把新节点的链接设为指向插入之前前节点所指向的节点。

把数据项“ Cookies”添加到链表内“ Eggs”的后面

数据结构和算法 – 8.链表

 

从链表中移除数据项也是如此容易。

1.就是简单地把要删除节点之前节点的链接重定向到删除节点所指向的节点,

2.并且把删除节点的链接设为空( null)就可以了

数据结构和算法 – 8.链表

 

8.3 面向对象链表的设计

链表的设计至少包含两个类

这里会创建一个 Node 类,而且每次向链表添加节点的时候会实例化一个 Node对象。

链表内的节点通过索引与其他节点相互连接在一起。而且把这些索引设置为使用创建在一个独立的 LinkedList类中的方法。

 

8.3.1.Node类

节点是由两个数据成员组成的:存储着节点数据的 Element,以及存储着指向表内下一节点引用的 Link。

为了完成 Node 类的定义,至少需要两种构造器方法。明确地需要一个默认的构造器来创建一个空的 Node,其中的 Element 和 Link 都设为空( null)。

还需要一个参数化的构造器用来给成员 Element 赋值数据,并且把成员 Link设置为空( null)。

public class Node
{
public Object Element;
public Node Link;
public Node()
{
Element = null;
Link = null;
}
public Node(Object theElement)
{
Element = theElement;
Link = null;
}
}

 

8.3.2 LinkedList

LinkedList 类用来创建链表中节点之间的链接。

需要一种构造器方法来实例化链表。

此类中唯一的数据成员就是头节点。

    public class LinkedList
{
protected Node header;
public LinkedList()
{
header = new Node("header");
..
}
}

头节点从其 Link 字段设置为空( null)开始。当把第一个节点添加到链表中的时候,会把头节点的 Link 字段设置成指向新的节点,并且把新节点的 Link 字段设置为空( null)。

 

 

8.4 链表设计的改进方案

8.4.1 双向链表

8.4.2 循环链表

8.5.使用 Iterator

LinkedList 类存在的一个问题就是不能在链表内同时引用两个位置。大家可以引用链表内的任何一个位置(当前节点、前一个节点等等),但是如果想指定两个甚至更多个位置,比如想从链表中移除一段范围内的节点,就需要一些其他方法了。这种方法就是 Iterator 类。

相关文章