基本数据结构ADT及其实现

目录

  • 0.抽象数据类型ADT——Abstract Data Type
  • 1.表ADT及其实现
    1.1 表ADT
    1.2 表的实现
      1.2.1 数组实现
      1.2.2 链表
      1.2.3 双链表
      1.2.4 循环链表
    1.3 表的应用
      1.3.1 多项式
      1.3.2 基数排序
      1.3.3 多重表
  • 2.栈ADT及其实现
    2.1 栈ADT
    2.2 栈的实现
    2.3 栈的应用
      2.3.1 平衡符号
      2.3.2 后缀表达式
      2.3.3 中缀到后缀的转换
      2.3.4 函数调用
  • 3.队列ADT及其实现
    3.1 队列ADT
    3.2 队列的实现
    3.3 队列的应用
      3.3.1 排队论
      3.3.2 任务队列
      3.3.3 在图论中有大量的应用
      3.3.4 消息队列
      3.3.5 linux内核进程执行队列(按优先级轮转)
  • 4.哈希表ADT及其实现
  • 5.查找树ADT及其实现
  • 6.优先队列(堆)ADT及其实现
  • 7.不相交集ADT及其实现——并查集

0.抽象数据类型ADT——Abstract Data Type

ADT是一些操作的集合。抽象数据类型是数学的抽象,在ADT的定义中不涉及如何实现操作的结合。

对诸如表、集合、图和它们的操作一起可以看作是抽象数据类型,就像整数、实数是数据类型一样。对于集合ADT,可以有诸如并(union)、交(intersection)、获取大小(size)以及取余(complement)等操作。

1.表ADT及其实现

1.1 表ADT

1)表ADT的数据结构
形如A1, A2, ..., An的表。表的大小是n。大小为0的表为空表。
对除空表外的任何表,说Ai+1后继Ai并称Ai-1前驱Ai。表中第一个元素是A1,最后一个元素是An。不定义A1的前驱元和An的后继元。元素Ai在表中的位置为i。

2)表ADT上进行的操作的集合

  • PrintList
  • MakeEmpty
  • Find返回关键字首次出现的位置
  • FindKth返回某个位置上的元素
  • Insert/Delete从表的某个位置插入和删除某个关键字

1.2 表的实现

1.2.1 数组实现(连续存储)

表的大小实现需要已知(除非实现位动态数组)
插入和删除是昂贵的,最坏情况为O(N)

1.2.2 链表

链表允许不连续存储。
链表有一系列不在内存中相连的结构组成。每一个结构均含有表元素和指向包含该元素后继元的结构的指针(Next指针)。


实现时,采用带有表头的链表:


1)链表的声明和一些简单的判断



2)查找

3)删除



4)插入


5)删除整个链表

1.2.3 双链表

1.2.4 循环链表

1.3 表的应用

1.3.1 多项式

使用数组(适合稠密)和链表(适合稀疏)实现。


数组实现

链表实现

1.3.2 基数排序

1.3.3 多重表

2.栈ADT及其实现

2.1 栈ADT——LIFO(后进先出)表

栈是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈的顶。

2.2 栈的实现

任何实现表的方法都能实现栈。

2.2.1 栈的链表实现

通过在表顶端插入来实现push,通过删除表顶端元素实现pop。







2.2.2 栈的数组实现








2.3 栈的应用

2.3.1 平衡符号

针对括号类的检查:

  • 做一个空栈。读入字符直到文件尾
  • 如果字符是一个开发符号,则将其推入栈中
    如果字符是一个封闭符号,则当空栈时报错;否则,将栈元素弹出。
    如果弹出的符号不是对应的开放符号,则报错。
  • 在文件尾,如果栈非空则报错。

2.3.2 后缀表达式

后缀表达式: a b c * + d e * f + g * +

  • 当见到一个数是就把它推入栈中
  • 遇到一个运算符时,从栈中弹出两个数,并运用该运算符计算,并将所得结果推入栈中

2.3.3 中缀到后缀的转换(栈的操作本质上是从左到右,将优先级高的先弹出,或者说是按照计算的次序进行弹出的)

将中缀表达式 a + b * c + (d * e + f) * g
转成后缀表达式 a b c * + d e * f + g * +

  • 当读到一个操作数的时候,立即把它放到输出中
  • 操作符不立即输出,将其放到栈中。当遇到做括号时,也将其推入栈中
  • 见到一个右括号,将栈元素弹出,将弹出的符号写出,直到遇到一个对应的左括号。左括号弹出,不输出。
  • (如果栈顶符号的优先级高于当前符号,要弹出)如果见到任何其他的符号: + * (,从栈中弹出栈元素直到发现优先级更低的元素位置。例外:除非在处理),否则不从栈中移走(。当从栈弹出元素的工作完成后,在将操作符压入栈中。
  • 读到输入的末尾,将栈元素弹出知道该栈变成空栈,将符号写到输出中。

a + b * c + (d * e + f) * g:










2.3.4 函数调用

函数调用是,需要存储当前所有重要信息(活动记录、栈帧),诸如寄存器的值和返回地址。
将这些信息放到栈中,然后控制转移到新函数,新函数可以自由地用它的一些值代替这些寄存器。

栈溢出:许多系统中是不检测溢出的。由于有太多同时在运行着的函数,用尽栈空间情况总是可能发生的。
当栈太大是,可能触及到你的程序部分。

  • 如果撞进了你的程序部分,产生一些无意义的指令并在这些指令执行时程序崩溃
  • 如果撞进了你的数据部分,你将一些信息写入数据时,将毁坏栈的信息,很可能是返回地址,则你的程序将返回到某个奇怪的地址,从而程序崩溃。

发生栈溢出一般是由失控递归(忘记基准情形)引起的。
消除递归一般方法是使用一个栈,而且仅当你能够把最低限度的最小值放到栈上时,这个方法才值得一用。

3.队列ADT及其实现

3.1 队列ADT——FIFO表

队列也是表,插入在一端(队尾rear),删除在另一端(对头front)。


3.2 队列的实现

同栈一样,任何表的实现都是合法的。

3.2.1 队列的链表实现

3.2.2 队列的数组实现





3.3 队列的应用

3.3.1 排队论

  • 当所有的接线员忙得不可开交的时候,对大公司的传呼一般都被放到一个队列中
  • 在大规模的大学里,如果所有的终端都被占用,由于资源有限,学生们必须在一个等代表上签字。在终端上待得时间最长的学生将首先被强制离开,而等待时间最长的学习则将是下一个被允许使用终端的用户。

处理用概率的方法计算用户排队预计等待时间、等待服务的队列能够排多长,以及其他一些诸如此列的问题将用到被称为排队类的整个数学分支。
问题的答案依赖于用户加入队列的频率以及一旦用户得到服务时处理服务花费的时间。这两个参数作为概率分布函数给出。
如果有k个接线员,直接解决比较困难,可以用模拟的方法(使用一个队列)进行进行求解。

模拟方法:(当k变大时需要模拟)

  • 模拟由处理中的事件组成。这里的两个事件:
    1)一位顾客的到达
    2)一位顾客的离开,从而腾出一名出纳员
  • 使用过概率函数来生成一个输入流,由每位顾客的到达时间和服务时间的序偶组成,并通过到达时间排序。不必使用一天中的准确时间,而是使用单位时间量,称之为一个滴答(tick)
  • 使用队列进行模拟

3.3.2 任务队列

将任务按照顺序放到一个队列中,用一个线程池(多个处理线程)轮流冲任务队列中取出任务进行处理。

3.3.3 在图论中有大量的应用

3.3.4 消息队列

3.3.5 linux内核进程执行队列(按优先级轮转)

4.哈希表ADT及其实现

4.1 哈希表ADT

散列(hashing)是一种用于以常数平均时间执行插入、删除、查找的技术。
那些需要元素间任何排序信息的操作将不会得到有效支持。因此诸如FindMin、FindMax等操作都是哈希表不支持的。

4.2 哈希表的实现

实现参见:http://www.jianshu.com/p/6dfd8c4c2b50

5.查找树ADT及其实现

参见http://www.jianshu.com/p/bdd7442f54e2

5.1 查找树ADT

5.2 查找树的实现

5.2.1 二叉查找树

5.2.2 AVL树

5.2.3 伸展树

5.2.4 B-树

5.2.5 红黑树

参考红黑树专题
参考2-3-4树及2-3树的总结

6.优先队列(堆)ADT及其实现

6.1 优先队列ADT

优先队列是允许至少下列两种操作的数据结构:
1)Insert
2)DeleteMin 找出、返回和删除优先队列中最小的元素


6.2 优先队列的实现

参见http://www.jianshu.com/p/f62787325788

6.2.1 二叉堆

6.2.2 d-堆

6.2.3 左式堆

6.2.4 斜堆

6.2.5 二项队列

6.2.6 斐波那契堆

6.2.7 van Emde Boas树

7.不相交集ADT及其实现——并查集

7.1 不相交集ADT

一些应用涉及将n个元素分成一组不相交的集合。这些应用经常需要进行两种特别的操作:寻找包含给定元素的唯一集合和合并两个集合。

支持以下三个操作:

  • MAKE-SET(x):建立一个新的集合,它的唯一成员是x。因为各个集合是不相交的,故x不会出现在别的某个集合中。
  • UNION(x, y):将包含x和y的两个动态集合(Sx和Sy)合并成一个新的集合。
  • FIND-SET(x):返回一个指针,这个指针指向包含x的(唯一)结合的代表。

7.2 不相交集的实现

7.2.1 用链表表示集合

1)表示方法
每个集合用一个链表来表示。

  • head指向表的第一个对象,也是集合的代表
  • tail属性指向最后一个对象
  • 集合每个对象包括:集合成员、指向下一个对象的指针、指向集合对象的指针
b为UNION(g, e)的结果

2)操作

  • MAKE-SET——O(1)时间
  • FIND-SET——O(1)时间
    x对象的指向集合对象的指针,然后通过集合对象返回head指向对象的成员。
  • UNION——链表合并,但是必须更新一个链表(集合)中素有对象指向集合对象的指针。最坏情况下的UNION平均摊还时间为Θ(n)。


UNION的一种方法:总是将较短的表拼接到较长的链表中。


7.2.2 用有根树表示集合——不相交集合森林

1)基础表示法
使用有根树来表示集合,树中每个结点包含一个成员,每棵树代表一个集合。
在一个不相交集合森林(disjoint-set forest)中,每个成员仅指向它的父节点。

  • MAKE-SET
  • FIND-SET:沿着指向父节点的指针找到书的根。
    这一通向根节点的简单路径上所访问的结点构成了查找路径。
  • UNION:使得一棵树的根指向另外一颗树的根
b为UNION(e, g)

2)按秩合并与路径压缩

  • 按秩合并
    对于每个结点,维护一个秩,它表示该节点高度(从该结点到某一后代叶节点的最长简单路径上边的数目)的一个上界。
    在使用按秩合并策略的UNION操作中,让具有较小的秩的根指向具有较大秩的根。

  • 路径压缩
    在FIND-SET操作中,使用这种策略可以使查找路径中的每个结点直接指向根。路径压缩并不改变任何结点的秩。


  • MAKE-SET


  • UNION(x, y)


  • FIND-SET(x)——递归的精妙作用(Amazing!)
    该递归是一种两趟方法:
    1)第一趟沿着查找路径向上直到找到根
    2)递归回溯时,第二趟沿着搜索向下更新每个结点,使其直接指向根。


3)运行时间分析

  • n——表示MAKE-SET操作的次数,这里假设n个MAKE-SET操作总是最先执行的n个操作。
  • m——表示MAKE-SET、UNION和FIND-SET操作的总次数(m >= n)
    当同时使用按秩合并和路径压缩时,最坏情况的运行时间为O(mα(n)),这里α(n)是一个增长非常慢的函数,在任何一个可以想得到的不相交集合数据结构的应用中,都有α(n) <= 4.
    详细分析参见摊还分析:3.2.8 不相交集合——并查集

7.3 不相交集合的应用

7.3.1 确定无向图的连通分量


7.3.2 同一个人的多个账号

  • 以前做的某个投票网站当中需要查封小号刷票的作弊账号,就在后台悄悄做了一个设置,如果某个人不小心带着相同的cookies登录了不同的账号(也就是在同一个浏览器上退出一个账号之后又登入了另一个账号),登录系统就会悄悄标记这两个账号属于同一个人,如果A和B是同一个人,B和C也是同一个人,那么A、B、C都是同一个人,我们最后只关心哪些账号是同一个人而哪些不是,并不关心究竟是通过怎样的步骤发现它们是同一个人的,这就是并查集最典型的应用。
  • 这个问题就可以在MySQL里面创建一个表,它有两个字段,第一个叫做ID,主键,第二个叫做Parent,当前等价的父节点,这就是一个MySQL数据表表示的并查集,然后随便用SELECT和UPDATE实现一下,并查集接近O(1)的复杂度,一般也就几次MySQL查询
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,071评论 0 12
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 文/@Monster猫吃带鱼 随着圣桑的《天鹅》响起,那个身着白裙的女人在我的视野里愈渐发亮。大提琴暧昧的声音让这...
    Monster猫吃带鱼阅读 387评论 0 1
  • ▌就如上面这张图给人的感觉一样,这部《蜘蛛侠》的气质与过去的所有英雄电影都不同,摒弃了「能力越大责任越大」的沉重,...
    戴某DEMO阅读 553评论 0 0