本节主要介绍三种顺序表中删除所有指定元素的方法,详情请见下图。
代码部分如下:前边是顺序表类,服务之后函数的调用,在之后会展现具体的函数。
class SqList:#Sq 是squen的意思,表示顺序;这里建立了一个顺序表类
def __init__(self):
self.incapacity=5
self.capacity=self.incapacity
self.data=[None]*self.capacity#None表示不知道存储元素的类别,也起到占位的作用;这个语句设置了顺序表的空间
self.size=0
def resize(self,newcapacity):
assert newcapacity>=0
olddata=self.data#olddata这个变量用来存储源列表data的内容,相当于把罐子里的水挪出来才能操作原来装水的罐子
self.data=[None]*newcapacity
self.capacity=newcapacity
for i in range(self.size):
self.data[i]=olddata[i]#这样操作过后原列表data的空间会被释放
#时间复杂度O(n),n为olddata的长度
def CreateList(self,a):#其中a是一个列表类型,这个语句是整体将一个列表创建成一个顺序表存储
for i in range(0,len(a)):
if self.size==self.capacity:#以防顺序表容量不够
self.resize(2*self.size)
self.data[self.size]=a[i]#这样是为了顺序表前边压实,不会出现露的位置,每次循环self.size都+1,也是每个位置都随着i的变化逐个填充
self.size+=1
#本算法的时间复杂度为O(n),n表示顺序表中元素的个数
def Add(self,e):#将元素e添加到顺序表的末尾
if self.size==self.capacity:
self.resize(2*self.size)
self.data[self.size]=e
self.size+=1
#一般来讲if语句块大多情况下不会执行,执行的话也执行一次就够。resize()的时间复杂度为O(n),如果
#resize()方法不调用的话时间复杂度为O(1),而调用resize()方法的概率很低,所以算平均时间复杂度仍然为O(1)
def getsize(self):#求顺序表的长度
return self.size
#时间复杂度为O(1)
def __getitem__(self,i): #获取顺序表中序号为i的元素
assert 0<=i<self.size
return self.data[i]
#时间复杂度为O(1)
def __setitem__(self,i,x):
assert 0<=i<self.size #这句话叫参数i的正确性断言
self.data[i]=x
# 时间复杂度为O(1)
def GetNo(self,e):#获取第一个值为e的元素序号,如果不存在则返回-1
i=0
while i<self.size and self.data[i]!=e:#前面的小于判断是为了检测每一个元素,后面的判断语句是检测是不是所要找的元素
i+=1#为了检测下一个
if(i>=self.size):#前面的语句i进行加1之后如果大于则证明检测完但是没有找到等于e的元素值
return -1
else:
return i
#时间复杂度为O(n)
def Insert(self,i,e):#把元素e放到序号为i的位置,原来序号为i及其之后的元素均后移一位
assert 0<=i<=self.size #这句话叫参数i的正确性断言
if self.size == self.capacity:#先要判断要不要扩容
#其实我觉得应该要判断self.size+1是否等于self.capacity,因为要考虑添加完一个元素之后是否顺序表满
self.resize(2*self.size)
for j in range(self.size,i-1,-1):#最后一个移开,倒数第二个才能移动,倒数第二个移动完,倒数第三个才能移动……所以要考虑for range语句的倒用
#步长为负数,是从后向前依次遍历,但是集合的开闭依然是前面闭,后面开,[self.size,i-1),从数轴的角度来看从self.size开始,到i截止
#这里有一点不清晰,要去问老师
self.data[i]=self.data[i-1]#把元素整体右移,但我认为最后一个元素没有考虑到,应该是self.data[j+1]=self.data[j]
self.data[i]=e
self.size+=1
#计算时间复杂度:
#假设表长是n,那么序号就是0到n-1,但是插入的位置有n+1个,因为不仅n个为位置可以插入,最后序号为n的空位置也可以插入(此种情况不要移动)
#假设序号为i的位置要进行插入操作,则后面(n-1)-(i-1)个元素需要移动,即n-i个元素需要移动,要移动n-i次
#因为插入的位置有n+1个,所以假设每个位置被操作的概率是1/n+1
#进行平均时间复杂度的计算,i从0到n, Σ(1/n+1)*(n-i),i从0到n
#数学方法求出来是n/2,所以时间复杂度为O(n)
#调整顺序表内存的长度的语句发生的概率极小,所以不考虑进时间复杂度内
def Delete(self,i):#删除序号为i的元素,删除完后面的元素依次补位
assert 0<=i<=self.size #这句话叫参数i的正确性断言
for j in range(i,self.size):
self.data[i]=self.data[i+1]
self.size-=1
if self.capacity>self.initcapacity and self.size<=self.capacity/4:#为什么有这样的条件?
self.resize(self.capacity//2)
# 计算时间复杂度:
# 假设表长是n,那么序号就是0到n-1,删除的位置有n个
# 假设序号为i的位置要进行删除操作,则后面(n-1)-(i-1)-1个元素需要移动,-1的原因是本身删除了的元素不要进行移动,即n-i-1个元素需要移动,要移动n-i-1次
# 因为删除的位置有n个,所以假设每个位置被操作的概率是1/n
# 进行平均时间复杂度的计算,i从0到n, Σ(1/n+1)*(n-i-1),i从0到n
# 数学方法求出来是n-1/2,所以时间复杂度为O(n)
# 调整顺序表内存的长度的语句发生的概率极小,所以不考虑进时间复杂度内
def display(self):#输出顺序表
for i in range(0,self.size):
print(self.data[i],end='')
print()
#时间复杂度O(n)
def Deletex1(L,x):#L为顺序表,x为要删除的元素,请见方法一图解
k=0
for i in range(L.getsize()):
if L[i]!=x:
L[k]=L[i]
k+=1
L.size=k
def Deletex2(L,x):#L为顺序表,x为要删除的元素,请见方法二图解
k=0
for i in range(L.getsize()):
if L[i]!=x:
L[i-k]=L[i]
else:
k+=1
L.size-=k
def Deletex3(L,x):#L为顺序表,x为要删除的元素,请见方法三图解
i=-1
j=0
while j<L.getsize():
if L[j]!=x:
i+=1
if i!=j:
L[i],L[j]=L[j],L[i]
j+=1
L.size=i+1