数据结构随笔之线性表(一)

  最近在看一本《大话数据结构》的书,感觉挺有意思,所以就把看到的内容整理一下,权当是做个笔记,方便以后回顾。

  今天就先聊一下数据结构中的线性表。

  首先,什么是线性表?

  举个例子,我们会经常看到有的幼儿园放学小朋友会排着队出来,而且每个小朋友排队的位置每次都是固定的。为什么要这样呢?为了安全!每个小朋友的位置都是固定的,这样养成习惯以后,老师就可以很快的知道每个小朋友前面是谁,后面是谁,如果谁不在,他前面和后面的小朋友就会知道报告给老师。即使出去公园等地方的时候,老师也可以很快的点清人数,玩意有人走丢,老师也能最快知道,方便即使寻找。这种排队组织方式,就是线性表。零个或者多个数据元素的有限序列

  按我们熟悉的语言来标记:

  a1----a2----a2……ai-1----ai----ai+1……an

  上图里面,我们将 ai-1 称为 a的直接前驱元素,ai+1 称为 a的直接前驱元素,当表不为空的时候,ai 有且仅有一个直接前驱和后继。

  线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,称为空表

  线性表说完了,我们说一下线性表两种物理结构:顺序存储结构 和 链式存储结构

  

  顺序存储结构

  线性表的顺序存储结构,指的是用一段地址连续的存储单元一次存储线性表的数据元素

  顺序存储就想我们上面讲的存储结构,也像我们常用过的数组。

  但是这里我们需要区分两个东西:数组的长度线性表的长度

  数组的长度:指存放线性表的存储空间的长度,存储分配以后这个量一般是不变的。(当前不考虑高级语言中的动态分配数组)

  线性表的长度:指线性表中的数据元素的个数,这个长度可以根据线性表的插入删除而变化。

  注意:在任意时刻,线性表的长度应该小于等于数组的长度!

  

 

  在存储器中每个存储单元都有自己的编号,这个编号称为地址。就像电影院中的座位一样,都有自己的编号。我们只要占住其中一个位置以后,这个位置的后面位置都是可以计算的。例如 我们成绩在班里是第二名,我后面的5个同学的成绩名次是多少呢,当时是3,4,5,6,7,以为 2+1, 2+2, 2+3, 2+4, 2+5。由于每个数据元素,不管它是整型还是字符型,它都是需要占用一定的存储单元空间的。假设占用的是c个存储单元,那么线性表中的第i+1个元素的存储位置和第i个元素的存储位置满足这个关系(LOC表示获得存储位置的函数):

  LOC(ai+1)=LOC(ai)+ c

  所以对于第i个数据元素的 ai 的存储位置可以有 a1 推算得出:

  LOC(ai)=LOC(a1)+ (i-1)* c

  通过这个公式,可以随时推算出线性表中的任意位置的地址,不管它是第一个,还是最后一个,都是相同的时间。所以我们对线性表位置的存入(不是插入)或者读取,对于计算机来说都是相等的时间。那么时间复杂度就是O(1) 。

  而对于顺序存储结构的插入和删除操作,我们再举个例子,比如排队买票的时候,来个一个美女,对个队伍中排在第三位 的你说,“大哥,求求你帮帮忙,火车马上开了,队伍这么长,能不能让我排在你的前面?” 你心一软,答应了,这时,你就要后退一步,否则她没有办法进入队伍。那这可了不得了,后面的人就都得后退一步。骂声四起,但后面的人也不清楚这加塞是怎么回事,没什么办法。

  

  插入算法的思路:

  1.如果插入位置不合理,跑出异常

  2.如果线性表长度大于等于数组长度,则抛出异常或动态增加容量

  3.从最后一个元素开始向前遍历到第 i 个位置,分别将它们都想后移动一个位置

  4.将要插入的元素填入位置 i 处

  5.表长加 1

  

  接着刚才的例子,此时后面排队的人群意见都很大,都说怎么可以这样,不管什么原因,插队就是不行。就在这时,远处跑来一人,对着美女喊,可找到你了,你这骗子,还我钱。只见这女子二话不说,突然就冲出了队伍,消失在人群中。于是排队的人群,又像蠕虫一样,均向前移动了一步,队伍又恢复了平静。这就是线性表的顺序存储结构删除的过程。

  

  

  删除算法的思路:

  1.如果删除的位置不合理,抛出异常

  2.去除删除元素

  3.从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置

  4.表长减 1

  我们来看下,插入和删除的时间复杂度。

  最好的情况,元素如果插入最后一个位置,或者删除最后一个元素,此时时间复杂度为O(1) ,因为不需要移动元素。最坏的情况,元素要插入到第一个位置或者删除第一个元素,此时意味着所有的元素都要向后或者向前移动,时间复杂度为O(n)。平均情况下,元素插入到第 i 个位置,或者删除第 i 个元素,需要移动 n - 1 个元素。每个位置插入或者删除的可能性都是相同的,位置靠前,移动元素多,位置靠后,移动元素少。平均时间复杂度还是O(n)。

  

  综上:线性表的顺序存储结构的优缺点:

  优点:无须为表示表中元素之间的逻辑关系而增加额外的存储空间;可以快速的存取表中任一位置的元素

  缺点:插入和删除操作需要移动大量的元素;当线性表长度变化较大时,难以确定存储空间的容量;造成存储空间的“碎片”

 

   链式存储结构

  线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。以前在顺序存储结构中,每个数据元素只需要存储数据元素就可以了,现在在链式存储结构中,除了要存储数据元素信息外,还要存储它的后继元素的存储位置(指针)。

 

   单链表的读取

   在顺序存储结构中,我们要计算任意一个元素的存储位置是很容易的,但在单链表中,由于第 i 个元素到底在哪儿,没办法一开始就知道,必须从头找,直到第 i 个元素位置。这个算法的时间复杂度取决于 i 的位置,当i=1 时,则不需要遍历,第一个就取出来了,而当 i=n 时则遍历 n-1 次才可以。因此最坏情况的时间复杂度为O(n)。

  单链表的插入和删除

  如果我们要对单链表进行插入和删除操作,其实是由两部分组成:第一部分就是遍历查找要插入的位置 i ;第二部分就是插入和删除元素;

  插入:

    s->next = p->next p->next = s,两个步骤,先将 a元素的指针赋值给 e 元素,这样两个节点都指向了ai+1 元素,然后再把 e 元素赋值给ai 元素,这样a元素就能指向 e 元素,不再指向 ai+1 元素了,如果两句话位置写反的话,先把a元素的指针赋值给 e 元素的话,a元素与后面的ai+1 元素的关联就断掉了,这样就导致找不到后面的元素了。

  

  删除:

    p->next = ai+1 删除比较简单,只需要把需要的删除节点的前一个节点指针指向要删除的节点的后一个节点即可。

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

  

  我们可以根据这些对单链表结构和顺序存储结构做个简单对比:

  1.存储分配方式:

    A.顺序存储结构用一段连续的存储单元依次存储线性表的数据元素

    B.单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素

  2.时间性能

    查找:

      顺序存储结构:O(1)

      单链表:O(n)

    插入和删除:

      顺序存储结构需要平均移动表长一半的元素,时间为O(n)

      单链表在先找出某位置的指针后,插入和删除时间为(1)

  3.空间性能

    顺序存储结构需要预分配存储空间,分大了。浪费,分小了易发生上溢

    单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制

  

猜你喜欢

转载自www.cnblogs.com/lv-suma/p/12672056.html
今日推荐