第四次作业 实验二栈和队列

| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/qdu/DS2020 | |
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/qdu/DS2020/homework/11296 | ---- |
| 这个作业的目标 | ①掌握栈的结构特性及其入栈,出栈操作②掌握队列的结构特性及其入队、出队的操作,掌握循环队列的特点及其操作 | |

一、实验目的
1、掌握栈的结构特性及其入栈,出栈操作;
2、掌握队列的结构特性及其入队、出队的操作,掌握循环队列的特点及其操作。

二、实验预习
说明以下概念
1、顺序栈:
由于栈是运算受限的线性表,因此线性表的存储结构对栈也适用。栈的顺序存储结构简称为顺序栈,它是运算受限的顺序表。
类似于顺序表的定义,顺序栈也可用向量来实现。因为栈底位置是固定不变的,所以可以将栈底位置设置在向量两端的任意一个端点;栈顶位置是随着进栈和退栈操作而变化的,故需用一个整型量top来指示当前栈顶位置,通常称top为栈顶指针。

2、链栈:
栈的链式存储结构称为链栈。它是运算受限的单链表,其插入和删除操作仅限制在表头位置上进行。由于只能在链表头部进行操作,故链栈没有必要像单链表那样需要附加头结点。栈顶指针就是链表的头指针。

3、循环队列:
循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队列运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。

4、链队
队列的链式存储结构简称为链队列,它是限制仅在表头删除和表尾插入的单链表。
显然仅有单链表的头指针不便于在表尾做插入操作,为此再增加一个尾指针,指向链表上的最后一个结点。于是,一个链队列由一个头指针和一个尾指针唯一地确定。

三、实验内容和要求
1、阅读下面程序,将函数Push和函数Pop补充完整。要求输入元素序列1 2 3 4 5 e,运行结果如下所示。

#include<stdio.h>
#include<malloc.h>
#define ERROR 0
#define OK 1
#define STACK_INT_SIZE 10  /*存储空间初始分配量*/
#define STACKINCREMENT 5  /*存储空间分配增量*/
typedef  int ElemType; /*定义元素的类型*/
typedef struct{
    ElemType *base;
    ElemType *top;
    int stacksize;     /*当前已分配的存储空间*/
}SqStack;

int InitStack(SqStack *S);   /*构造空栈*/
int push(SqStack *S,ElemType e); /*入栈*/
int Pop(SqStack *S,ElemType *e);  /*出栈*/
int CreateStack(SqStack *S);     /*创建栈*/
void PrintStack(SqStack *S);   /*出栈并输出栈中元素*/

int InitStack(SqStack *S){
    S->base=(ElemType *)malloc(STACK_INT_SIZE *sizeof(ElemType));
    if(!S->base) return ERROR;
    S->top=S->base;
    S->stacksize=STACK_INT_SIZE;
    return OK;
}/*InitStack*/

int Push(SqStack *S,ElemType e){
    
}/*Push*/

int Pop(SqStack *S,ElemType *e){
   
}/*Pop*/

int CreateStack(SqStack *S){
    int e;
    if(InitStack(S))
        printf("Init Success!\n");
    else{
        printf("Init Fail!\n");
        return ERROR;
    }
    printf("input data:(Terminated by inputing a character)\n");
    while(scanf("%d",&e))
        Push(S,e);
    return OK;
}/*CreateStack*/

void PrintStack(SqStack *S){
    ElemType e;
    while(Pop(S,&e))
        printf("%3d",e);
}/*Pop_and_Print*/

int main(){
    SqStack ss;
    printf("\n1-createStack\n");
    CreateStack(&ss);
    printf("\n2-Pop&Print\n");
    PrintStack(&ss);
    return 0;
}   	

算法分析:输入元素序列1 2 3 4 5,为什么输出序列为5 4 3 2 1?体现了栈的什么特性?
体现了栈是只允许在表的一端进行操作的线性表且具有先进后出的特征。因为当main函数调用PrintStack(&ss)时,程序转到函数中,而在该函数体内,又调用了int Pop(SqStack *S,ElemType *e),此函数的功能是栈S的栈顶元素退栈并返回其值。所以输入元素序列1 2 3 4 5,输出序列为5 4 3 2 1。这体现了栈是只允许在表的一端进行操作的线性表且具有先进后出的特征

2、在第1题的程序中,编写一个十进制转换为二进制的数制转换算法函数(要求利用栈来实现),并验证其正确性。
实现代码

ElemType n,h;
	int m=0,k=0;
	InitStack(S);
	printf("Input element\n");
	scanf("%d",&n);
	while(n){
		m++;
		Push(S,n%2);
		n=n/2;
	}
	while(k<m){
		k++;
		Pop(S,&h);
		printf("%d",h);
	}
}

int main(){
	SqStack S;
	conveshen(&S);
	printf("\n");
	return ERROR;
}

验证:

3、阅读并运行程序,并分析程序功能。

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define M 20
#define  elemtype  char
typedef struct
{
    elemtype stack[M];
    int top;
}
stacknode;
void init(stacknode *st);
void push(stacknode *st,elemtype x);
void pop(stacknode *st);

void init(stacknode *st)
{
    st->top=0;
}

void push(stacknode *st,elemtype x)
{
    if(st->top==M)
        printf("the stack is overflow!\n");
    else
    {
        st->top=st->top+1;
        st->stack[st->top]=x;
    }
}

void pop(stacknode *st)
{
if(st->top>0)  st->top--;
    else  printf(“Stack is Empty!\n”);
}

int main()
{
    char s[M];
    int i;
    stacknode *sp;
    printf("create a empty stack!\n");
    sp=malloc(sizeof(stacknode));
    init(sp);
    printf("input a expression:\n");
    gets(s);
    for(i=0;i<strlen(s);i++)
    {
        if(s[i]=='(')
            push(sp,s[i]);
        if(s[i]==')')
            pop(sp);
    }
    if(sp->top==0)
        printf("'('match')'!\n");
    else
        printf("'('not match')'!\n");
    return 0;
}

输入:2+((c-d)6-(f-7)a)/6
运行结果:

输入:a-((c-d)*6-(s/3-x)/2
运行结果:

程序的基本功能:
判断多项式的左右括号是否配对

以下为选做实验:
4、设计算法,将一个表达式转换为后缀表达式,并按照后缀表达式进行计算,得出表达式得结果。
实现代码

//中缀表达式转后缀
#include<iostream>
#include<string>
#include<stack>
using namespace std;

int prio(char op) {                 //给运算符优先级排序
	int priority;
	if (op == '*' || op == '/')
		priority = 2;
	if (op == '+' || op == '-')
		priority = 1;
	if (op == '(')
		priority = 0;
	return priority;
}
bool Trans(string &str,string &str1) {   //引用传递
	stack<char> s;                   //定义一个char类型的栈s
	int i;
	for (i = 0; i<str.size(); i++) {
		if (str[i] >= '0' && str[i] <= '9') {    //如果是数字,直接入栈
			str1+=str[i];
		}
		else {                        //否则不是数字
			if (s.empty())            //栈空则入站
				s.push(str[i]);
			else if (str[i] == '(')   //左括号入栈
				s.push(str[i]);
			else if (str[i] == ')') {  //如果是右括号,只要栈顶不是左括号,就弹出并输出
				while (s.top() != '(') {  
					str1+= s.top();
					s.pop();
				}
				s.pop();                 //弹出左括号,但不输出
			}
			else {
				while (prio(str[i]) <= prio(s.top())) { //栈顶优先级大于等于当前运算符,则输出
					str1+= s.top();
					s.pop();
					if (s.empty())      //栈为空,停止
						break;
				}
				s.push(str[i]);   //把当前运算符入栈
			}
		}
	}
	while (!s.empty()) {      //最后,如果栈不空,则弹出所有元素并输出
		str1+= s.top();
		s.pop();
	}
	return true;
}
int main() {                //主程序
	string infix;
	string postfix;
	cout << "请输入中缀表达式:" << infix << endl;
	cin >> infix;
	Trans(infix,postfix);
	cout << "后缀表达式为:" << postfix << endl;
	return 1;
}

5、假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾结点(不设队头指针),试编写相应的置空队列、入队列、出队列的算法。
实现代码:

#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1
#define OVERFLOW 0

typedef int qelemType;

typedef struct queue
{
	qelemType data;
	struct queue *next;
}queue,*linkqueue;
typedef struct
{
	linkqueue rear;
	int length;
}sqqueue;

void initQueue(sqqueue &queue)//置空队列
{
	queue.rear=(linkqueue)malloc(sizeof(queue));
	queue.rear->next=queue.rear;
}

int emptyQueue(sqqueue &queue)//判队列是否为空
{
	if(queue.rear->next==queue.rear)
		return OK;
	else
		return 0;
}

int enqueue(sqqueue &queue,qelemType e)
{
	linkqueue p;
	p=(linkqueue)malloc(sizeof(queue));
	if(!p)
		return OVERFLOW;
	p->data=e;
	p->next=queue.rear->next;
	queue.rear->next=p;
	queue.rear=p;
	return OK;
}

int delqueue(sqqueue &queue,qelemType &e)
{
	linkqueue p;
	if(queue.rear->next==queue.rear)
		return ERROR;//若队列为空返回0
	p=queue.rear->next->next;//循环链表队列队尾指针下一结点(也即头结点)的下一结点(即队头指针)
	e=p->data;
	queue.rear->next->next=p->next;
	free(p);
	//delete(p);//free函数与delete函数均可使用
	return OK;
}

int main()
{
	sqqueue queue2;
	qelemType num;
	initQueue(queue2);
	if(emptyQueue(queue2))
		printf("该队列目前为空!\n");
	else
		printf("该队列不为空!\n");
	for(int i=1;i<=10;i++)![](https://img2020.cnblogs.com/blog/2147598/202010/2147598-20201018185026543-2068855702.png)


		if(enqueue(queue2,i))
			printf("元素%d成功入列!\n",i);
	printf("\n\n");
	for(int j=1;j<=9;j++)
		if(delqueue(queue2,num))
			printf("元素%d成功出列!\n",num);
	if(emptyQueue(queue2))
		printf("该队列目前为空!\n");
	else
		printf("该队列不为空!\n");
	return 0;
}

四、实验小结
更好地掌握了栈的结构特性及其入栈,出栈操作,队列的结构特性及其入队、出队的操作,循环队列的特点及其操作;
对栈和队列有了更深的理解,对程序代码的实现有了一个更为全面深刻的认识。

posted @ 2020-10-18 18:38  懵柠未迟  阅读(693)  评论(0)    收藏  举报