[读书笔记]-大话数据结构-3-线性表-线性表的链式存储

Posted zhaoxianyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[读书笔记]-大话数据结构-3-线性表-线性表的链式存储相关的知识,希望对你有一定的参考价值。

线性表链式存储结构

    为了解决线性表插入、删除操作复杂和空间大小不灵活等缺点, 可以用链式存储结构表示线性表。链式存储结构的定义为:为了表示每个数据元素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()
    
View Code

 

以上是关于[读书笔记]-大话数据结构-3-线性表-线性表的链式存储的主要内容,如果未能解决你的问题,请参考以下文章

[读书笔记]-大话数据结构-3-线性表-静态链表循环链表和双向链表

大话数据结构读书笔记系列线性表

大话数据结构读书笔记

《大话数据结构》笔记--线性表的顺序存储结构

学习总结《大话数据结构》- 第3章-线性表

大话数据结构-2