栈和队列

来源:互联网 发布:如何在excel筛选数据 编辑:程序博客网 时间:2024/05/22 13:48


【学习重点】

栈和队列的操作特性;

基于顺序栈和链栈的基本操作的实现;

基于循环队列和链栈的基本操作的实现;

一、栈

1.      栈的定义

栈是限定仅在表尾进行插入和删除操作的线性表,允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈中元素除了具有线性关系外还具有后进先出的特性。

2.      栈的抽象数据类型定义

ADT  Stack

Data

栈中元素具有相同类型及后进先出的特点,相邻元素具有前驱和后继关系

Operation

InitStack

前置条件:栈不存在

输入:无

功能:栈的初始化

输出:无

后置条件:构造一个空栈

DestroyStack

前置条件:栈已存在

输入:无

功能:销毁栈

输出:无

后置条件:释放线性表栈所占用的存储空间

Push

前置条件:栈已存在

输入:元素值x

功能:入栈操作,在栈顶插入一个元素x

输出:如果插入不成功,则抛出异常

后置条件:如果插入成功,则栈顶增加了一个元素

Pop

前置条件:栈已存在

输入:无

功能:出栈操作,删除栈顶元素

输出:如果删除成功,返回被删除的元素值,否则抛出异常

后置条件:如果删除成功,则栈顶少了一个元素

GetTop

前置条件:栈已存在

输入:无

功能:取栈顶元素,读取当前的栈顶元素

输出:若栈不空,返回当前的栈顶元素

后置条件:栈不变

Empty

前置条件:栈已存在

输入:无

功能:判空操作,判断栈是否为空

输出:如果栈为空,返回1,否则返回0

后置条件:栈不变

endADT

2.栈的存储结构及实现

2.1栈的顺序存储结构——顺序栈

栈的顺序存储结构称为顺序栈

2.2顺序栈的实现

const intStackSize=10;

template<classDataType>

class SeqStack

{public:

SeqStack(){top=-1;}

~SeqStack(){}

void Push(DataTypex);

DataType Pop();

DataTypeGetTop(){if(top!=-1)return data[top];

intEmpty(){top==-1?return 1:return 0;}

private:

DataTypedata[StackSize];

int top;};

 

(1)栈的初始化

初始化栈只需将栈顶元素指针top置为-1.

(2)顺序栈入栈操作

在栈中插入一个元素x只需将栈顶指针top加1,然后在top指向的位置填入元素x,算法如下:

template<classDataType>

voidSeqStack<DataType>::Push(DataType x)

{

if(top==StackSize-1)throw"上溢"

data[++top]=x;}

(3)顺序栈出栈操作

删除栈顶元素只需取出栈顶元素,然后将栈顶指针top-1,算法如下:

template<classDataType>

voidSeqStack<DataType>::pop()

{

if(top==-1)throw"下溢"

x=data[top--];

return x;}

(4)取栈顶元素

取栈顶元素只是将top指向的栈顶元素取出,并不修改栈顶指针。

(5)判空操作

判空操作只需判断top==1是否成立,如果成立,则栈为空,返回1;如果不成立,则栈非空,返回0.

3.      两栈共享空间

抽象数据类型定义如下:

ADT BothStack

Data

共享的数组空间长度StackSize

存放栈元素的数组data[StackSize]

栈1的栈顶指针top1

栈2的栈顶指针top2

Operation

BothStack

前置条件:共享数组空间不存在

输入:无

功能:创建两栈共享的数组空间

输出:无

后置条件:两栈均为空,top1=-1,top2=StackSize

~BothStack

前置条件:共享空间已存在

输入:无

功能:销毁两栈共享的数组空间

输出:无

后置条件:将两栈共享的数组空间释放

GetTop

前置条件:共享空间已存在

输入:栈号i

功能:读取栈i当前的栈顶元素

输出:若栈i不为空,返回栈i当前的栈顶元素

后置条件:两栈均不变

Push

前置条件:共享空间已存在

输入:栈号i,元素值x

功能:入栈操作,在栈i中插入元素x

输出:若插入不成功,则抛出异常

后置条件:若插入成功,则栈i插入了一个栈顶元素

Pop

前置条件:共享空间已存在

输入:栈号i

功能:出栈操作,在栈i中删除栈顶元素

输出:若删除不成功,则抛出异常

后置条件:删除成功,则栈中删除了栈顶元素

Empty

前置条件:共享空间已存在

输入:栈号i

功能:判空操作,判断栈i是否为空栈

输出:若栈i是空栈,则返回1,否则返回0

后置条件:两栈均不变

endADT

对应的c++类声明如下:

const intStackSize=100;

template <classDataType>

class BothStack

{

public:

       BothStack(){top1=-1;top2=StackSize;}

       ~BothStack(){}

void Push(inti,DataType X);

 

DataType Pop(inti);

DataTypeGetTop(int i);

int Empty(int i);

private:

DataTypedata[StackSize];

int top1,top2;};

(1)入栈操作

当存储栈的数组中没有空闲单元时为栈满,此时栈1的栈顶元素和栈2的栈顶元素位于数组中的相邻位置,即top1=top2-1,另外,当新元素插入栈2时,栈顶指针top2不是加1而是减1,算法如下:

两栈共享空间入栈算法Push

template <classDataType>

voidBothStack<DataType>::Push(int i,DataType x)

{

if(top1==top2-1)throw"上溢";

if(i==1)data[++top1]=x;

if(i==2)data[--top2]=x;}

(2)出栈操作

当top1=-1时栈1为空;当top2=StackSize时栈2为空。另外,当栈2删除元素时,栈顶指针top2不是减一而是加一,算法如下:

template <classDataType>

DataTypeBothStack<DataType>::Pop(int i)

{

       if(i==1){if(top1==-1)throw"下溢";

returndata[top1--];

}

       if(i==2){if(top2==StackSize)throw"下溢";

returndata[top2++];}}

4.栈的链接存储结构及实现

4.1栈的链接存储结构---链栈

栈的链接存储结构称为链栈

4.2链栈的实现

template <classDataType>

class LinkStack

{

public:

       LinkStack(){top=NULL;}

~LinkStack();

void Push(DataTypex);

DataType Pop();

DataTypeGetTop(){if(top!=NULL)return top->data;}

intEmpty(){top==NULL?return 1:return 0;}

private:

Node<DataType>*top;};

(1)构造函数

构造函数的作用是初始化一个空的链栈,由于链栈不带头结点,因此只需将栈顶指针top置为空。

(2)入栈操作

链栈的插入操作只需处理栈顶即第一个位置的情况,而无需考虑其他位置的情况,其算法如下:

template <classDataType>

voidLinkStack<DataType>::Push(DataType x)

{

s=new Node;s->data=x;

s->next=top;top=s;}

(3)出栈操作

链栈的出栈操作只需处理栈顶即第一个位置的情况,而无需考虑其他位置的情况。算法如下:

template <classDataType>

DataTypeLinkStack<DataType>::Pop()

{

if(top==NULL)throw"下溢";

x=top->data;p=top;

top=top->next;

delete p;

return x;}

(4)取栈顶元素

取栈顶元素只需返回栈顶指针top所在的结点的数据域。

(5)判空操作

栈链的判空操作只需判断top==NULL是否成立。如果成立,则栈为空,返回1;如果不成立,则栈非空,返回0.

(6)析构函数

链栈的析构函数需要将链栈中所有结点的存储空间释放,算法与单链表类的析构函数类似。

5.顺序栈和链栈的比较

链栈没有栈满问题,只有当内存没有可用空间时才会出现栈满情况,但是每一个元素都需要一个指针域,从而产生了结构性开销。所以当栈的使用过程中元素个数变化较大时,用链栈是适宜的;反之,应采用顺序栈。

二、队列

1.队列的逻辑结构

1.1队列的定义

队列时只允许在一端进行插入操作,在另一端进行删除操作的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。其具有先进先出的特性。

1.2队列的抽象数据类型定义

ADT  Queue

Data

队列中元素具有相同类型及先进先出的特点,相邻元素具有前驱和后继关系

Operation

InitQueue

前置条件:队列不存在

输入:无

功能:队列的初始化

输出:无

后置条件:创建一个空队列

DestroyQueue

前置条件:队列已存在

输入:无

功能:销毁队列

输出:无

后置条件:释放队列所占用的存储空间

EnQueue

前置条件:队列已存在

输入:元素值x

功能:入队操作,在队尾插入一个元素x

输出:如果插入不成功,则抛出异常

后置条件:如果插入成功,则队尾增加了一个元素

DeQueue

前置条件:队列已存在

输入:无

功能:出队操作,删除队头元素

输出:如果删除成功,返回被删除的元素值,否则抛出异常

后置条件:如果删除成功,则队头少了一个元素

GetQueue

前置条件:队列已存在

输入:无

功能:读取当前的队头元素

输出:若队列不空,返回当前的队头元素

后置条件:队列不变

Empty

前置条件:队列已存在

输入:无

功能:判空操作,判断队列是否为空

输出:如果队列为空,返回1,否则返回0

后置条件:队列不变

endADT

2.队列的顺序存储结构及实现

2.1队列的顺序存储结构——循环队列

队列的这种头尾相接的顺序存储结构成为循环队列。

2.2循环队列的实现

const intQueueSize=100;

template<classDataType>

class CirQueue

{

public:

       CirQueue(){front=rear=QueueSize-1;}

       ~CriQueue(){}

void EnQueue(DataTypex);

DataTypeDeQueue();

DataTypeGeQueue();

intEmpty(){front==rear?return1:return 0;}

private :

DataTypedata[QueueSize];

int front,rear;};

(1)构造函数

其作用是初始化一个空的循环队列,只需将队头指针和队尾指针同时指向数组中的某一个位置,一般是数组的高端,即rear=front=QueueSize-1.

(2)入队操作

循环队列的入队操作只需将队尾的指针rear在循环意义下加1,然后将带插入元素x 插入队尾位置。算法如下:

template<classDataType>

voidCirQueue<DataType>::EnQueue(DataType x)

{

if((rear+1)%QueueSize==front)throw"上溢";

rear=(rear+1)%QueueSize;

data[rear]=x;}

(3)出队操作

 

循环队列的出队操作只需将队头的指针front在循环意义下加1,然后读取并返回队头元素。算法如下:

循环队列的出队算法DeQueue

template<classDataType>

voidCirQueue<DataType>::DeQueue()

{

if(rear==front)throw"下溢";

i=(front+1)%QueueSize;

return data[i];}

(4)读取队头元素

template<classDataType>

DataTypeCirQueue<DataType>::GetQueue()

{

if(rear==front)throw"下溢";

i=(front+1)%QueueSize;

return data[i];}

(5)判空操作

循环队列的判空操作只需判断front==rear是否成立。如果成功,则队列为空,返回1;如果不成立,则队列非空,返回0。

3.队列的链接存储结构及实现

3.1队列的链接存储结构—链队列

队列的链接存储结构称为链队列。

3.2链队列的实现

template<classDataType>

class LinkQueue

{

public:

LinkQueue();

~LinkQueu();

voidEnQueue(DataType x);

DataTypeDeQueue();

DataTypeGetQueue();

intEmpty(){front==rear?return1:return0;}

Private:

Node<DataType>*front,*rear;};

(1)构造函数

构造函数的作用是初始化一个空的链队列,只需申请一个头结点,然后让队头指针和队尾均指向头结点,算法如下:

链队列构造函数算法LinkQueue

template<classDataType>

LinkQueue<DataType>::LinkQueue()

{

s=newNode;s->next=NULL;

front=rear=s;}

(2)入队操作

链队列的插入操作只考虑在链表的尾部进行,由于链队带头结点,空链队列和非空链队列的入队操作语句一致。算法如下:

链队列入队算法EnQueue

template<classDataType>

voidLinkQueue<DataType>::EnQueue(DataType x)

{

s=newNode;s->data=x;

s->next=NULL;

rear->next=s;

rear=s;}

(3)出队操作

链队列出队操作DeQueue

template<classDataType>

DataTypeLinkQueue<DataType>::EnQueue()

{

if(rear==front)throw"下溢";

p=front->next;x=p->data;

front->next=p->next;

if(p->next==NULL)rear=front;

delete p;

return x;}

(4)取队头操作

取链队列的队头元素只需返回第一个元素结点的数据域,即返回first->next->data

(5)判空操作

判断front==rear是否成立。如果成立,则队列为空,返回1,如果不成立,则队列非空,返回0.

 

0 0
原创粉丝点击