[读书笔记]-大话数据结构-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),但顺序栈需要事先确定一个长度,可能存在空间浪费问题。

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

 

posted @ 2017-11-08 16:24  zhaoxianyu  阅读(503)  评论(0编辑  收藏  举报