1、数据类型

集合E上线性表为E中有穷元素排列的序列 L=(e0,e1,...,en-1) ei∈E n>=0。对于L表元素的关系称为下一个关系,是一个二元组集合{<e0,e1>,...,<en-2,en-1>}。将线性表作为一种数学对象加以研究,建立抽象数学模型需要考虑:

①实现者角度:内部结构如何组织;提供必要外部操作

②使用者角度:结构提供哪些操作;如何有效使用

线性表抽象数据类型:

线性表实现模型有顺序表、链接表两种。

2、顺序表(连续存储空间)

假设一顺序表对象,起始位置内存I0,一个元素所需存储单元c=size(元素),元素ei存储地址计算:Loc(ei)=Loc(e0)+c*i。顺序表创建与访问:创建空表、访问下表i元素,遍历、查找元素d位置,在不修改表结构的操作一种直接访问,另一种基于整型变量O(1),按照下表循环检查处理O(n);变动操作:insert、append、deltete。

顺序表优点:O(1)时间访问元素,存储紧凑;缺点:表很大时需要申请大的连续存储空间,存储区大小不随插入删除操作变化,过大浪费空间,过小需开辟新的存储空间,灵活性较低,插入与删除操作需要移动许多元素O(n)时间效率较低。两种实现方式如下:

        一体式结构,存储信息与元素存储区以连续方式放在存储空间中,从而形成完整表对象,这种方式优点:整体紧凑,易于管理,由于连续存放,从表对象L出发访问元素ei的内存地址为:Loc(ei)=Loc(L)+C+i*size(e),其中C为辅助存储空间大小;缺点:不同表对象大小不同一,表创建后存储区大小固定,不灵活。

        分离式结构,表中仅仅保存与表有关信息,实际元素存放在独立元素存储区对象中,通过链接与表对象关联,优点是表对象大小统一,不同表关联存储区大小可以不同;缺点是不易管理。

两结构的对比:1、分离式结构元素访问时需要首先定位元素存储区,然后利用线性表元素L(ei)计算公式得到元素存储位置,代价较一体式结构较高,但是仍未O(1)时间复杂度。2、分离式结构带来的最大优点是在表标识不变情况下为表替换存储区,一体式结构中加入操作在表满时操作便会失败,分离式结构在表满时可以替换更大的存储区并链接到相应存储区,此时加入新元素步骤如下:①申请更大存储区②复制元素到存储区③更改链接对象④加入新对象。分离式结构在程序运行环境还有足够空闲区间条件下不会因为表满而无法操作,也将这种技术实现的顺序表称为动态顺序表

考虑动态顺序表后端插入与扩容操作,假设随着操作进行,动态顺序表大小从0扩容到n,插入采用前端插入或者定点插入方式,每次插入操作时间开销与表长度有关,总的时间复杂度为O(n**2)。后端插入每次复杂度O(1),当表填满替换存储区时,设计存储单元量替换频度问题,考虑每次替换10个元素,表长度从0增长到1000,每加入10个元素替换一次存储区,总的复制次数:10+20+30+...+990=49500,对于一般n而言,可以算出总的复制次数约为n**2/20,意味着虽然每次尾端插入复杂度为O(1),但是由于开辟新空间元素复制问题,一次插入操作平均代价达到了(n),考虑底数为2指数频度增长,从0增长到1024时存储区大小赋值次数:1+2+4+...+512=1024,进行9次赋值,对于一般n而言,元素复制次数为O(n),平均复杂度为O(1)。后一种频度替换策略时间上优势明显,但是会出现空元素较多的情况,比如前一种最大空闲单元数为9,后一种可以达到n/2个空闲单元,可以看到不同频度替换策略带来了不同时间复杂度,也同样付出了不同的空间代价。另一个问题是:动态顺序表后端插入代价不统一,多数后端插入在O(1)时间内完成,但会由于替换存储区出现高代价操作,这种高代价操作会随着表的增大变得越来越稀疏,这种高代价在时间要求高的应用中应该特别注意。为缓解这一问题可以增加给定容量时表预替换操作,使得在关键计算片段不会出现存储区替换,令时间得到保证。

        Python中的list 是采用分离式计数实现的动态顺序表,官方系统中,list实现采用如下策略:建立空表时,系统分配容纳8个元素的存储区,执行insert或者append时如果表满替换一块4倍大的存储区,若表大于5000时改变替换策略从而避免出现过多空闲存储位置,这种技术使得尾端插入平均时间复杂度O(1)。list中有几个特殊操作:1、clear操作,清除表元素时有两种做法,第一种将表元素计数值设为0,实现简单效率高,但是不能释放元素存储区,第二种丢弃原存储区,分配新存储区,但是需要一次次替换存储区. 2、reverse操作,收尾元素替换

顺序表总结:顺序表技术是组织一组元素的重要方式,采用顺序表实现线性表可以O(1)时间定位访问元素,主要问题是插入/删除操作时的效率问题,然而特殊的尾端插入通过采用适当存储区扩容策略,具有O(1)平均时间复杂度。顺序表优点与缺点都在于元素存储方式的集中连续性,缺点上看这种方式不够灵活,不容易调整和变化,如果操作需要经常修改表结构,顺序表代价就会比较高。另一方面,顺序表需要巨大块连续存储空间,可能会造成存储管理方面的问题。

3、链接表(离散存储空间)

线性表基本需求是从首元素出发,能够找到表中任一元素,上面顺序表将表元素存储在连续空间中,自然满足两个需求,其中元素顺序关联是隐含的。另一种方式是基于链接结构,用链接关系表示元素之间顺序关系,对象之间链接看作一种顺序关联,基于链接技术实现的线性表称为链接表,实现链接表思想如下:1、表中元素分别存储在独立节点中2、保证表结构中任一节点可以找到下一节点3、前一节点用链接方式显式记录后一节点关联。

        单链表,掌握表首节点引用(表头变量,表头指针),通过判断链接域值是否为空连接,可以找到所有节点。基本链表操作有:创建表、插入\删除节点、表空判断、遍历操作等,插入与删除一般分为散步:1、创建节点并存入数据2、修改插入(删除)节点前后链接,遍历分为扫描与定位(按下标与按元素定位)可以查找表中一些节点。

        循环单链表,需要数据域_rear,逻辑上始终引用表尾节点,前端加入节点就是在尾端域首端节点之间加入新的首节点,为节点引用不变。

        双链表,单链表只能做一个方向的扫描和逐步操作,增加了尾节点引用也只支持O(1)时间首端/尾端元素加入/删除,如果希望操作两端插入与删除操作都能高效完成,修改单链表变为双链表,不仅支持两端高校操作,一般节点操作也会更加方便,当然需要增加链接域,增加了额外空间开销与节点数成正比为O(n),为了支持收尾两端高效操作,双链表应该采用如图所示结构,从任一节点出发,可以直接找到前后相邻节点,而对于单链表而言只能方便找到下一节点。

        循环双链表,双链表可以定义为循环链表,让尾部与首部节点互相指向。

链表反转:考虑Python的list中reverse函数操作,对于链表翻转第一种可以在节点之间搬动元素,第二种可以修改节点的链接关系,从而改变元素顺序,而搬动元素反转很不方便,效率很低。考虑基于修改链接方法,对于单链表首段的插入/删除元素节点时最方便的,只需要O(1)时间,如果不断向一个表首段插入节点,最早放进去的节点将在表尾,表尾节点将在表首,总的时间开销为O(n),这就是一个搞笑的反转算法。

链表排序:考虑Python的list中sort函数操作,对于一个顺序表进行排序,考虑已经排序好的部分,如图所示,未排序部分越来越小,因此可以让两部分公用原来的表,在表前部积累排序片段,从而不需要额外存储开销。

对于链表的排序,存在着①移动表元素②调整节点链接关系两种方法,在基于移动元素的单链表排序算法中,采用插入排序,每次拿一个未排序元素在已排序序列中找到正确位置后插入元素,将其他元素后移。基于调整链接插入排序,在未排序元素中取下链表节点,插入排序链表的正确位置。

链表总结:

1、基本单链表通过一个方向构造起来,支持高效O(1)前端插入删除,定位或尾部操作需要O(n)

2、增加尾部节点引用域单链表可以很好支持首端/尾端插入弹出元素,但不能支持高效尾端删除

3、双链表每个节点两个方向链接,因此可以高效找到前后节点,如果有尾节点引用,两端插入域删除操作都能在O(1)时间内完成

链表优点如下:

1、表结构通过链接形成,节点之间顺序由链接关系决定,链接可以修改,表结构容易调整和修改

2、不需要修改节点里数据元素或移动它们,只需要修改节点之间链接,就能灵活修改数据排列方式

3、整个表由小的存储块构成,容易安排与管理

链表缺点如下:

1、定位访问需要线性时间,这是与顺序表相比最大的略势

2、找当前元素前一元素必须从头开始扫描,双链表可以解决此问题,但是付出更多空间代价

3、为存储一个表元素,需要用一个或者多个链接域,存储代价较高。

4、表的应用

Josephus问题:假设n个人围成一圈,现球第k个人开始报数,直到m个人退出,然后从下一个人继续报数直到所有人退出,按顺序输出各个出列人编号。

解法1:基于Python的list和固定大小数组概念,将list看作元素个数固定的对象,只修改元素的值,不改变表结构。初始建立n个人的表,找到第k个人并开始算法,将表中元素修改为0的方式表示出列,直到n个人全部出列算法结束。m=1时,每次内循环时间开销O(n),m=n时,遍历一遍只能把count值加1,整个计算中时间复杂度为:

解法2:基于顺序表的解,用list按表方式处理,一旦确定退出,将编号从表中删除。如图,函数执行n次每次需要调用list的pop操作,算法时间复杂度O(n**2)。

解法3:基于循环单链表的解,①建立指定个数节点的循环单链表,②循环计数,找到退出节点。如图,定义了turn方法,将表对象rear指针沿着next方向移动m步。算法时间复杂度:建立初始表为O(n),循环部分复杂度为O(m*n)。

5、总结

顺序表存储在一块大的存储区域中,逻辑顺序关系通过实际存储位置直接反应,表中只需放数据元素本身信息,空间利用率高,元素存储位置可以基于下表通过简单算式计算出,在O(1)时间内随机存取。另一方面,采用连续方式存储元素,顺序表技术灵活性不高,为了有效支持元素插入和删除,顺序表需要预留一些空间,此外,顺序表中插入域删除元素可能需要移动许多元素,代价通常较高。由于采用连续方式存储元素,需要安排确定大小存储空间,如果填满则无法继续插入元素,动态顺序表解决了这个问题,出现了新的问题:原本高效的后端插入操作,可能由于扩存而比较耗时。偶发的情况可能影响程序的行为,另一种扩存策略时在平均操作效率和闲置存储量之间权衡。

链接表中表元素保存在一批较小的存储块中,显式链接这些块反应元素顺序关系,表元素之间顺序由节点之间链接关系显式表示,节点可以任意安排位置,通过链接完成表元素的插入、删除和各种顺序的操作,这都说明链接表实现的灵活性较强,操作的实现方式更加灵活多样。然而为了实现链接表,每个节点需要增加额外链接域,付出了额外存储空间代价,但是表中不需要预留空闲位置,而对于一个链表,能直接掌握的只有其中一两个节点,访问代价较高,由于这种情况,使用链表最合理方式时前端操作和按元素顺序访问,增加尾节点后支持受限后端操作,包括表元素访问和新元素插入,不包括删除,引入双链接后增加了另一访问顺序,节点间操作也更方便,但并没有改变链表的本质。

顺序表与链表并不是决然相对的技术,可以在链表一个节点中存放多个顺序表元素,形成一种混合形式。顺序表另一个优点时访问的局部性,表元素顺序映射到内存中连续单元里,元素之间存储位置接近,而由于计算机结构体系特点,顺序访问内存相邻位置效率比较高,对于链表而言,逻辑上下一个节点可能倍安排在内存中任何位置,逻辑上顺序访问对内存中随机访问,效率较低。

数据结构与算法 Python语言描述 第三章 线性表相关推荐

  1. 数据结构python课后答案_数据结构与算法:Python语言描述 1~5章课后习题

    数据结构与算法:Python语言描述 1~5章课后习题 发布时间:2018-07-19 20:42, 浏览次数:1885 , 标签: Python MarkDown语法写的,不知道为啥上传到CSDN不 ...

  2. 《数据结构与算法 Python语言描述》 读书笔记

    已经发布博客 <数据结构与算法 Python语言描述> 读书笔记 第二章 抽象数据类型和Python类 2.1 抽象数据类型abstract data type:ADT 2.1.1 使用编 ...

  3. 数据结构与算法python描述_数据结构与算法——Python语言描述.pdf

    数据结构与算法--Python语言描述.pdf 欢迎加入非盈利Python编学习交流程QQ群783462347,群里免费提供500+本Python书籍! 欢迎加入非盈利Python编程学习交流程QQ群 ...

  4. 数据结构与算法python语言实现-第四章答案

    数据结构与算法python语言实现-第四章答案 4.1 def findmax(S, index=0):if index == len(S) - 1:return S[index]max=findma ...

  5. python数据结构题目_《数据结构与算法Python语言描述》习题第二章第三题(python版)...

    ADT Rational: #定义有理数的抽象数据类型 Rational(self, int num, int den) #构造有理数num/den +(self, Rational r2) #求出本 ...

  6. 数据结构与算法 Python语言描述 笔记

    数据结构 线性表包括顺序表和链表,python的list是顺序表,链表一般在动态语言中不会使用.不过链表还是会出现在各种算法题中. 链表 link list 单链表 逆转链表: leetcode 20 ...

  7. 数据结构python语言描述课后答案_《数据结构与算法Python语言描述》习题第二章第三题(python版)...

    1 #!/usr/bib/env python 2 #-*- coding:utf-8 -*- 3 4 """ 5 ADT Rational: #定义有理数的抽象数据类型 ...

  8. 《数据结构与算法Python语言描述》习题第二章第二题(python版)

    ADT Date: #定义日期对象的抽象数据类型 Date(self, int year, int month, int day) #构造表示year/month/day的对象 difference( ...

  9. 数据结构与算法python语言描述答案_《数据结构与算法Python语言描述》习题第二章第一题(python版)...

    1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 """ 5 定义一个表示时间的类Time6 a)Time(hour ...

最新文章

  1. .tar.gz mysql 安装_mysql tar.gz 版本 linux系统的安装-Go语言中文社区
  2. 深度解析 Lucene 轻量级全文索引实现原理
  3. 高并发编程-02-创建多线程的7种方式
  4. 自动装配有哪些局限性?
  5. SAP Analytics Cloud Model的delta upload(增量导入)功能
  6. JAVA的rotate怎么用,java如何利用rotate旋转图片_如何在Java中旋转图形
  7. 【数据库】SQL查询强化篇
  8. [MM9]复制格式的快捷操作
  9. linux ssh密钥登录配置
  10. Spring Boot之自定义属性
  11. JEPF 3.1.3 发布,我们的软件机床
  12. 5.数据中台 --- 数据汇聚联通:打破企业数据孤岛
  13. 高德地图在android上的开发汇总
  14. L298N模块驱动电机(实现pwm调速)
  15. JavaWeb公交调度系统的设计与实现
  16. CNC编程工程师如何炼成?要哪些必备技能?
  17. 实战 | 电感元件定位--Halcon与OpenCV实现详解(附源码)
  18. 计算机圆半径计算公式,圆半径计算公式是什么?
  19. 2022年一级建造师《工程经济》模拟卷有解析
  20. 量化投资学习——一份高频因子的研报综述

热门文章

  1. 图书管理系统+购物车JavaScript/Jquery + HTML
  2. 计算机动画是矢量动画吗,计算机动画画面的视觉特征
  3. 【Codeforces div3-498】题解
  4. TTS(1)单片机播放WAV语音,有原理,有代码
  5. 聊聊分布式任务调度系统
  6. 我读懂了这样一种自然之语
  7. 中国软磁材料行业发展现状与竞争格局分析报告2021年版
  8. VC 随鼠标移动的文字。
  9. 李宏毅机器学习第一周
  10. JavaScript通过js的方式来计算平行四边形的面积的代码