数据结构(C++版)第三章 栈和队列

 

(1)从数据结构角度看,栈和队列是操作受限的线性表,他们的逻辑结构相同。

(2)从抽象数据类型角度看,栈和队列是两种重要的抽象数据类型。

一、

1栈的逻辑结构:

1、栈的定义

栈:限定仅在表的一端进行插入和删除操作的线性表。

允许插入和删除的一端称为栈顶,另一端称为栈底。

空栈:不含任何数据元素的栈。

插入:入栈、进栈、压栈

删除:出栈、弹栈

栈的操作特性:后进先出

2栈的抽象数据类型定义

ADTStack

Data

栈中元素具有相同类型及后进先出特性,

相邻元素具有前驱和后继关系

Operation

InitStack

前置条件:栈不存在

输入:无

功能:栈的初始化

输出:无

后置条件:构造一个空栈

DestroyStack

前置条件:栈已存在

输入:无

功能:销毁栈

输出:无

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

Push

前置条件:栈已存在

输入:元素值x

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

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

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

Pop

前置条件:栈已存在

输入:无

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

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

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

GetTop

前置条件:栈已存在

输入:无

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

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

后置条件:栈不变

Empty

前置条件:栈已存在

输入:无

功能:判断栈是否为空

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

后置条件:栈不变

endADT

2栈的顺序存储结构及实现

1、栈的顺序存储结构——顺序栈

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

通常把数组中下标为0的一端作为栈底,同时附设指针top指示栈顶元素在数组中的位置。(top=数组元素的下标)

设存储栈元素的数组长度为StackSize,则:

栈空时,栈顶指针top==-1;

栈满时,栈顶指针top==StackSize-1.

入栈时,top=top+1;

出栈时,top=top-1.

2顺序栈的实现

类的声明

constint StackSize=100;

template<class DataType>

classseqStack

{

public:

seqStack( ) {top=-1;}

~seqStack( ){}

voidPush ( DataType x );

DataTypePop ( );

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

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

private:

DataTypedata[StackSize];

int top;

};

入栈Push

template<class DataType>

voidSeqStack<DataType> ::Push ( DataType x)

{

if (top== StackSize -1) throw “上溢”;

top++;

data[top]= x;

}

出栈Pop

template<class DataType>

DataTypeseqStack<DataType> :: Pop ( )

{

if (top== -1) throw “下溢”;

x =data[top--];

returnx;

}

3两栈共享空间

两栈共享空间:使用一个数组来存储两个栈,让一个栈的栈底为该数组的始端,另一个栈的栈底为该数组的末端,两个栈从各自的端点向中间延伸。

1的底固定在下标为0的一端;

2的底固定在下标为StackSize-1的一端。

top1top2分别为栈1和栈2的栈顶指针;

StackSize为整个数组空间的大小

1为空:top 1=-1;

2为空:top 2=StackSize;

栈满:top 2=top1 + 1;

入栈:top 1++; top 2--;

出栈:top 1--; top 2++;

类的声明:

constint StackSize=100;

template<class DataType>

classBothStack

{

public:

BothStack(){top 1=-1;top 2= StackSize;}

~BothStack(){}

voidPush(int i, DataType x);

DataTypePop(int i);

DataTypeGetTop(int i);

intEmpty(int i);

private:

DataTypedata[StackSize];

inttop1, top2;

};

入栈Push

template<class DataType>

voidSeqStack<DataType> ::Push (int I, DataType x)

{

if (top1== top 2 - 1) throw “上溢”;

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

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

}

出栈Pop

template<class DataType>

DataTypeseqStack<DataType> :: Pop ( int i)

{

if(i==1)

{

if(top1==-1) throw“下溢”;

returndata[top1--];

}

if(i==2)

{

if(top2==StackSize) throw“下溢”;

returndata[top2++];

}

}

3栈的链接存储结构及实现

1、栈的链接存储结构——链栈

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

将链头作为栈顶,方便操作;链栈不需要附设头结点

2链栈的实现

类的声明

template<class DataType>

classLinkStack

{

public:

LinkStack(){top=NULL;}

~LinkStack();

voidPush(DataType x);

DataTypePop( );

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

intEmpty( );

private:

Node<DataType>*top;

};

入栈Push

template<class DataType>

voidLinkStack<DataType> ::Push(DataType x)

{

s = newNode<DataType>;

s->data= x;

s->next= top;

top = s;

}

出栈Pop

template<class DataType>

DataTypeLinkStack<DataType> ::Pop( )

{

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

x =top->data;

p = top;

top =top->next;

deletep;

returnx;

}

4顺序栈和链栈的比较

时间性能:相同,都是常数时间O(1)

空间性能:

顺序栈:有元素个数的限制和空间浪费的问题。

链栈:没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一个指针域,从而产生了结构性开销。

总之,当栈的使用过程中元素个数变化较大时,用链栈是适宜的,反之,应该采用顺序栈。

二、队列

1队列的逻辑结构

定义

队列:只允许在一端进行插入操作,而另一端进行删除操作的线性表。

允许插入(也称入队、进队)的一端称为队尾,允许删除(也称出队)的一端称为队头。

空队列:不含任何数据元素的队列。

队列的操作特性:先进先出

队列的抽象数据类型定义

ADTQueue

Data

队列中元素具有相同类型及先进先出特性,

相邻元素具有前驱和后继关系

Operation

InitQueue

前置条件:队列不存在

输入:无

功能:初始化队列

输出:无

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

DestroyQueue

前置条件:队列已存在

输入:无

功能:销毁队列

输出:无

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

EnQueue

前置条件:队列已存在

输入:元素值x

功能:在队尾插入一个元素

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

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

DeQueue

前置条件:队列已存在

输入:无

功能:删除队头元素

输出:如果删除成功,返回被删元素值

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

GetQueue

前置条件:队列已存在

输入:无

功能:读取队头元素

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

后置条件:队列不变

Empty

前置条件:队列已存在

输入:无

功能:判断队列是否为空

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

后置条件:队列不变

endADT

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

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

设置队头、队尾两个指针

约定:队头指针front指向队头元素的前一个位置,

队尾指针rear指向队尾元素。

假溢出:当元素被插入到数组中下标最大的位置上之后,队列的空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做假溢出

循环队列:将存储队列的数组头尾相接。

队空:rear=front

队满:(rear+1)%QueueSize=front

2循环队列的实现

类的声明:

constint QueueSize=100;

template<class DataType>

classCirQueue

{

public:

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

~CirQueue( ){}

voidEnQueue(DataType x);

DataTypeDeQueue( );

DataTypeGetQueue( );

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

private:

DataTypedata[QueueSize];

intfront, rear;

};

入队EnQueue

template<class DataType>

voidCirQueue<DataType> ::EnQueue(DataType x)

{

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

rear=(rear+1) % QueueSize;

data[rear]= x;

}

出队DeQueue

template<class DataType>

DataTypeCirQueue<DataType> ::DeQueue( )

{

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

front=(front + 1) % QueueSize;

return data[front];

}

读队头元素GetQueue

template<class DataType>

DataTypeCirQueue<DataType> ::GetQueue( )

{

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

i =(front + 1) % QueueSize;

returndata[i];

}

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

1、队列的链接存储结构——链队列

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

队头指针即为链表的头指针。

2、链队列的实现

类的声明

template<class DataType>

classLinkQueue

{

public:

LinkQueue();

~LinkQueue();

voidEnQueue(DataType x);

DataTypeDeQueue( );

DataTypeGetQueue( )

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

private:

Node<DataType>*front, *rear;

};

构造函数LinkQueue

template<class DataType>

LinkQueue<DataType>::LinkQueue( )

{

s = newNode<DataType>;

s->next= NULL;

rear =front=s;

}

入队EnQueue

template<class DataType>

voidLinkQueue<DataType> ::EnQueue(DataType x)

{

s = newNode<DataType>;

s->data= x;

s->next= NULL;

rear->next= s;

rear =s;

}

出队DeQueue

template<class DataType>

DataTypeLinkQueue<DataType> ::DeQueue( )

{

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

p =front->next;

x =p->data;

front->next= p->next;

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

deletep;

returnx;

}

7循环队列和链队列的比较

时间性能:循环队列和链队列的基本操作都需要常数时间O(1)

空间性能:

1、循环队列:必须预先确定一个固定的长度,所以有存储元素个数的限制和空间浪费的问题。

2、链队列:没有队列满的问题,只有当内存没有可用空间时才会出现队列满,但是每个元素都需要一个指针域,从而产生了结构性开销。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值