线性表
线性表的定义:一些元素的序列,维持着元素之间的一种线性关系。
线性表分为顺序表和链接表(链表)
一、顺序表
1.定义
将表中元素顺序地存放在一大块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。
2.顺序表的两种布局方案
(1)如果一个表里保存的元素类型相同,那么每个表元素所需的存储量相同,即可在表里等距安排同样大小的存储位置。如下图左
(2)如果一个表里保存的元素类型不同,那么每个表元素所需的存储量可能不全相同,因此不能在表里等距安排同样大小的存储位置。对于这种情况,将实际数据元素另行存储,而在顺序表里各单元位置保存对相应元素的引用信息(链接),因为每个链接所需的存储量相同。而后对链接做一次访问,就能得到实际元素的数据。如下图右
在上图(a)中,c是指数据元素的大小,在上图(b)中,c 是指存储一个链接所需的存储量。
3.一个顺序表对象的完整信息
表头(容量+当前元素个数)+数据区
4.顺序表的两种实现方式
5.在python中的应用
list和tuple
tuple是不变的表,不支持改变其内部状态的任何操作。
二、链表
1.定义
将表元素存放在通过链接构造起来的一系列存储块里。
2.
(一)单链表
1.结点
结点由表元素域和链接域两部分构成,其表元素域elem保存的是数据项,链接域next保存的是下一个结点的链接
2.单链表的实现形式
(1)从单链表的首结点出发,可以找到这个表里的第一个元素(即这个首结点的elem域),还能找到这个表的下一个结点(即这个首结点的next域),照同样的方式进行下去,能找到表里的所有数据元素。
(2)**表头变量(表头指针)**保存着这个表的首结点的链接
(3)单链表的最后一个结点的next域是None
3.基本链表操作
创建空链表
判断是否为空链表
链表的长度
遍历链表元素
链表头部插入元素
链表尾部插入元素
链表指定位置插入元素
删除指定元素
查找指定元素是否存在
4.python代码实现
##定义结点,结点是由元素域和下一结点链接域构成的
class Node(object):
def __init__(self,elem):
self.elem=elem #结点的元素值
self.next=None #结点指向的下一个链接,初始化为None
class SingleLinkList(object):#单链表
'''
链表是否为空
链表长度
遍历整个链表
链表头部添加元素
链表尾部添加元素
指定位置添加元素
删除结点
查找结点
'''
def __init__(self,node=None):
self.__head=node #链表的头结点,初始化为None。两横线__表示私有属性
def is_empty(self): #判断链表是否为空
return self.__head==None
def length(self): #求链表长度
count=0
cur=self.__head
while cur!=None:
count+=1
cur=cur.next
return count
def travel(self): #遍历整个链表元素
cur=self.__head
while cur!=None:
print(cur.elem)
cur=cur.next
def add(self,item): #在链表头部添加元素
node=Node(item)
if self.is_empty():
self.__head=node
else:
node.next=self.__head
self.__head=node
def append(self,item): #链表尾部添加元素
node=Node(item)
if self.is_empty():
self.__head=node
else:
cur=self.__head
while cur.next!=None:
cur=cur.next
cur.next=node
def insert(self,pos,item):#指定位置添加元素
count=self.length()
if pos<=0:
self.add(item)
elif 0<pos<count:
node=Node(item)
cur=self.__head
num=1
while num<pos:
cur=cur.next
num+=1
node.next=cur.next
cur.next=node
elif pos>=count:
self.append(item)
'''
def insert(self,pos,item):
if pos<=0:
self.add(item)
elif pos>=self.length():
self.append(item)
else:
node=Node(item)
cur=self.__head
pre=None
num=0
while num<pos:
pre=cur
cur=cur.next
num+=1
node.next=cur
pre.next=node'''
'''
def insert(self,pos,item):
if pos<=0:
self.add(item)
elif pos>=self.length():
self.append(item)
else:
node=Node(item)
cur=self.__head
num=0
while num< pos-1:
cur=cur.next
num+=1
node.next=cur.next
cur.next=node'''
def remove(self,item): #删除元素————从头开始,删除遇到的第一个指定元素
cur=self.__head
pre=None
while cur!=None:
if cur.elem==item:
if cur==self.__head:
self.__head=cur.next
else:
pre.next=cur.next
break
else:
pre=cur
cur=cur.next
def search(self,item):#查找结点是否存在
cur=self.__head
while cur!=None:
if cur.elem==item:
return True
else:
cur=cur.next
return False
ll=SingleLinkList() #实例化
ll.append(1)
ll.append(2)
ll.append(3)
ll.travel()
ll.remove(3)
(二)单向循环链表
1.实现形式
单向循环链表的最后一个结点的next域指向表的第一个结点
2.python代码
##单向循环链表————尾结点的链接指向头结点
class Node(object):
def __init__(self,elem):
self.elem=elem
self.next=None
class SingleLinklist(object):
def __init__(self,node=None): #构造函数
self.__head=node #将_head指向头结点
if node:
node.next=node #指向自己
def is_empty(self):
if self.__head==None:
return True
else:
False
def length(self):
if self.__head==None: #空链表的情况
return 0
else:
cur=self.__head
count=1
while cur.next!=self.__head: #尾结点的判断标准————若cur.next==self.__head,那么cur就是尾结点。
count+=1
cur=cur.next
return count
def travel(self):
if self.is_empty(): #空链表的情况
return
else:
cur=self.__head
while cur.next!=self.__head:#循环终止条件————游标cur到达尾结点
print(cur.elem)
cur=cur.next
print(cur.elem) #尾结点
def add(self,item): #头部添加————尾结点的指向改变
node=Node(item)
if self.__head==None: #空链表的情况
self.__head=node
node.next=node #指向自己
else:
##需要找到尾结点
cur=self.__head
while cur.next!=self.__head:
cur=cur.next
#退出循环后,此时的cur是尾结点
node.next=self.__head #新结点node指向原来的头结点
self.__head=node #__head指向新结点,即新的头结点
cur.next=node #尾结点指向新的头结点
#先找到尾结点,再改变链接的指向要比先改变链接的指向,再找尾结点的时间复杂度低。————尽量不改变原来的链表
def append(self,item): #尾部添加————尾结点改变,需重新指向头结点
node=Node(item)
if self.__head==None: #空链表的情况
self.__head=node
node.next=node
else:
cur=self.__head
while cur.next!=self.__head:
cur=cur.next
#退出循环后,此时的cur是尾结点
cur.next=node
node.next=self.__head
def insert(self,pos,item):
if pos<=0: #相当于头插法
self.add(item)
elif pos>self.length()-1: #相当于尾插法
self.append(item)
else: #中间插入————头结点和尾结点都没有发生变化,故没有改变尾结点的指向
node=Node(item)
cur=self.__head #游标
num=0
while num<pos-1:
num+=1
cur=cur.next
#退出循环后,此时的cur后面要插入新的结点
node.next=cur.next #新结点指向cur后的结点
cur.next=node
def remove(self,item):
if self.__head==None: #空链表,则不执行任何操作
return
else:
cur=self.__head #游标,需要遍历
pre=None
while cur.next!=self.__head:#遍历终止的条件————游标cur到达尾结点
if cur.elem==item:
if cur==self.__head:#考虑头结点的情况
#需要找到尾结点,标明指向
rear=self.__head #游标
while rear.next!=self.__head:
rear=rear.next
#尾结点————rear
self.__head=cur.next
rear.next=self.__head
else:
pre.next=cur.next
return #结束(这里不能写break,因为break跳出循环体后,会执行循环体外的语句)
else:
pre=cur
cur=cur.next
#退出循环后,考虑尾结点的情况
if cur.elem==item:
#考虑只有一个结点的情况
if cur==self.__head:#__head的指向没有发生变化,仍是指向头结点
self.__head=None
else:
pre.next=self.__head
def search(self,item):
if self.__head==None: #考虑空链表的情况
return False
else:
cur=self.__head #游标,需要遍历
while cur.next!=self.__head:#遍历终止的条件————游标cur到达尾结点
if cur.elem==item:
return True
else:
cur=cur.next
##退出循环后,此时的cur是尾结点
#要考虑尾结点的元素值是否等于item
if cur.elem==item:
return True
else:
return False
(三)双向链表
1.实现形式
双链表的每一个结点有两个链接:一个prev指向前一个结点,一个next指向后一个结点。
双链表的首结点的prev域指向None,双链表的尾结点的next域指向None
2.python代码实现
#双向链表
class Node(object):
def __init__(self,elem):
self.elem=elem #链表元素
self.next=None #后继结点
self.prev=None #前驱结点
class DoubleLinkList(object):
def __init__(self,node=None): #初始化
self.__head=node #__head指向头结点
def is_empty(self):#判断是否是空链表
if self.__head is None:
return True
else:
return False
def length(self):
cur=self.__head #相当于游标,去遍历所有结点
count=0
while cur!=None: #结点为None时,链表遍历结束
count+=1
cur=cur.next
return count
def travel(self):
cur=self.__head
while cur!=None:
print(cur.elem)
cur=cur.next
def add(self,item):
node=Node(item)
node.next=self.__head #新结点的后继结点指向原来的头结点
self.__head.prev=node #原来头结点的前驱结点指向新结点
self.__head=node #__head指向新结点
def append(self,item):
node=Node(item)
if self.__head==None:
self.__head=node
else:
cur=self.__head
while cur.next!=None:
cur=cur.next
cur.next=node
node.prev=cur
def insert(self,pos,item):
if pos<=0:
self.add(item)
elif pos>=self.length():
self.append(item)
else:
node=Node(item)
cur=self.__head
num=0
while num< pos:
cur=cur.next
num+=1
cur.prev.next=node
node.prev=cur.prev
node.next=cur
cur.prev=node
#None是没有前驱结点和后继结点的
def remove(self,item):#删除元素————从头开始,删除遇到的第一个指定元素
cur=self.__head
while cur!=None: #遍历
if cur.elem==item:
if cur==self.__head: #判断此结点是否是头结点
self.__head=cur.next
if cur.next!=None: #判断链表是否只有一个结点 '''if cur.next:'''
cur.next.prev=None
else:
cur.prev.next=cur.next
if cur.next: #判断此结点是否是最后一个结点
cur.next.prev=cur.prev
break
else:
cur=cur.next
def search(self,item):#查找结点是否存在
cur=self.__head
while cur!=None:
if cur.elem==item:
return True
else:
cur=cur.next
return False
'''
def add(self,item):
node=Node(item)
node.next=self.__head #新结点的后继结点指向原来的头结点
self.__head=node #__head指向新结点
node.next.prev=node #新的结点的后继结点的前驱结点指向新结点
#表示方式不是唯一的
'''
'''
def insert(self,pos,item):
if pos<=0:
self.add(item)
elif pos>=self.length():
self.append(item)
else:
node=Node(item)
cur=self.__head
num=0
while num< pos-1:
cur=cur.next
num+=1
node.next=cur.next
cur.next.prev=node
cur.next=node
node.prev=cur
'''
三、小结
顺序表和链表的时间复杂度对比