线性表链式存储结构
为了解决线性表插入、删除操作复杂和空间大小不灵活等缺点, 可以用链式存储结构表示线性表。链式存储结构的定义为:为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需要存储一个指示其后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称作为指针。这两部分信息组成数据元素ai的存储映像,称为节点(Node).
n个节点链接成一个链表,即线性表(a1,a2,...an)的链式存储结构。因为该链表每个节点只包含一个指针域,也叫做单链表。如下图:
我们把链表中第一个节点存储位置叫做头指针,整个链表的存取都必须从头指针开始。最后一个节点的指针一般为空。有时,我们会在单链表的第一个节点前辅设一个节点,称为头结点。头结点的数据域可以不存储任何信息或者链表长度等附加信息。如下图
头指针与头结点的异同
链式存储Python代码实现
class Node(object): def __init__(self,data=None): #生成数据节点 self.data=data self.next=None #指针默认指向空 class LinkList(object): def __init__(self): #生成一个链表,无头结点,默认指向空 self.head=None
单链表的读取
单链表中第i个数据的算法思路:
- 声明一个节点p,指向链表的第一个节点,初始化j从1 开始;
- 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一节点,j累加1;
- 若链表末尾p为空,则说明第i个元素不存在;
- 否则查找成功,返回节点p的数据。
Python实现代码:
def GetElem(self,i): p=self.head #p指向链表的头 j=1 #初始下标为1 while p!=None and j<i: #下标小于i或者p不到链表尾部(p=None)时,资讯 j+=1 #下标加1 p=p.next #节点指向下一个 if p==None or j>i: raise IndexError('not exit') #第i个元素不存在 return p.data #返回第i个元素的值
这个算法的时间复杂度为O(n)。算法的核心思想是“工作指针后移”
单链表的插入与删除
插入
要向单链表中插入数据(ai与ai+1之间插入),需要先断开ai与ai+1之间的指针,将新节点s指向ai+1,并用ai指向s,如下图所示三种情况:
单链表第i个数据插入节点的算法思路:
- 声明一个指针p,指向链表的头,初始化j从1开始
- 当j<i时遍历链表,让p遍历链表,指向下一个节点,并且j累加1;
- 如果p到达链表的尾部,说明i不存在;
- 否则查找成功,生成一个节点s,将数据e赋值给s;
- 在位置i后插入链表,插入的标准语句为:s.next=p.next p.next=s
- 返回成功
Python实现代码
def ListInsert(self, i, e): p=self.head j=1 while p!=None and j<i: j+=1 p=p.next if p==None or j>i: raise IndexError('not exit') s=Node(e) #生成新节点 s.next=p.next #新节点指向p的下一个元素 p.next=s #p指向s return True #返回成功
删除
删除节点实际上是将删除节点(ai)的前一个节点(ai-1)的指针绕过ai,直接指向ai+1,如下图所示
单链表第i个数据删除节点的算法思路:
- 声明一个节点p指向链表的头,初始化q(p的前一个节点)指向空,j从1开始;
- 当j<i时,遍历链表,让p不断指向下一个节点,q指向p, j累加1
- 若到达链表尾部(p为空),说明i不存在
- 否则查找成功,将p的前一个节点q指向p.next
- 将p的值返回
Python实现代码
def ListDelete(self,i): p=self.head #工作节点 q=None #p的前一个节点 j=1 while p!=None and j<i: #遍历寻找节点i j+=1 q=p p=p.next if p==None or j>i:raise IndexError('not exit') if q==None: self.head=p.next #当q指向空时,头指针指向p.next else: q.next=p.next #上一个节点指向p.next,即删除p return p.data #返回p的值
插入和删除的时间复杂度都是O(n),但是需要同时删除多个数据时,链表存储不用再多遍历一遍,所以,对于插入或者删除数据越频繁的操作,单链表的效率优势越明显。
单链表的整表创建
单链表整表创建的思路:
- 对待插入数据执行循环:
- 用数据e生成一个节点p
- 用p指向链表的头
- 链表的头重新指向p
def ListCreate(self,l): l.reverse() for e in l: #从最后一个元素到第一个元素 p=Node(e) #生成一个新节点 p.next=self.head #这个及诶单指向链表头 self.head=p #链表头指向这个节点
上面的方法是在头结点之前一次插入数据,也可以在链表尾部依次插入数据:
- 对待插入数据执行循环:
- 用数据e生成一个节点p
- 如果头为空,头指向p,否则尾节点指向p
- 让p等于尾节点
def ListCreateTail(self,l): self.head=None q=None for e in l: #从第一个到最后一个元素 p=Node(e) #新生成一个节点 if self.head==None: #如果头结点为空 self.head=p #头节点指向先生存的节点 else:q.next=p #否则q指向新节点 q=p #q等于尾节点
单链表结构与顺序存储结构优缺点
若线性表需要频繁查找,很少进行插入和删除操作时,宜采用顺序存储结构。若需要频繁插入和删除时,宜采用单链表结构。
若线性表的元素个数变化较大或者根本不知道有多大时,最好用单链表结构,如果事先知道线性表的大致长度,用顺序存储结构较好。
代码合集
#encoding=UTF-8 class Node(object): def __init__(self,data=None): #生成数据节点 self.data=data self.next=None #指针默认指向空 class LinkList(object): def __init__(self): #生成一个链表,无头结点,默认指向空 self.head=None def ListEmpty(self): return self.head==None def ClearList(self): self.head=None def GetElem(self,i): p=self.head #p指向链表的头 j=1 #初始下标为1 while p!=None and j<i: #下标小于i或者p不到链表尾部(p=None)时,资讯 j+=1 #下标加1 p=p.next #节点指向下一个 if p==None or j>i: raise IndexError('not exit') #第i个元素不存在 return p.data #返回第i个元素的值 def LoacateElem(self,e): p=self.head i=0 while p!=None: i+=1 if p.data==e:return i p=p.next return -1 def ListInsert(self, i, e): p=self.head j=1 while p!=None and j<i: j+=1 p=p.next if p==None or j>i: raise IndexError('not exit') s=Node(e) #生成新节点 s.next=p.next #新节点指向p的下一个元素 p.next=s #p指向s return True #返回成功 def ListDelete(self,i): p=self.head #工作节点 q=None #p的前一个节点 j=1 while p!=None and j<i: #遍历寻找节点i j+=1 q=p p=p.next if p==None or j>i:raise IndexError('not exit') if q==None: self.head=p.next #当q指向空时,头指针指向p.next else: q.next=p.next #上一个节点指向p.next,即删除p return p.data #返回p的值 def ListLength(self): cnt=0 p=self.head while p!=None: cnt+=1 p=p.next return cnt def ListShow(self): p=self.head q=self.head while p!=None: print p.data, p=p.next print '' def ListCreate(self,l): self.head=None l.reverse() for e in l: #从最后一个元素到第一个元素 p=Node(e) #生成一个新节点 p.next=self.head #这个及诶单指向链表头 self.head=p #链表头指向这个节点 def ListCreateTail(self,l): self.head=None q=None for e in l: #从第一个到最后一个元素 p=Node(e) #新生成一个节点 if self.head==None: #如果头结点为空 self.head=p #头节点指向先生存的节点 else:q.next=p #否则q指向新节点 q=p #q等于尾节点 def Union(self,lb): p=lb.head while p!=None: e=p.data if self.LoacateElem(e)==-1: #如果p.data不在la中 q=Node(e) q.next=self.head self.head=q p=p.next if __name__=='__main__': la=LinkList() lb=LinkList() print la.ListEmpty() la.ListCreateTail(range(0,20,2)) la.ListShow() lb.ListCreate(range(1,20,3)) lb.ListShow() print la.ListEmpty() print la.GetElem(7) print la.LoacateElem(8) la.ListInsert(5,15) la.ListShow() print la.ListLength() #print la.ListDelete(1) la.ListShow() la.Union(lb) la.ListShow() la.ClearList() la.ListShow()