第3章 线性表

序言

线性表

顺序存储(数组:查询速度快)

链式存储(链表:增加删除速度快)

链表主要解决动态存储数据的问题.

链表增加新节点和删除节点方便,链表比普通查找(顺序引导查找)方便。

静态链表内存大小是规定了的,动态链表可以根据类型来申请不同的内存大小。

线性表的两种存储结构

1.顺序表(数组)

即线性表用顺序存储结构保存数据,数据是连续的。

顺序表的优点:随机访问的速度很快;空间利用率高(存储空间连续分配,不存在浪费)。

顺序表的缺点:顺序表的长度是固定的,如果超出分配的长度就会造成溢出,如果存放的数据太少就会造成空间浪费。

在插入元素和删除元素时(尤其插入和删除的位置不在尾部时),会移动大量的元素,造成性能和效率低下。

2.链表 

即线性表用链式存储结构保存数据,数据是不连续的。

链式存储结构

线性表是什么 

1.线性表是最基本、最简单的一种数据结构。

2.线性表中元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。

3.线性表具有以下几个特征:

  ①有且只有一个“首”元素

  ②有且只有一个“尾”元素

  ③除“首”元素之外,其余元素都有唯一的前驱元素。

  ④除“尾”元素之外,其余元素都有唯一的后继元素。

链表是什么

 

从内存角度出发: 链表可分为静态链表、动态链表。

从链表存储方式的角度出发:链表可分为单链表、双链表、以及循环链表。

1.静态链表

 

2.单链表

即前面介绍的普通链表。单向链表的节点包含值和指向下一节点的引用两项数据。我们将首个节点称为头节点,将最后一个节点称为尾节点,尾节点指向空 None 。

 

3.单向循环链表

如果我们令单向链表的尾节点指向头节点(首尾相接),则得到一个环形链表。在环形链表中,任意节点都可以视作头节点。

 

4.双链表

与单向链表相比,双向链表记录了两个方向的引用。双向链表的节点定义同时包含指向后继节点(下一个节点)和前驱节点(上一个节点)的引用(指针)。

相较于单向链表,双向链表更具灵活性,可以朝两个方向遍历链表,但相应地也需要占用更多的内存空间。

 

/* 双向链表节点类 */
class ListNode(int x) {  // 构造函数
    int val = x;    // 节点值
    ListNode next;  // 指向后继节点的引用
    ListNode prev;  // 指向前驱节点的引用
}

 

 

5.双向循环链表

单链表是不错的,但是呢,人无完人,玉有微瑕,单链表也不是完美的,单链表的缺点是只能往前,不能后退,虽然有循环单链表,但后退的成本还是很高的,需要跑一圈。

在这个时候呢,双向链表就应运而生了,再加上循环即双向循环链表就更加不错了。

所谓双向链表只不过是添加了一个指向前驱结点的指针,双向循环链表是将最后一个结点的后继指针指向头结点。

 

链表典型应用

单向链表通常用于实现栈、队列、哈希表和图等数据结构。

  • 栈与队列:当插入和删除操作都在链表的一端进行时,它表现的特性为先进后出,对应栈;当插入操作在链表的一端进行,删除操作在链表的另一端进行,它表现的特性为先进先出,对应队列。
  • 哈希表:链式地址是解决哈希冲突的主流方案之一,在该方案中,所有冲突的元素都会被放到一个链表中。
  • :邻接表是表示图的一种常用方式,其中图的每个顶点都与一个链表相关联,链表中的每个元素都代表与该顶点相连的其他顶点。

双向链表常用于需要快速查找前一个和后一个元素的场景。

  • 高级数据结构:比如在红黑树、B 树中,我们需要访问节点的父节点,这可以通过在节点中保存一个指向父节点的引用来实现,类似于双向链表。
  • 浏览器历史:在网页浏览器中,当用户点击前进或后退按钮时,浏览器需要知道用户访问过的前一个和后一个网页。双向链表的特性使得这种操作变得简单。
  • LRU 算法:在缓存淘汰(LRU)算法中,我们需要快速找到最近最少使用的数据,以及支持快速添加和删除节点。这时候使用双向链表就非常合适。

环形链表常用于需要周期性操作的场景,比如操作系统的资源调度。

  • 时间片轮转调度算法:在操作系统中,时间片轮转调度算法是一种常见的 CPU 调度算法,它需要对一组进程进行循环。每个进程被赋予一个时间片,当时间片用完时,CPU 将切换到下一个进程。这种循环操作可以通过环形链表来实现。
  • 数据缓冲区:在某些数据缓冲区的实现中,也可能会使用环形链表。比如在音频、视频播放器中,数据流可能会被分成多个缓冲块并放入一个环形链表,以便实现无缝播放。

顺序表和单链表的比较

顺序表:

优点:主要优点是读取元素的速度较快,以及内存空间利用效率高;

缺点:主要缺点是需要预先给出顺序表的最大元素个数,而这通常很难准确做到。当实际的元素个数超过了预先给出的个数,会发生异常。另外,顺序表插入和删除操作时需要移动较多的数据元素。

单链表:

优点:主要优点是不需要预先给出最大元素个数。另外,单链表插入和删除操作时不需要移动数据元素;

缺点:主要缺点是每个节点都需要分为地址域和数据域,因此单链表的空间利用率略低于顺序表。另外,单链表读取一个元素的时间复杂度为O(n);而顺序表读取一个元素的时间复杂度为O(1)  

数组、链表、Hash

1.数组:

数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。但是如果要

在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的

道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。如果应用需要快速访问数据,很少插入和

删除元素,就应该用数组。

2.链表:

链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起,每个结点包括两个部分:一个是存

储数据元素 的数据域,另一个是存储下一个结点地址的 指针。如果要访问链表中一个元素,需要从第一个元素始,

一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以

了。如果应用需要经常插入和删除元素你就需要用链表。

3.Hash:

hash表其实是结合了数组和链表的优点,进行的折中方案。平衡了数组和链表的优缺点。hash的具体实现有很多种,但是需要解决冲突的问题。​

不相同的数据通过hash函数得到相同的key值。这时候,就产生了hash冲突。解决hash冲突的方式有两种。一种是挂链式,也叫拉链法。

挂链式的思想在产生冲突的hash地址指向一个链表,将具有相同的key值的数据存放到链表中。另一种是建立一个公共溢出区。

将所有产生冲突的数据都存放到公共溢出区,也可以使问题解决。​

.Net数据结构

 Array是始终是连续存放的,而ArrayList的存放不一定连续。

 线性表那就是List

.NET 框架中一些集合实现了IList接口,如ArrayList,ListDictionary,StringCollection,String Dictionary.

.NET 线性表中顺序存储采用的是数组,而链式的存储方式则是:IList接口。

栈和队列是非常重要的两种数据结构,栈和队列也是线性结构,线性表、栈和队列这三种数据结构的数据元素和元素的逻辑关系也相同

差别在于:线性表的操作不受限制,栈和队列操作受限制(遵循一定的原则),因此栈和队列也称为受限制的线性表。

和数组一样是一种数据结构,数组不支持高效的删除和插入,因为要涉及到数据的移动,并且数组的大小是固定的。

但是链表克服了这些缺点,但是他也有自己的缺点,需要额外的内存存储维持链表的变量,并且不能像数组那样随机访问。

所以这就是计算机科学中的tradeoff吧,有得必有失。

.NET中自带的链表是LinkedList类,并且已经直接实现成了双向循环链表。

Java数据结构

List 只要有两个实现类(ArrayList 和linkedList ),ArryList是基于数组实现,LinkedList是基于链表实现。

LinkedList是List接口的双向链表实现。由于是链表结构,所以长度没有限制;而且添加/删除元素的时候,只需要改变指针的指向(把链表断开,插入/删除元素,再把链表连起来)即可,非常方便,而ArrayList却需要重整数组 (add/remove中间元素)。所以LinkedList适合用于添加/删除操作频繁的情况。

LinkedList是java对双链表的一种实现,定义了链表的双端操作。这种链表的集合有一个很好的优点:其可以实现元素的快速添加和删除。但也有一个很大的缺点:如果获取一个指定位置的元素,则要通过遍历的方式,这种方式十分低效率。所以在集合选取的时候也考虑此集合主要用于元素的查看和修改还是元素的增删。

资料

http://www.cnblogs.com/songwenjie/p/8678212.html

https://www.cnblogs.com/fivestudy/p/10674966.html

https://blog.csdn.net/javazejian/article/details/52953190

动画模拟:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

数据结构-链表

(超详细) 动手编写 — 链表 (Java实现)

posted @ 2016-02-26 17:08  ~沐风  阅读(292)  评论(0编辑  收藏  举报