线性表:零个或者多个元素的有限序列。包括顺序表和链表(单向链表、循环链表、双向链表、循环双向链表)
线性表的定义
若将线性表记为(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()