• [读书笔记]-大话数据结构-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
  • 相关阅读:
    在小程序开发的新风口 看华为云如何助立创科技抢占市场红利
    华为云软件开发云助力集时通软件敏捷开发
    一站式云端安卓软件开发工具的体验之路!
    一名优秀的全栈工程师必需的开发工具
    学哪种编程语言更有“钱”赚?
    深度剖析:最新云端开发工具如何实现敏捷+DevOps开发落地
    软件开发未来发展五大趋势,从业者们注意了!
    十个最有“钱景”的IT技能, 你掌握了哪个?
    “敏捷开发”之白话篇
    解决软件开发中的多个痛点——华为软件开发云
  • 原文地址:https://www.cnblogs.com/zhaoxy/p/7728122.html
Copyright © 2020-2023  润新知