实验2:栈和队列的基本操作实现及其应用

一、实验目的

1、   熟练掌栈和队列的结构特点,掌握栈和队列的顺序存储和链式存储结构和实现。

2、   学会使用栈和队列解决实际问题。

二、实验内容

1、自己确定结点的具体数据类型和问题规模:

分别建立一个顺序栈和链栈,实现栈的压栈和出栈操作。

分别建立一个顺序队列和链队列,实现队列的入队和出队操作。

2、设计算法并写出代码,实现一个十进制转换成二进制数。

3、选做题(*

设计一个模拟饭堂排队打饭管理软件,实现“先来先打饭”的排号叫号管理。

三、实验步骤

1、依据实验内容分别说明实验程序中用到的数据类型的定义;

2、相关操作的算法表达;

3、完整程序;

4、总结、运行结果和分析。

5、总体收获和不足,疑问等。

三、设计与编码

(一)顺序栈

1.本实验用到的理论知识

(1)栈的序号用数组的下标i表示,注意对栈操作时其下标要在范围之内。

(2)建造顺序栈入元素时,这种特殊线性表的长度不能超过数组的最大度。
2.算法设计

(1)定义SeqStack类模板

class SeqStack

{

int data[StackSize];

int top;                        //栈顶指针指向栈顶数组元素的下标

public:

SeqStack();

~SeqStack(){};

void Push(int x);

int Pop();

int GetTop();

int Empty();

};

(2)构造函数:无参构造函数建立一个空栈,并给头指针top赋值-1;定义了宏定义量StackSize,代表栈的长度为20。
(3)入栈:首先判断栈是否为满,若为满,则不能执行插入操作,否则,头指针top+1,并把需要入栈的元素放到top指向的位置。
(4)出栈:首先判断
栈是否为空,若为空,则不能执行出栈操作,否则,先把出栈的元素的值赋给新的变量并返回其值,头指针头top-1。

(5)取栈顶元素:如果栈不为空,则返回头指针所指向的栈顶元素。

(6)判断栈是否为空:若头指针top=-1,则输出栈为空。

3.代码

#include

const int StackSize=20;            //顺序栈长度为20

class SeqStack

{

int data[StackSize];

int top;                        //栈顶指针指向栈顶数组元素的下标

public:

SeqStack();

~SeqStack(){};

void Push(int x);

int Pop();

int GetTop();

int Empty();

};

SeqStack::SeqStack()

{

top=-1;

}

void SeqStack::Push(int x)              //入栈

{

if(top==StackSize-1)throw"上溢!";              //栈满

top++;

data[top]=x;

}

int SeqStack::Pop()             //出栈

{

int x;

if(top==-1)throw"下溢!";                       //栈空

x=data[top--];

return x;

}

int SeqStack::GetTop()                          //取栈顶元素

{

if(top!=-1)

return data[top];

}

int SeqStack::Empty()                           //判断栈是否为空

{

if(top==-1)return 1;

else return 0;

}

void main()

{

SeqStack S;                  //定义对象S

cout<<"此时";

if(S.Empty())

cout<<"栈为空!"<

else cout<<"栈非空!"<

cout<<"对15和10执行入栈操作!"<

//入栈

S.Push(15);

S.Push(10);

cout<<"栈顶元素为:"<

cout<

cout<<"执行一次出栈操作!"<

S.Pop();                             //出栈

cout<<"栈顶元素为:"<

cout<

}

4.运行结果:

(1)将15.10压入栈中,输出栈顶元素为15。

(2)将栈顶元素弹出(即15),后来的弹出的栈顶元素为10。

(3)如果栈为满,执行入栈操作,会抛出异常(上溢)。

(4)如果栈为空,执行出栈操作,会抛出异常(下溢)。

 

 

(二)链栈

1.本实验用到的理论知识

(1)链栈和顺序栈不一样,链栈不需事先知道栈的长度。

(2)链栈和普通链表一样:有数据域和指针域(统称结点)。

2.算法设计

(1)定义LinkStack类模板

class LinkStack

{

Node *top;     

public:

LinkStack();        //构造函数

~LinkStack(){};         

void Push(int x);            //入栈

int Pop();                      //出栈

int GetTop();                      //取栈顶元素

int Empty();                          //判断是否为空

};

(2) 构造函数:将top赋值为NULL。

(3)入栈:用new申请一个动态存储空间,利用头指针执行入栈操作。

(4)出栈:首先判断链栈是否为空(top=NULL),若为空则不能执行出栈操作,否则:先申请一个指针p,把top指向的元素(即要删除的元素)的地址赋给p,然后调用析购函数删除p,top++指向下一个元素。

(5)取栈顶元素:若栈不为空则返回(输出)栈顶元素。

(6)判断栈是否为空:若头指针top=NULL,则输出栈为空。

3.代码

#include

class Node{  

    friend class LinkStack;  //声明友元函数

private:  

int data;                   

Node *next;              //定义Node类的next指针

};  

class LinkStack

{

Node *top;     

public:

LinkStack();        //构造函数

~LinkStack(){};         

void Push(int x);            //入栈

int Pop();                      //出栈

int GetTop();                      //取栈顶元素

int Empty();                          //判断是否为空

};

LinkStack::LinkStack()

{

top=NULL;

}

void LinkStack::Push(int x)

{

Node *s;                    //链栈入栈操作

s=new Node;

s->data=x;

s->next=top;

top=s;

}

int LinkStack::Pop()

{ Node *p;

if(top==NULL)throw"下溢!";     //链栈出栈操作

int x=top->data;

p=top;

top=top->next;

delete p;

return x;

}

int LinkStack::GetTop()              //取栈顶元素

{

if(top!=NULL)

return top->data;

}

int LinkStack::Empty()                 //判断是否为空

{

if(top==NULL) return 1;     

        else return 0;

}

void main()

{

LinkStack S;          //创建s对象

cout<<"此时";

if(S.Empty())

cout<<"栈为空!"<

else cout<<"栈非空!"<

cout<<"对5,8和15执行入栈操作!"<

//入栈

S.Push(5);

S.Push(8);

S.Push(15);

cout<<"栈顶元素为:"<

cout<

cout<<"执行一次出栈操作!"<

S.Pop();                          //出栈

cout<<"栈顶元素为:"<

cout<

}

4.运行结果:

(1)将5.8.15压入栈中,输出栈顶元素为15。

(2)将栈顶元素弹出(即15),后来的弹出的栈顶元素为8。

(3)如果栈为空(top=NULL),执行出栈操作,会抛出异常(下溢)。



 

(三)顺序队列

1.本实验用到的理论知识

(1)队列有“先进先出”的特点。

(2)队列的序号用数组的下标i表示,注意对队列操作时其下标要在范围之内。

(3)建造顺序队列入元素时,这种特殊线性表的长度不能超过数组的最大度。

2.算法设计

(1)定义CirQueue类模板

class CirQueue

{

int data[QueueSize];                 //定义存放队列元素的数组

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

public:

   CirQueue();       

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

   void EnQueue(int x);

   int DeQueue();

   int GetQueue();

   int Empty();

};

(2)定义一个队头指针和一个队尾指针。

(3)构造函数:初始化空队列(front指针rear指针指向同一结点

(4)入队:首先判断队列是否为满,若为满,则不能进行入队操作,否则,让队尾指针在循环意义下加1且在队尾处插入元素

(5)出队:首先判断队列是否为空(rear==front),若为空则不能执行出队操作,否则,队头指针在循环意义下加1后读取并返回出队前的队头元素

(6)取队列顶元素:若队不为空则重新定义一个变量将队头元素输出

(7)判断栈是否为空:若头指针front==rear,则输出队列为空。

3.代码

#include

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

class CirQueue

{

int data[QueueSize];                 //定义存放队列元素的数组

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

public:

   CirQueue();       

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

   void EnQueue(int x);

   int DeQueue();

   int GetQueue();

   int Empty();

};

CirQueue::CirQueue()                  //析构函数,初始化空队列

{

front=rear=QueueSize-1;

}

void CirQueue::EnQueue(int x)     //入队操作,将x元素入队

{

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

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

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

}

int CirQueue::DeQueue()                         //出队操作,将队头元素出队

{

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

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

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

}

int CirQueue::GetQueue()            //取队头元素(并不删除)

{

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

int i=(front+1)%QueueSize;              //重新定义一个变量将队头元素输出

return data[i];

}

int CirQueue::Empty()              //判断队列是否为空

{

if(front==rear)return 1;

else return 0;

}

void main()

{

CirQueue S;             //定义对象

cout<<"此时";

if(S.Empty())                 //判断队列是否为空

cout<<"队列为空!"<

else cout<<"队列非空!"<

cout<<"对5,8和15执行入队操作!"<

//执行入队操作

S.EnQueue(5);

S.EnQueue(8);

S.EnQueue(15);

cout<<"队头元素为:"<

cout<

cout<<"执行一次出队操作!"<

S.DeQueue();                 //执行出队操作

cout<<"队头元素为:"<

cout<

}

4.运行结果:

(1)将5.8.15传入队列中,输出队列顶元素为15。

(2)将队列头元素弹出(即15),后来的弹出的队头元素为8。

(3)如果队列为满((rear+1)%QueueSize==front),执行出队操作时,会抛出异常(上溢)。

(4)如果队列为空(front=rear),执行出队操作时,会抛出异常(下溢)。

 

 

(四)链队列

1.本实验用到的理论知识

(1)链队列和顺序队列不一样,链队列不需事先知道队列的长度。

(2)链队列有头指针和尾指针,方便执行插入和删除操作。

2.算法设计

(1)定义LinQueue类模板

class LinkQueue

{

Node *front,*rear;                  //队头和队尾指针

public:

   LinkQueue();       

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

   void EnQueue(int x);

   int DeQueue();

   int GetQueue();

   int Empty();

};

(2)构造函数:创建一个头结点,再初始化初始化空队列,将队头指针和队尾指针都指向头结点。

(3)入栈:用new申请一个动态存储空间,利用尾指针把需要入队的元素插到队尾。

(4)出栈:首先判断链栈是否为空(top=NULL),若为空则不能执行出栈操作,否则:先申请一个变量暂存队头元素将队头元素所在的结点摘链,判断出队前队列指针长度是否为1,若为1,则让队尾指针与队头指针指向的位置一样,即队列为空。

(5)取队头元素:若队列不为空则返回(输出)队列头元素。

(6)判断队列是否为空:若front=rear,则输出队列为空。

3.代码

#include

class Node{  

    friend class LinkQueue;  //声明友元函数

private:  

  int data;

    Node *next;  //定义Node类的next指针                         

};  

class LinkQueue

{

Node *front,*rear;                  //队头和队尾指针

public:

   LinkQueue();       

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

   void EnQueue(int x);

   int DeQueue();

   int GetQueue();

   int Empty();

};

LinkQueue::LinkQueue()                  //析构函数,初始化空队列

{

Node *s=new Node;             //创建一个头结点s

s->next=NULL;

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

}

void LinkQueue::EnQueue(int x)     //入队操作,将x元素入队

{    

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

s->next=NULL;

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

rear=s;        

}

int LinkQueue::DeQueue()                         //出队操作,将队头元素出队

{

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

Node *p=front->next;

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

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

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

delete p;

return x;

}

int LinkQueue::GetQueue()            //取队头元素(并不删除)

{

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

return front->next->data;

}

int LinkQueue::Empty()              //判断队列是否为空

{

if(front==rear)return 1;

else return 0;

}

void main()

{

LinkQueue S;             //定义对象

cout<<"此时";

if(S.Empty())                 //判断队列是否为空

cout<<"队列为空!"<

else cout<<"队列非空!"<

cout<<"对2,6,15和23执行入队操作!"<

//执行入队操作

S.EnQueue(2);

S.EnQueue(6);

S.EnQueue(15);

S.EnQueue(23);

if(S.Empty())

{

cout<

}

cout<<"队头元素为:"<

cout<

cout<<"执行一次出队操作!"<

S.DeQueue();                 //执行出队操作

cout<<"队头元素为:"<

cout<

4.运行结果:

(1)将5.8.15传入队列中,输出队列顶元素为15。

(2)将队列头元素弹出(即15),后来的弹出的队头元素为8。

(3)如果队列为空(front=rear),执行出队操作,会抛出异常(下溢)

 

(五)十进制转换为二进制

1.本实验用到的理论知识

(1)利用顺序栈“先进后出”的特点把十进制转换为二进制的数正确输出。

2.算法设计

(1)定义SeqStack类模板

#include

const int StackSize=20;            //顺序栈长度为20

class SeqStack

{

int data[StackSize];

int top;                        //栈顶指针指向栈顶数组元素的下标

public:

SeqStack();

~SeqStack(){};

void Push(int x);

int Pop();

int GetTop();

int Empty();

void Transform(int y);

};

(3)构造函数:无参构造函数建立一个空栈,并给头指针赋值-1;定义了宏定义量StackSize,代表栈的长度为20。
(4)入栈:首先判断栈是否为满,若为满,则不能执行插入操作,否则,头指针top+1,并把需要入栈的元素放到top指向的位置。
(5)出栈:首先判断
栈是否为空,若为空,则不能执行出栈操作,否则,先把出栈的元素的值赋给新的变量并返回其值,头指针头top-1。

(6)取栈顶元素:如果栈不为空,则返回头指针所指向的栈顶元素。

(7)判断栈是否为空:若头指针top=-1,则输出栈为空。

3.代码

#include

const int StackSize=20;            //顺序栈长度为20

class SeqStack

{

int data[StackSize];

int top;                        //栈顶指针指向栈顶数组元素的下标

public:

SeqStack();

~SeqStack(){};

void Push(int x);

int Pop();

int GetTop();

int Empty();

void Transform(int y);

};

SeqStack::SeqStack()

{

top=-1;

}

void SeqStack::Push(int x)             //入栈

{

if(top==StackSize-1)throw"上溢!";              //栈满

top++;

data[top]=x;

}

int SeqStack::Pop()             //出栈

{

int x;

if(top==-1)throw"下溢!";                       //栈空

x=data[top--];

return x;

}

int SeqStack::GetTop()                          //取栈顶元素

{

if(top!=-1)

return data[top];

}

int SeqStack::Empty()                           //判断栈是否为空

{

if(top==-1)return 1;

else return 0;

}

void SeqStack::Transform(int y)              //执行将十进制转换为二进制

{

do

{

int n=y%2;          //取余

y=y/2;                   //取整                                      

Push(n);                      //入栈,利用栈“先进后出”的特点

}while(y!=0);

while(!Empty())              //栈不为空时,输出的栈中所有元素

        {  

            cout<

    }  

}

void main()

{

SeqStack S;    //定义对象

int y;

cout<<"请输入需要转换为十进制的数字:";

cin>>y;

cout<<"转换为二进制的值为:";

S.Transform(y);

cout<

}

五、总结与心得

    通过这次实验复习了栈和队列的大部分知识,但是链栈和链队列的插入删除操作不是很熟练。


你可能感兴趣的:(实验2:栈和队列的基本操作实现及其应用)