• [读书笔记]-大话数据结构-4-栈与队列(一)-栈、共享栈和链栈


    栈与队列

        栈是限定仅在表尾进行插入和删除操作的线性表。

        队列是只允许在一端进行拆入操作、而另一端进行删除操作的线性表。

    栈的定义

        栈(stack)是限定仅在表尾进行插入和删除操作的线性表。我们把允许插入和删除的一端称为栈顶(top),另一端称为(bottom),不含任何元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构

        栈的拆入操作,也叫做进栈,也称压栈、入栈。栈的删除操作,也叫做出栈,也有的叫做弹栈。

    栈的抽象数据类型

    ADT 栈(stack)
    Data
        '''同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。'''
    Operation 
        InitStack(*S):'''初始化操作,建立一个空栈S。'''
        DestroyStack(*S):'''若栈存在,则销毁它'''
        ClearStack(*S):'''将栈清空'''
        StackEmpty(S):'''若栈为空,返回true,否则返回false'''
        GetTop(S,*e):'''若栈存在且非空,用e返回S的栈顶元素。'''
        Push(*S,e):'''若栈S存在,插入新元素e到栈S中并成为栈顶元素。'''
        Pop(*S,e):'''删除栈S中栈顶元素,并用e返回其值。'''
        StackLength(S):'''返回栈S的元素个数。'''
    endADT

    栈的顺序存储结构及实现

        我们需要一个线性表存储数据,和一个指向栈顶的top变量。下标0表示栈底。

    class SqStack(object):
        def __init__(self,size=20):
            self.data=[None for i in range(size)]
            self.size=size
            self.top=-1

        一个大小为5的栈如下图所示:

    栈的顺序存储结构--进栈操作

        对于进栈操作,Python代码如下:

        def Push(self,e):  #将e压入栈顶
            if self.top+1>=self.size:   #满栈
                return 0    #压栈失败
            self.top+=1    #栈顶指针+1
            self.data[self.top]=e   #将新元素赋值给栈顶
            return 1    #压栈成功

    栈的顺序存储结构--出栈操作

        def Pop(self): #若栈不为空,讲栈顶元素,否则返回None
            if self.top<0:   #若栈为空,返回None
                return None
            e=self.data[self.top]  #获得栈顶元素
            self.data[self.top]=None  #删除栈顶元素
            self.top-=1    #栈指针-1
            return e

    栈的线性存储结构完整代码

    class SqStack(object):
        def __init__(self,size=20):
            self.data=[None for i in range(size)]
            self.size=size
            self.top=-1
        
        def Push(self,e):  #将e压入栈顶
            if self.top+1>=self.size:   #满栈
                return 0    #压栈失败
            self.top+=1    #栈顶指针+1
            self.data[self.top]=e   #将新元素赋值给栈顶
            return 1    #压栈成功
        
        def Pop(self): #若栈不为空,讲栈顶元素,否则返回None
            if self.top<0:   #若栈为空,返回None
                return None
            e=self.data[self.top]  #获得栈顶元素
            self.data[self.top]=None  #删除栈顶元素
            self.top-=1    #栈指针-1
            return e
        def ClearStack(self):  #将栈清空
            while self.top>=0:
                self.data[self.top]=None
                self.top-=1
        def StackEmpty(self):  #判断栈是否为空
            return self.top==-1
        def GetTop(self):  #返回栈顶元素
            return self.data[self.top]
        def StackLength(self):#返回栈的元素个数
            return self.top+1
    View Code

    两栈共享空间

        用线性存储表示栈有好处,只需要再一端操作,避免了插入、删除移动大量元素,但也有一个缺点,事先不知道栈的大小,如果开辟太多空间,造成存储空间浪费。因此可以用两个占共享空间,即一个栈的栈底为数组的始端(下标为0),另一个栈为数组的末端(下标n-1),这样两个栈如果增加元素就从两端往中间延伸。如下图:


    class SqDoubleStack(object):
        def __init__(self,size=40):
            self.data=[None for i in range(size)]   #列表数据
            self.size=size  #栈的大小
            self.top1=-1   #第一个栈为空时指向-1
            self.top2=size  #第二个栈为空时指向n

    两栈共享空间的push方法

        对第一个栈压栈的时候,其top指针+1;第二个栈压栈时,top指针-1,当两个指针相遇时,表示栈满。

        def Push(self,e,stacknumber):
            if self.top1+1==self.top2:  #栈满
                return 0
            if stacknumber==1:   #如果为第一个栈
                self.top1+=1      #栈顶+1
                self.data[self.top1] =e   #给栈顶位置赋值
            elif stacknumber==2:    #如果为第二个栈
                self.top2-=1     #栈顶-1
                self.data[self.top2] =e #给栈顶赋值
            else: return 0
            return 1

    两栈共享空间的pop方法

        与压栈类似,第一个栈出栈时,top指针-1,当其指向-1时表示空栈;第二个栈出栈时top指针+1,当其指向n时,表示满栈。

        def Pop(self,stacknumber):
            if stacknumber==1:
                if self.top1<0:  #如果栈1为空,返回0
                    return 0
                e=self.data[self.top1]   #取出栈1的元素
                self.data[self.top1]=None
                self.top1-=1
            elif stacknumber==2:   #
                if self.top2>=self.size:  #如果栈2为空,返回0
                    return 0
                e=self.data[self.top2]   #取出栈2的元素
                self.data[self.top2]=None
                self.top2+=1   
            else:return 0   #如果栈指定的不对,返回0
            return e   #返回e

        事实上,这样的数据结构,通常是两个栈的空间需求有相反关系时,采用较多。

    两栈共享空间的完整代码

    class SqDoubleStack(object):
        def __init__(self,size=40):
            self.data=[None for i in range(size)]   #列表数据
            self.size=size  #栈的大小
            self.top1=-1   #第一个栈为空时指向-1
            self.top2=size  #第二个栈为空时指向n
        
        def Push(self,e,stacknumber):
            if self.top1+1==self.top2:  #栈满
                return 0
            if stacknumber==1:   #如果为第一个栈
                self.top1+=1      #栈顶+1
                self.data[self.top1] =e   #给栈顶位置赋值
            elif stacknumber==2:    #如果为第二个栈
                self.top2-=1     #栈顶-1
                self.data[self.top2] =e #给栈顶赋值
            else: return 0
            return 1
        def Pop(self,stacknumber):
            if stacknumber==1:
                if self.top1<0:  #如果栈1为空,返回0
                    return 0
                e=self.data[self.top1]   #取出栈1的元素
                self.data[self.top1]=None
                self.top1-=1
            elif stacknumber==2:   #
                if self.top2>=self.size:  #如果栈2为空,返回0
                    return 0
                e=self.data[self.top2]   #取出栈2的元素
                self.data[self.top2]=None
                self.top2+=1   
            else:return 0   #如果栈指定的不对,返回0
            return e   #返回e
        def ClearStack(self,stacknumber):#清空某个栈
            if stacknumber==1:
                while self.top1>=0:  #当栈1部委空时,循环一下操作
                    self.data[self.top1]=None  #清除栈1的当前元素
                    self.top1-=1          #栈1的栈顶位置往下移
            elif stacknumber==2:   
                while self.top2<self.size:  #当栈2不为空时,循环
                    self.data[self.top2]=None #清除当前
                    self.top2+=1   #栈2的栈顶往上移
            else:
                raise ERROR()
        def StackEmpty(self,stacknumber):#某个栈是否为空
            if stacknumber==1:
                return self.top1==-1  #返回栈1是否为空
            elif stacknumber==2:
                return self.top2==self.size  #返回栈2是否为空
            else:raise ERROR()
        def GetTop(self,stacknumber):#获取某个栈的栈顶元素
            if stacknumber==1:
                if self.top1>=0: return self.data[self.top1]   #栈1不为空返回栈顶元素
            elif stacknumber==2:
                if self.top2<=self.size: return self.data[self.top2] #栈2不为空返回栈顶元素
            return None  #否则返回空
        def StackLength(self,stacknumber):#返回栈的长度
            if stacknumber==1:
                return self.top1+1
            elif stacknumber==2:
                return self.size-self.top2
            else:raise ERROR()
    View Code

    栈的链式存储结构及实现

         栈的链式存储结构,简称链栈。对于链式存储结构,最好的方法是把栈顶放在链表的头部,链栈基本不存在栈满的情况,除非内存满。链栈的top指针指向空时,表示空栈。链栈的示意图如下:

        链栈的实现代码

    class Node(object):   #定义链表节点
        def __init__(self,data=None):
            self.data=data
            self.next=None        
            
    class LinkStack(object):
        def __init__(self):  #生成一个空的链栈
            self.top=None
            self.count=0   #计算栈的元素个数

    链栈的进栈操作

        def Push(self,e):  #将e压入栈顶
            tnode=Node(e)   #新生成一个节点
            tnode.next=self.top   #指向栈顶的元素
            self.top=tnode  #栈顶指向这个新节点
            self.count+=1

    链栈的出栈操作

        def Pop(self): #若栈不为空,讲栈顶元素,否则返回None
            if self.top==None:  #如果栈空,返回None
                return None
            else:
                e=self.top    #获取栈顶元素
                self.top=self.top.next  #栈顶指向下一个元素
                self.count-=1
                return e.data

    链栈的完整代码

    class LinkStack(object):
        def __init__(self):  #生成一个空的链栈
            self.top=None
            self.count=0   #计算栈的元素个数
        
        def Push(self,e):  #将e压入栈顶
            tnode=Node(e)   #新生成一个节点
            tnode.next=self.top   #指向栈顶的元素
            self.top=tnode  #栈顶指向这个新节点
            self.count+=1
        
        def Pop(self): #若栈不为空,讲栈顶元素,否则返回None
            if self.top==None:  #如果栈空,返回None
                return None
            else:
                e=self.top    #获取栈顶元素
                self.top=self.top.next  #栈顶指向下一个元素
                self.count-=1
                return e.data
            
        def ClearStack(self):  #将栈清空
            self.top =None
            self.count=0
                
        def StackEmpty(self):  #判断栈是否为空
            return self.top==None
        def GetTop(self):  #返回栈顶元素
            return self.top.data
        def StackLength(self):#返回栈的元素个数
            return self.count
    View Code

    顺序栈与链栈的时间复杂度都是O(1),但顺序栈需要事先确定一个长度,可能存在空间浪费问题。

    如果栈的使用过程中元素的变化不可预料,有事很小,有时非常大,那么最好用链栈,反之,如果它的变化在可控范围内,建议用顺序栈会好一些。

  • 相关阅读:
    Objective-C Runtime 运行时之四:Method Swizzling
    App启动加载广告页面思路
    关于CoreData和SQLite多线程访问时的线程安全问题
    HIVE学习(待更新)
    流处理环境搭建
    CAJ2PDF
    ArcMap加载在线地图
    学习opencv(持续更新)
    风险和策略(待更新)
    区块链入门教程(转)
  • 原文地址:https://www.cnblogs.com/zhaoxy/p/7800204.html
Copyright © 2020-2023  润新知