一. 栈的逻辑结构
1. 栈:限定仅在表的一端进行插入和删除操作的线性表
空栈:不含任何数据元素的栈。允许插入和删除的一端称为栈顶,另一端称为栈底。
2. ADT Stack
Data
栈中元素具有相同类型及后进先出特性,
相邻元素具有前驱和后继关系
Operation
InitStack
前置条件:栈不存在
输入:无
功能:栈的初始化
输出:无
后置条件:构造一个空栈
DestroyStack
前置条件:栈已存在
输入:无
功能:销毁栈
输出:无
后置条件:释放栈所占用的存储空间
Push
前置条件:栈已存在
输入:元素值x
功能:在栈顶插入一个元素x
输出:如果插入不成功,抛出异常
后置条件:如果插入成功,栈顶增加了一个元素
Pop
前置条件:栈已存在
输入:无
功能:删除栈顶元素
输出:如果删除成功,返回被删元素值,否则,抛出异常
后置条件:如果删除成功,栈减少了一个元素
GetTop
前置条件:栈已存在
输入:无
功能:读取当前的栈顶元素
输出:若栈不空,返回当前的栈顶元素值
后置条件:栈不变
Empty
前置条件:栈已存在
输入:无
功能:判断栈是否为空
输出:如果栈为空,返回1,否则,返回0
后置条件:栈不变
endADT
二.栈的顺序结构及实现
1.栈的顺序结构称为顺序栈
2.顺序栈类的声明
const int MAX_SIZE=100;
template <class DataType>
class seqStack
{
public:
seqStack ( ) ;
~seqStack ( );
void Push ( DataType x );
DataType Pop ( );
DataType GetTop ( );
bool Empty ( );
private:
DataType data[MAX_SIZE];
int top;
}
3.顺序栈入栈算法
template <class DataType>
void seqStack<DataType> ::Push ( DataType x)
{
if (top == MAX_SIZE-1) throw “溢出”;
top++;
data[top] = x;
}
4.顺序栈出栈算法
template <class DataType>
DataType seqStack<DataType> :: Pop ( )
{
if (top == -1) throw “溢出”;
x = data[top--];
return x;
}
5.两栈共享空间类的声明
const int Stack_Size=100;
template <class DataType>
class BothStack
{
public:
BothStack( );
~BothStack( );
void Push(int i, DataType x);
DataType Pop(int i);
DataType GetTop(int i);
bool Empty(int i);
private:
DataType data[Stack_Size];
int top1, top2;
};
三.栈的链接存储结构及实现
1.栈的链接存储结构称为链栈。
2.链栈的类声明
template <class DataType>
class LinkStack
{
public:
LinkStack( );
~LinkStack( );
void Push(DataType x);
DataType Pop( );
DataType GetTop( );
bool Empty( );
private:
Node<DataType> *top;
}
3.链栈的插入算法
template <class DataType>
void LinkStack<DataType> ::Push(DataType x)
{
s = new Node<DataType>;
s->data = x;
s->next = top;
top = s;
}
4.顺序栈和链栈的比较
顺序栈:有元素个数的限制和空间浪费的问题。
链栈:没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一个指针域,从而产生了结构性开销。
四.队列
一.队列的逻辑结构
1. 队列:只允许在一端进行插入操作,而另一端进行删除操作的线性表
空队列:不含任何数据元素的队列允许插入(也称入队、进队)的一端称为队尾,允许删除(也称出队)的一端称为队头。
2.
ADT Queue
Data
队列中元素具有相同类型及先进先出特性,
相邻元素具有前驱和后继关系
Operation
InitQueue
前置条件:队列不存在
输入:无
功能:初始化队列
输出:无
后置条件:创建一个空队列
DestroyQueue
前置条件:队列已存在
输入:无
功能:销毁队列
输出:无
后置条件:释放队列所占用的存储空间
EnQueue
前置条件:队列已存在
输入:元素值x
功能:在队尾插入一个元素
输出:如果插入不成功,抛出异常
后置条件:如果插入成功,队尾增加了一个元素
DeQueue
前置条件:队列已存在
输入:无
功能:删除队头元素
输出:如果删除成功,返回被删元素值
后置条件:如果删除成功,队头减少了一个元素
GetQueue
前置条件:队列已存在
输入:无
功能:读取队头元素
输出:若队列不空,返回队头元素
后置条件:队列不变
Empty
前置条件:队列已存在
输入:无
功能:判断队列是否为空
输出:如果队列为空,返回1,否则,返回0
后置条件:队列不变
endADT
二.队列的顺序存储结构及实现
1.循环队列类的声明
const int QueueSize=100;
template <class DataType>
class CirQueue
{
public:
CirQueue( );
~ CirQueue( );
void EnQueue(DataType x);
DataType DeQueue( );
DataType GetQueue( );
bool Empty( );
private:
DataType data[QueueSize];
int front, rear;
};
2.循环队列入队算法
template <class DataType>
void CirQueue<DataType> ::EnQueue(DataType x)
{
if ((rear+1) % QueueSize == front) throw "上溢";
rear =(rear+1) % QueueSize;
data[rear] = x;
}
3.读取队头元素算法
template <class DataType>
DataType CirQueue<DataType> ::GetQueue( )
{
if (rear == front) throw "下溢";
i = (front + 1) % QueueSize;
return data[i];
}
4. 如何确定不同的队空、队满的判定条件?
方法一:附设一个存储队列中元素个数的变量num,当num=0时队空,当num=QueueSize时为队满;
方法二:修改队满条件,浪费一个元素空间,队满时数组中只有一个空闲单元;
方法三:设置标志flag,当front=rear且flag=0时为队空,当front=rear且flag=1时为队满
5链队列:队列的链接存储结构
6.链队列类的声明
template <class DataType>
class LinkQueue
{
public:
LinkQueue( );
~LinkQueue( );
void EnQueue(DataType x);
DataType DeQueue( );
DataType GetQueue( );
bool Empty( );
private:
Node<DataType> *front, *rear;
};
7.链队列构造函数算法
template <class DataType>
LinkQueue<DataType> ::LinkQueue( )
{
front = new Node<DataType>;
front->next = NULL;
rear = front;
}
8.链队列入队算法
template <class DataType>
void LinkQueue<DataType> ::EnQueue(DataType x)
{
s = new Node<DataType>;
s->data = x;
s->next = NULL;
rear->next = s;
rear = s;
}
9.链队列出队算法
template <class DataType>
DataType LinkQueue<DataType> ::DeQueue( )
{
if (rear == front) throw "下溢";
p = front->next;
x = p->data;
front->next = p->next;
if (p->next == NULL) rear = front;
delete p;
return x;
}
10. 循环队列和链队列的比较
循环队列:必须预先确定一个固定的长度,所以有存储元素个数的限制和空间浪费的问题。
链队列:没有队列满的问题,只有当内存没有可用空间时才会出现队列满,但是每个元素都需要一个指针域从而产生了结构性开销。 循环队列和链队列的基本操作都需要常数时间O (1)。