4 线性表(二)

线性表2.

3.7 单链表的读取

在线性表的顺序存储结构中,我们要计算任意一个元素的存储位置是很容易的。但在单链表中,由于第i个元素到底在哪?没办法一开始就知道,必须得从头开始找。

获得链表第i个数据的算法思路:

  • 声明一个结点p指向链表第一个结点,初始化j从1开始;
  • 当j < i 时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
  • 若到链表末尾p为空,则说明第i个元素不存在;
  • 否则查找成功,返回结点p的数据。

说白了,就是从头开始找,直到第i个元素为止,由于这个算法的时间复杂度取决于i的位置,当i=1时,则不需要遍历,第一个就取出数据了,而当i=n时则遍历n-1次才行。因此最坏情况的时间复杂度是O(n)。

由于单链表的结构中没有定义表长,所以不能事先知道要循环多少次,因此也就不方便使用for来控制循环。其主要核心思想就是“工作指针后移”,这其实也是很多算法的常用技术。

3.8 单链表的插入和删除

3.8.1 单链表的插入

s->next = p->next,p->next = s;

解读这两句代码,也就是说让p的后继结点改成s的后继结点,再把结点s变成p的后继结点。

**单链表第i个数据插入结点的算法思路: **

  • 声明一结点p指向链表的第一个结点,初始化j从1开始。
  • 当j < i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1。
  • 若到链表末尾p为空,则说明第i个元素不存在
  • 否则查找成功,在系统中生成一个空结点s
  • 将数据元素e赋值给s->data
  • 单链表的插入标准语句s->next = p->next,p->next = s;
  • 返回成功

在这段算法代码中,我们用到了C语言的malloc标准函数,它的作用就是生成一个新的结点,其类型与Node是一样的,其实质就是在内存中找了一小块空地,准备用来存放e数据s结点。

3.8.2 单链表的删除

设存储元素ai的结点为q,要实现将结点q删除单链表的操作,其实就是将它的前继结点的指针绕过,指向它的后继结点即可。

q = p->next; p->next = q->next

单链表第i个数据删除结点的算法思路:

  • 声明一结点p指向链表第一个结点,初始化j从1开始
  • 当j<1时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1
  • 若到链表末尾p为空,则说明第i个元素不存在
  • 否则查找成功,将欲删除的节点p->next赋值给q。
  • 单链表的标准删除语句p->next = q->next。
  • 将q结点中的数据赋值给e,作为返回。
  • 释放q结点。
  • 返回成功。

这段算法代码里,我们又用到了另一个C语言的标准函数free。它的作用就是让系统回收一个Node结点,释放内存。分析一下刚才我们讲解的单链表插入和删除算法,我们发现他们其实都是由两部分组成:第一部分就是遍历查找第i个元素,第二部分就是插入和删除元素

从整个算法来说,我们很容易推导出:他们的时间复杂度都是O(n)。如果在我们不知道第i个元素的指针位置,单链表数据结构在插入和删除操作上,与线性表的顺序存储结构是没有太大优势的。但如果,我们希望从第i个位置,插入10个元素对于顺序寻出结构意味着,每一次插入都意味着要移动n-i个元素,每次都是O(n)。而单链表,我们只需要在第一次时,找到第i个位置的指针,此时为O(n),接下来只是简单里通过赋值移动指针而已,时间复杂度都是O(1),显然,对于插入或删除数据越频繁的操作,单链表的效率优势就越是明显

3.9 单链表的整表创建

回顾一下,顺序存储结构的创建,其实就是一个数组的初始化,即声明一个类型和大小的数组并赋值的过程。而单链表和顺序存储结构不一样,它不像顺序存储结构那么集中,它可以很散,是一种动态结构。对于每个链表来说,它所占用空间的大小和位置是不需要预先分配划定的,可以根据系统的情况和实际的需求即时生成。

单链表整表创建的算法思路:

  • 声明一结点p和计数器变量i
  • 初始化一空链表L
  • 让L的头结点的指针指向NULL,即建立一个带头结点的单链表
  • 循环
* 生成一新结点赋值给p 
* 随机生成一数字赋值给p的数据域p->data
* 将p插入到头结点与前一新结点之间。

这段算法代码里,我们其实用的是插队的办法,就是始终让新结点在第一的位置。这种算法简称为头插法

我们把每次新结点都插在终端结点的后面,这种算法称为尾插法

注意L与r的关系,L是指整个单链表,而r是指向尾结点的变量,r会随着循环不断地变化结点,而L则是随着循环增长为一个多结点的链表。

对于r->next = p的理解

它的意思,就是本来r是在ai-1元素的结点,可现在它已经不是最后的节点了,现在最后的节点是ai,所以应该要让p结点这个最后的结点赋值给r。此时r又是最终的尾结点了。

循环结束后,那么应该让这个链表的指针域置空,因此有了“r->next = NULL”,以便以后遍历时可以确定其是尾部。

3.10 单链表的整表删除

也就是在内存中将它释放掉。

单链表整表删除的算法思路:

  • 声明一结点p和q
  • 将第一个结点赋值给p
  • 循环
* 将下一节点赋值给q
* 释放p
* 将q赋值给p

3.11 单链表结构与顺序存储结构优缺点

  • 若线性表需要频繁的查找,很少进行插入和删除操作时,宜采用顺序存储结构。若需要频繁插入和删除时,宜采用单链表结构。
  • 当线性表中的元素个数变化较大或则根本不知道有多大时,最好用单链表结构。这样可以不需要考虑存储空间的大小问题。而如果事先知道线性表的大致长度,这种用顺序存储结构效率会高很多。

3.12 静态链表

其实C语言真是好东西,它具有的指针能力,使得它可以非常容易地操作内存中的地址和数据,这比其他高级语言更加灵活方便。

首先我们让数组的元素都是由两个数据域组成,data和cur。也就是说,数组的每个下标都对应一个data和cur。数据域data,用来存放数据元素,也就是我们通常要处理的数据;而游标cur相当于单链表中的next指针,存放该元素的后继在数组中的下标。

我们把这种用数组描述的链表叫做静态链表,这种描述方法还有起名叫做游标实现法

另外我们对数组第一个和最后一个元素作为特殊元素处理,不存数据。我们通常把未被使用的数组元素称为备用链表。而数组第一个元素,即下表为0的元素的cur就存放备用链表的第一个结点的下标;而数组的最后一个元素的cur则存放第一个有数值的元素的下标,相当于单链表中的头结点作用,当整个链表为空时,则为O^2。

![](http://upload-images.jianshu.io/upload_images/3532835-6c5874b975475c10.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

此时,“甲”这里就存有下一元素“乙”的游标2,“乙”则存有下一元素“丁”的下标3。而“庚”是最后一个有值元素,所以它的cur设置为0,而最后一个元素的cur则因“甲”第一有值元素而存有它的下标为1。而第一个元素则因空闲空间的第一个元素下标为7,所以它的cur存有7。

3.12.1 静态链表的插入操作

静态链表中要解决的是:如何用静态模拟动态链表结构的存储空间的分配,需要时申请,无用时释放。

为了辨明数组中哪些分量未被使用,解决的办法是将所有未被使用过的及已被删除的分量用游标链成一个备用的链表,每当进行插入时,便可以从备用链表上取得第一个结点作为带插入的新节点。

这段代码有意思,一方面它的作用就是返回一个下标值,这个值就是数组头元素的cur存的第一个空闲的下标。从上面的图示例子来看,其实就是返回7。

那么既然下标为7的分量准备使用了,就得有接替者,所以就把分量7的cur值赋值给头元素,也就是把8给space[0].cur。之后就可以继续分配新的空闲分量,实现类似malloc()函数的作用。

  • 当我们执行插入语句时,我们的目的是要在“乙”和“丁”之间插入“丙”。调用代码时,输入i值为3。
  • 第4行让k=MAX_SIZE-1=999
  • 第7行,j=Malloc_SSL(L) = 7。此时下标为0的cur也因为7要被占用而更改备用链表的值为8。
  • 第11~12行,for循环1由1到2,执行两次。代码k= L[k].cur;使得k=999,得到k=L[999].cur = 1;在得到k=L[1].cur = 2。
  • 第13行,L[j].cur = L[k].cur;因j=7,而k=2得到L[7].cur = L[2].cur = 3.这就是刚才我所的让“丙”把它的cur改为3的意思。
  • 第14行,L[k].cur = j;意思就是L[2].cur= 7.也就是让“乙”得点好处,把它的cur改为指向“丙”的下标7.

3.12.2 静态链表的删除操作

这一节我没看懂释放怎么做的

3.12.2 静态链表的删除操作优缺点

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,719评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,337评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,887评论 0 324
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,488评论 1 266
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,313评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,284评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,672评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,346评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,644评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,700评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,457评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,316评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,706评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,261评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,648评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,859评论 2 335

推荐阅读更多精彩内容

  • 本文内容取自于小甲鱼的数据结构与算法。http://www.jianshu.com/p/230e6fde9c75 ...
    阿阿阿阿毛阅读 2,846评论 0 7
  • 1.线性表的定义 线性表:零个或多个数据元素的有限序列序列:也就是说元素之间是有顺序的,若元素存在多个,则第一个元...
    e40c669177be阅读 2,016评论 6 15
  • 大学的时候不好好学习,老师在讲台上讲课,自己在以为老师看不到的座位看小说,现在用到了老师讲的知识,只能自己看书查资...
    和珏猫阅读 1,429评论 1 3
  • 在上一篇文章中我们简单说了数据结构的概念和数据结构与算法的一些关系,这一篇文章的内容是关于线性表的东西,主要有线性...
    硅谷小虾米阅读 1,251评论 1 3
  • 1.一开场就是利落的杀人场景。虽然看惯了美剧,但看着钩子拖着人往冰窟窿里扔的时候还是觉得蛮吓人的。 2.看了半小时...
    Emma梧桐阅读 143评论 0 0