数据结构 第三章

  3.1      

3.1.1    栈的逻辑结构

1.栈(stack是限定仅在表尾进行插入和删除操作的线性表,允许插入和删除的而一端称为栈顶,另一端称为栈底。不含任何元素的栈称为空栈

 

2.栈的特性:后进先出(在任何时候出栈的元素都只能是栈顶元素,即最后入栈者最先出栈)。

 

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

ADT Stack

Data

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

Operation

   InitStack

      前置条件:栈不存在

      输入:无

      功能:栈的初始化

      输出:无

      后置条件:构造一个空栈

DestroyStack

      前置条件:栈已存在

      输入:无

      功能:销毁栈

      输出:无

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

Push

      前置条件:栈已存在

      输入:元素值x

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

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

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

Pop

      前置条件:栈已存在

      输入:无

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

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

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

GetTop

      前置条件:栈已存在

  

      输入:无

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

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

      后置条件:栈不变

Empty

 

  

      前置条件:栈已存在

      输入:无

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

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

      后置条件:栈不变

endADT

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

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

     通常把数组中下标为0的一端作为栈底 。             指针top指示栈顶元素在数组中的位置。

     StackSize:存储栈元素的数组长度。                     栈空:top= -1       栈满:top=StackSize - 1

2.  顺序栈的实现

  将栈的抽象数据类型定义在顺序栈存储结构下用c++中的类实现。由于栈元素的数据类型不能确定,因此采用c++的模板机制。

 

const  int  StackSize=10;      // 10只是示例性的数据,可以根据实际问题具体定义

template  <class  datatype>   //定义模板类SeqStack

class  SeqStack

{

 public:

    SeqStack(){top= -1;}            //构造函数,初始化一个空栈

   ~ SeqStack(){ }               //析构函数为空

 Void push(DataType x);  //入栈操作,将元素x入栈

DataType pop();     //出栈操作,将栈顶元素弹出

DataType GetTop(){if(top!=-1) return data [top];} //取栈顶元素

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

Private:

Datatype data[StckMaxsize];

Int top;

                 

;

(1) 栈的初始化

初始化一个空栈只需将栈顶指针top置为-1

2)入栈操作

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

template<class DataType>

void SeqStack<DataType>::Push(DataType x)

{

  If(top==StackSize-1) throw上溢

  data[++top=x;]

}

3)出栈操作

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

Template<class DataType>

DataType SeqStack<DataType>::pop()

{

 If(top==-1) throw下溢;

 X=data[top--];

 return x;

}

4)取栈顶元素

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

5)判空操作

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

3 两栈共享空间

两共享占空间入栈算法push

Template <class DataType>

Void BothStack<DataType>::push(int i,DataType x)

{

  If(top1==top2-1) throw上溢;

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

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

}

两栈共享空间出栈算法Pop

Template <class DataType>

DataType BothStack<DataType>::Pop(int i)

{

  If(i==1)

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

  Return data[top--];

}

If(i==2)

If(top2==StackSize)throw下溢

Return data[top2++];

  }

}

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

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

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

2. 链栈的实现

构造函数

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

入栈操作

链栈入栈算法Push

Template<class DataType>

Void LinkStack<DataType>::Push(DataType x)

{

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

s->next=top;top=s;

}

出栈操作

链栈出栈算法Pop

Template<class DataType>

DataType LinkStack<DataType>::Pop()

{

If(top==NULL)throw“下溢”;

X=top->data;p=top;

Top=top->next;

Delete p;

Return x;

}

取栈顶元素

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

判空操作

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

析构函数

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

3.14 顺序栈和链栈的比较

实现顺序栈和链栈的所有基本操作的算法都只需要常数时间,因此唯一可以比较的是空间性能。初始时顺序栈必须确定一个固定的长度,所以有存储元素个数的限制和空间浪费的问题。链栈没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一个指针域,从而产生了结构性开销。所以当栈的使用过程中元素个数变化较大时,用链栈是适宜的;反之,应该采用顺序栈。

3.2 队 列

3.2.1队列的逻辑结构

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

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

2.队列的抽象数据类型定义

ADT   Queue

         InitQueue

               前置条件:队列不存在

               输入:无

               功能:初始化队列

               输出:无

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

      DestroyQueue

               前置条件:队列已存在

               输入:无

               功能:销毁队列

               输出:无

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

     EnQueue

              前置条件:队列已存在

             输入:元素值x

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

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

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

     DeQueue

           前置条件:队列已存在

           输入:无

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

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

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

   GetQueue

           前置条件:队头已存在

           输入:无

           功能:读取队头元素

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

          后置条件:队列不变

  Empty

          前置条件:队列不存在

          输入:无

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

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

          后置条件:队列不变

endADT

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

循环队列:队列的头尾相接的顺序存储结构称为循环队列。

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

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

队空和队满的判定:队空front=rear

                            队满(rear+1%QueueSize==front

循环队列的实现

const int QueueSize=100;                           //定义存储队列元素的数组的最大长度

template<class DataType>                           //定义模板类CirQueue

class CirQueue

{

public:

CirQueue(){front=rear=QueueSize;}              //构造函数,初始化空队列

~CirQueue(){}                                  //析构函数为空

void EnQueue(DataType x);                      //入队操作,将元素x入队

DataType DeQueue();                            //出队操作,将队头元素出队

DataType GetQueue();                           //读取队头元素(并不删除)

int Empty(){front==rear?return 1:return 0;}    //判断队列是否为空

private:

DataType data[QueueSize];                     //存放队列元素的数组

int front,rear;                               //队头和队尾指针

};

(1) 构造函数

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

(2) 入队操作

template <class DataType>

void CirQueue<DataType>::EnQueue(DataType x)

{

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

rear=(rear+1)%QueueSize;                    //队尾指针在循环意义下加1

data[rear]=x;                               //在队尾处插入元素

}

(3) 出队操作

template <class DataType>

DataType CirQueue<DataType>::DeQueue()

{

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

front=(front+1)%QueueSize;                  //队头指针在循环意义下加

return data[front];                         //读取并返回出队前的队头元素

}

(4) 读取队头元素

template <class DataType>

DataType CirQueue<DataType>::GetQueue()

{

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

i=(front+1)%QueueSize;                 //注意不要给队头指针赋值

return data[i];

}

(5) 判空操作

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

3.2.3 队列的链式存储结构及实现

链队列:队列的链式存储结构称为链队列。

链队列的实现

template <class DataType>

class LinkQueue

{

public:

LinkQueue();                    //构造函数,初始化一个空的链队列

~LinkQueue();                   //析构函数,释放链队列中各结点的存储空间

void EnQueue(DataType x);       //入队操作,将元素x入队

DataType DeQueue();             //出队操作,将队头元素出队

DataType GetQueue();            //取链队列的队头元素

int Empty(){front==rear?return 1: return 0;}//判断链队列是否为空

private:

Node<DataType> *front, *rear;   //队头和队尾指针,分别指向头结点和终端结点

};

(1) 构造函数

template <class DataType>

LinkQueue<DataType>::LinkQueue()

{

Node<DataType> *s=NULL;

s=new Node<DataType>;s->next=NULL;//创建一个头结点

front=rear=s;                     //将队头指针队尾指针都指向头结点s

}

(2) 析构函数

template <class DataType>

LinkQueue<DataType>::~LinkQueue()

{

Node<DataType> *p=NULL;

while (front!=NULL)

{

p=front->next;

delete front;

front=p;

}

}

3)入队操作

template <class DataType>

void LinkQueue<DataType>::EnQueue(DataType x)

{

Node<DataType> *s=NULL;

s=new Node<DataType>;s->data=x;//申请一个数据域为x的结点s

s->next=NULL;

rear->next=s;                  //将结点s插入到队尾

rear=s;

}

4)出队操作

template <class DataType>

DataType LinkQueue<DataType>::DeQueue()

{

Node<DataType> *p=NULL;

int x;

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

p=front->next;x=p->data;//暂存队头元素

front->next=p->next;    //将队头元素所在结点摘链

if(p->next==NULL) rear=front;//判断出队前队列长度是否为1

delete p;

return x;

}

5)读取

template <class DataType>

DataType LinkQueue<DataType>::GetQueue()

{

if(front!=rear)

return front->next->data;

}

template <class DataType>::Empty()

{

if(front==rear)

return 1;

else

return 0;

}

3.3 应用举例

3.3.1 栈的应用举例——表达式求值

3.3.2栈的应用举例——火车车厢重排

思想火花——直觉可能是错误的

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值