• [读书笔记]-大话数据结构-3-线性表(一)-线性表的顺序存储


    线性表:零个或者多个元素的有限序列。包括顺序表和链表单向链表、循环链表、双向链表、循环双向链表

    线性表的定义

        若将线性表记为(a1,...,ai-1,ai,ai+1,...,an),则表中 ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。当i=1,2,...,n-1时,ai有且仅有一个直接后继,当i=2,3,...,n时,ai有且仅有一个直接前驱。如下图

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

        在较复杂的线性表中,一个数据元素可以由若干个数据项组成。如下图

    线性表的抽象数据类型

    线性表的抽象数据类型定义如下:

    ADT  线性表(List)
    Data
        '''线性表的数据对象集合为{a1,a2,...,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。'''
    Operation
        InitList(*L):   '''初始化操作,建立一个空的线性表L。'''
        ListEmpty(L):  '''若线性表为空,返回true,否则返回false.'''
        ClearList(*L):  '''将线性表清空。'''
        GetElem(L,i):  '''将线性表L中的第i个位置元素值返回。'''
        LocateElem(L,e):  '''在线性表中查找与给定值e相等的元素,如果查找成功,返回该元素在表中的序号表示成功;否则返回0表示失败。'''
        ListInsert(*L,i,e):  '''在线性表L中的第i个位置插入新元素e。'''
        ListDelete(*L,i):  '''删除线性表L中第i个位置元素,并返回其值。'''
        ListLength(L):   '''返回线性表L的元素个数。'''
    endADT

         不同的线性表基本操作不同,上述操作是最基本的,实际中可能有更复杂的操作。例如实现两个线性表A和B的并集操作,使得A=AUB。

        假设La表示集合A,Lb表示集合B,并集的Python实现代码如下:

        def Union(self,lb):
            for i in range(1,lb.ListLength()+1):   #循环b列表
                e=lb.GetElem(i)                #取出第i个元素
                if self.LoacateElem(e)==0:     #如果该元素不在a中
                    self.ListInsert(self.length+1, e)   #将e插入a

        上面定义的union操作用到了前面定义的 ListLength、GetElem、LocateElem和ListInsert操作。

    线性表的顺序存储结构

        线性表的顺序存储结构,是指用一段地址连续的存储单元一次存储线性表的数据元素。 线性表(a1,a2,...,an)的顺序存储示意图如下:

    线性表顺序存储代码(Python代码)

    class SqList(object):
        def __init__(self,size=20):  #默认生成20个元素的线性表
            self.data=list(None for i in range(size))  #数据
            self.maxsize=size   #最大长度
            self.length=0       #当前长度

        可以看到描述线性表需要三个属性:

    • 存储空间的起始位置:数组data的存储位置
    • 线性表的最大存储容量:maxsize
    • 线性表的当前长度:length

        顺序存储的每个存储单元都有自己的编号,这个编号称为地址。Python中存储单元的编号从0开始,依次类推。从时间复杂度的角度来说,它的存取时间性能为O(1),如下图:

    获得元素(GetElem)的代码实现

        def GetElem(self,i):   #Python没有指针,所以用返回的形式把值赋给e
            if i>self.length or i < 1:
                raise IndexError('Index is out of range...')
            else:
                return self.data[i-1]  

    顺序存储结构的插入与删除

    插入

        线性表拆入元素时不能直接拆入,必须把插入位置后面每个元素依次后移,留出位置后再插入,插入操作思路:

    • 如果插入位置不合理,抛出异常
    • 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;
    • 从最后一个元素开始向前遍历到第I个位置,分别将它们都向后移动一个位置;
    • 将要插入的元素放到第i个位置处

    插入数据(ListInsert)的实现代码

        def ListInsert(self, i, e):
            if i>self.length or i < 0:  #下标不在范围
                raise IndexError('Index out of range...')
            elif self.length == self.maxsize:  #线性表已满
                self.data.append(e)   #此处可以动态增加线性表长度,也可以抛出异常
                self.maxsize+=1
                self.length+=1
            elif i <= self.length:
                for j in range(i-1,self.length)[::-1]: #第i到length个元素从后往前遍历  
                    self.data[j+1]=self.data[j]        #元素依次后移
                self.data[i-1]=e               #第i个元素等于e
                self.length+=1                 #长度+1

    删除

        与插入数据元素类似,删除数据元素的算法思路为:

    • 如果删除位置不合适,抛出异常
    • 取出删除元素;
    • 从删除元素位置开始遍历到最后一个元素位置,分别将它们向前移动一个位置
    • 长减1

    删除元素(ListDelete)的Python代码实现如下:

        def ListDelete(self,i):
            if i>self.length or i <1:
                raise IndexError('Index out of range...')
            else:
                e=self.data[i-1]
                for j in range(i-1,self.length-1):  #从第i个元素到倒数第二个,
                    self.data[j]=self[j+1]          #一次等于后一个元素
                self.data[self.length-1] = None     #最后一个元素等于空
                self.length-=1                      #长度-1
                return e

        以上插入和删除的时间复杂度都是O(n)。

     线性表顺序存储的优点

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

    缺点

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

    线性表顺序存储的操作合集

    class SqList(object):
        def __init__(self,size=20):  #默认生成20个对象的线性表
            self.data=list(i for i in range(size))  #数据
            self.maxsize=size   #最大长度
            self.length=0       #当前长度
            
        def ListEmpty(self):
            return self.length==0
        
        def ClearList(self):
            for i in range(self.length):self.data[i]=None
            self.length=0
            
        def GetElem(self,i):   #Python没有指针,所以用返回的形式把值赋给e
            if i>self.length or i < 1:
                raise IndexError('Index is out of range...')
            else:
                return self.data[i-1]  
            
        def LoacateElem(self,e):
            for i,item in enumerate(self.data[:self.length]):
                if item==e:return i+1
            return 0
        
        def ListInsert(self, i, e):
            if i>self.length + 1 or i < 1:  #下标不在范围,可以插入最后
                raise IndexError('Index is out of range...')
            elif self.length == self.maxsize:  #线性表已满
                self.data.append(e)   #此处可以动态增加线性表长度,也可以抛出异常
                self.maxsize+=1
                self.length+=1
            elif i <= self.length+1:
                for j in range(i-1,self.length)[::-1]: #第i到length个元素从后往前  
                    self.data[j+1]=self.data[j]        #下标依次后移
                self.data[i-1]=e               #第i个元素等于e
                self.length+=1                 #长度+1
                
        def ListDelete(self,i):
            if i>self.length or i<1 :
                raise IndexError('Index is out of range...')
            else:
                e=self.data[i-1]
                for j in range(i-1,self.length-1):  #从第i个元素到倒数第二个,
                    self.data[j]=self.data[j+1]          #一次等于后一个元素
                self.data[self.length-1] = None     #最后一个元素等于空
                self.length-=1                      #长度-1
                return e
        
        def ListLength(self):
            return self.length
        
        def ListShow(self):
            print self.data[:self.length]
            
        def ListCreate(self,l):
            for i,e in enumerate(l):
                self.ListInsert(self.length+1, e)
                
        def Union(self,lb):
            for i in range(1,lb.ListLength()+1):   #循环b列表
                e=lb.GetElem(i)                #取出第i个元素
                if self.LoacateElem(e)==0:     #如果该元素不在a中
                    self.ListInsert(self.length+1, e)   #将e插入a
                
    if __name__=='__main__':
        la=SqList()
        lb=SqList()
        print la.ListEmpty()
        la.ListCreate(range(0,20,2))
        la.ListShow()
        lb.ListCreate(range(1,20,3))
        lb.ListShow()
        print la.ListEmpty()
        print la.GetElem(4)
        print la.LoacateElem(1)
        la.ListInsert(5,15)
        la.ListShow()
        print la.ListLength()
        la.ListDelete(4)
        la.ListShow()
        la.Union(lb)
        la.ListShow()
        la.ClearList()
        la.ListShow()
    View Code
  • 相关阅读:
    剑指 Offer 05. 替换空格
    28. 实现 strStr()
    67. 二进制求和
    排序算法之二快速排序
    排序算法之一冒泡排序
    将本地文件上传到GitHub
    spring data jpa 操作pipelinedb 的continuous view 与stream
    pipelinedb学习笔记
    PostgreSQL 、springboot 、spring data jpa 集成
    pipelineDB学习笔记-2. Stream (流)
  • 原文地址:https://www.cnblogs.com/zhaoxy/p/7723283.html
Copyright © 2020-2023  润新知