这个作业属于哪个班级 | 数据结构--网络2011/2012 |
---|---|
这个作业的地址 | DS博客作业02--栈和队列 |
这个作业的目标 | 学习栈和队列的结构设计及运算操作 |
姓名 | 郑俊佳 |
0.PTA得分截图
1.本周学习总结(0-5分)
1.1 栈
画一个栈的图形,介绍如下内容。
栈的定义:栈是一种只能在一端进行插入或删除操作的线性表。栈又称为后进先出的线性表,其中有几个名词:栈顶、栈底、空栈。
栈顶:允许插入和删除的一端。
栈底:不允许插入和删除的一端。
空栈:表中没有元素。
进栈出栈规则:
栈顶出栈->栈底最后出栈;
时进时出->元素未完全进栈时,即可出栈。
顺序栈的结构、操作函数
顺序栈定义结构体:
typedef struct
{
ElemType data[MaxSize]; //存放栈中的数据元素
int top; //栈顶指针,即存放栈顶元素在data数组中的下标
}SqStack; //顺序栈的类型
初始化顺序栈:
void InitStack(SqStack *&s)
{
s=new SqStack; //分配一个顺序栈空间,首地址存放在s中
s->top=-1; //栈顶指针置为-1,即栈空
}
销毁顺序栈:
void DestroyStack(SqStack *&s)
{
free(s);
}
判断顺序栈是否为空:
bool StackEmpty(SqStack * s)
{
return(s->top==-1);
}
元素进入顺序栈:
bool Push(SqStack *&s,ElemType e)
{
if(s->top==MaxSize-1) //栈满情况,即栈上溢出
return false;
s->top++; //栈顶指针增1
s->data[s->top]=e; //元素e放在栈顶指针处
return true;
}
元素出顺序栈:
bool Pop(SqStack *&s,ElemType &e)
{
if(s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top]; //取出栈顶元素
s->top--; //栈顶指针减1
return true;
}
取顺序栈中栈顶元素:
bool GetTop(SqStack *&s,ElemType &e)
{
if(s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top]; //取栈顶元素
return true;
}
共享栈:合并两个栈,用一个数组实现两个栈。
共享栈四要素:
栈空条件:栈1空为top1==-1;栈2空为top2==MaxSize。
栈满条件:top1==top2-1;
元素x进栈操作:进栈1操作为top1++;data[top1]=x;进栈2操作为top2--;data[top2]=x。
出栈x操作:出栈1操作为x=data[top1];top1--;出栈2操作为x=data[top2];top2++。
共享栈结构体:
typedef struct
{
ElemType data[MaxSize]; //存放共享栈中的元素
int top1,top2; //两个栈的栈顶指针
}DStack; //共享栈的类型
链栈的结构、操作函数
链栈的结构体:
typedef struct linknode
{
ElemType data; //数据域
struct linknode *next; //指针域
}LinkStNode; //链栈结点类型
初始化链栈:
void InitStack(LinkStNode *&s)
{
s=new LinkStNode;
s->next=NULL; //栈空
}
销毁链栈:
void DestroyStack(LinkStNode *&s)
{
LinkStNode * pre=s,*p=s->next; //pre指向头结点,p指向首结点
while(p!=NULL) //循环到p为空
{
free(pre); //释放pre结点
pre=p; //pre、p同步后移
p=pre->next;
}
free(pre); //此时pre指向尾结点,释放其空间
}
判断链栈是否为空:
bool StackEmpty(LinkStNode *s)
{
return (s->next=NULL);
}
元素进入链栈:
void Push(LinkStNode *&s,ElemType e)
{
LinkStNode *p;
p=new LinkStNode; //新建结点p
p->data=e; //存放元素e
p->next=s->next; //将p结点插入作为首结点
s->next=p;
}
元素出链栈:
bool Pop(LinkStNode *&s,ElemType &e)
{
LinkStNode * p;
if(s->next==NULL) //栈空情况
return false;
p=s->next; //p指向首结点
e=p->data; //提取首结点值
s->next=p->next; //删除首结点
free(p); //释放被删除结点的存储空间
return true;
}
取链栈栈顶元素:
bool GetTop(LinkStNode *&s,ElemType &e)
{
if(s->next==NULL) //栈空情况
return false;
e=s->next->data; //提取其首结点值
return true;
}
1.2 栈的应用
问题:
exp="1+2(4+12)";
做法:
1.转后缀表达式
2.后缀表达式求值
中缀表达式:运算符号位于两个运算数之间。如:a+bc-d/e
后缀表达式:运算符号位于两个运算数之后。如:abc*+de/-
将算式exp转化成后缀表达式postexp:
void trans(char * exp,char postexp[])
{
cahr e;
SqStack * Optr;
InitStack(Optr);
int i=0;
while(*exp!='\0')
{
switch(*exp)
{
case '(':
Push(Optr,'(');
exp++;
break;
case ')':
Pop(Optr,e);
while(e!='(')
{
postexp[i++]=e;
Pop(Optr,e);
}
exp++;
break;
case '+':
case '-':
while(!StackEmpty(Optr))
{
GetTop(Optr,e);
if(e!='(')
{
postexp[i++]=e;
Pop(Optr,e);
}
else
break;
}
Push(Optr,*exp);
exp++;
break;
case '*':
case '/':
while(!StackEmpty(Optr))
{
GetTop(Optr,e);
if(e=='*'||e=='/')
{
postexp[i++]=e;
Pop(Optr,e);
}
else
break;
}
Push(Optr,*exp);
exp++;
break;
default:
while(*exp>='0'&&*exp<='9')
{
postexp[i++]=*exp;
exp++;
}
postexp[i++]='#';
}
}
while(!StackEmpty(Optr))
{
Pop(Optr,e);
postexp[i++]=e;
}
postexp[i]='\0';
DestroyStack(Optr);
}
1.3 队列
画一个队列的图形,介绍如下内容。
顺序队列的结构、操作函数
顺序队列的结构体:
typedef struct
{
ElemType data[MaxSize]; //存放队中的元素
int front,rear; //队头和队尾指针
}SqQueue; //顺序队类型
初始化顺序队列:
{
q=new SqQueue;
q->front=q->rear=-1;
}
销毁顺序队列:
void DestroyQueue(SqQueue *&q)
{
free(q);
}
判断顺序队列是否为空:
bool QueueEmpty(SqQueue *q)
{
return (q->front==q->rear);
}
元素进入顺序队列:
bool enQueue(SqQueue *&q,ElemType e)
{
if(q->rear==MaxSize-1) //队列满上溢出
return false;
q->rear++; //队尾增1
q->data[q->rear]=e; //rear位置插入元素e
return true;
}
元素出顺序队列:
bool deQueue(SqQueue *&q,ElemType &e)
{
if(q->front==q->rear) //队列空下溢出
return false;
q->front++; //队头增1
e=q->data[q->front]; //front位置出队列
return true;
}
环形队列的结构、操作函数
初始化环形队列:
void InitQueue(SqQueue *&q)
{
q=new SqQueue;
q->front=q->rear=0;
}
销毁环形队列:
void DestroyQueue(SqQueue *&q)
{
free(q);
}
判断队列是否为空:
bool QueueEmpty(SqQueue *q)
{
return (q->front==q->rear);
}
元素进入环形队列:
bool enQueue(SqQueue *&q,ElemType e)
{
if((q->rear+1)%MaxSize==q->front) //队列满上溢出
return false;
q->rear=(q->rear+1)%MaxSize;
q->data[q->rear]=e;
return true;
}
元素出环形队列:
bool deQueue(SqQueue *&q,ElemType &e)
{
if(q->front==q->rear) //队列空下溢出
return false;
q->front=(q->front+1)%MaxSize;
e=q->data[q->front];
return true;
}
链队列的结构、操作函数
链队列的结构体:
typedef struct qnode
{
ElemType data; //存放元素
struct qnode *next;//下一个结点指针
}DataNode; //链队数据结点的类型
链队头结点类型LinkQuNode:
typedef struct
{
DataNode *front; //指向队首结点
DataNode *rear; //指向对尾结点
}LinkQuNode; //链队结点的类型
初始化链队:
void InitQueue(LinkQuNode *&q)
{
q=new LinkQuNode;
q->front=q->rear=NULL;
}
销毁链队:
void DestroyQueue(LinkQuNode *&q)
{
DataNode *pre=q->front,*p; //pre指向队首结点
if(pre!=NULL)
{
p=pre->next; //p指向结点pre的后续结点
while(p!=NULL) //p不为空时循环
{
free(pre); //释放pre结点
pre=p; //pre后移
p=p->next; //p后移
}
free(pre); //释放最后一个数据结点
}
free(q); //释放链队结点
}
判断链队是否为空:
bool QueueEmpty(LinkQuNode *q)
{
return (q->rear==NULL);
}
元素进入链队:
void enQueue(LinkQuNode *&q,ElemType e)
{
DataNode *p;
p=new DataNode; //创建新结点
p->data=e;
p->next=NULL;
if(q->rear==NULL) //若链队为空,则新结点既是队首结点又是对尾结点
q->front=q->rear=p;
else //若链队不空
{
q->rear->next=p; //将结点p链到对尾,并将rear指向它
q->rear=p;
}
}
元素出链队:
bool deQueue(LinkQuNode *&q,ElemType &e)
{
DataNode *t;
if(q->rear==NULL) //原来队列为空
return false;
t=q->front; //t指向首结点
if(q->front==q->rear) //原来队列只有一个数据结点时
q->front=q->rear=NULL;
else //原来队列中有两个或两个以上结点时
q->front=q->front->next;
e=t->data;
free(t);
return true;
}
队列应用,要有具体代码操作。
2.PTA实验作业(4分)
此处请放置下面2题代码所在码云地址(markdown插入代码所在的链接)。如何上传VS代码到码云
2.1 符号配对
2.1.1 解题思路及伪代码
解题思路:定义flag进行判断操作,输入左符号时入栈,输入右符号时并且判断栈里面是否有元素,若无则为一种情况,若有则进行配对,判断是否是该右符号对应的左符号,用flag标记对应的情况。
伪代码:
int flag=0;
for (遍历条件)
{
if (为左符号)
{
入栈;
}
else if (栈为空且有右符号)
{
flag = 1;
break;
}
else if (各自左符号与右符号配对情况)
{
出栈;
}
}
if (flag == 1)
{
右符号剩余;
}
else if (栈为空)
{
匹配;
}
else
{
正常情况的不匹配;
}
2.1.2 总结解题所用的知识点
-
- 宏定义,结构体,函数分装等
-
- 申请空间用malloc动态申请。
-
- 使用了链的存储功能,并且还使用了静态字符数组定义。
2.2 银行业务队列简单模拟
2.2.1 解题思路及伪代码
解题思路:
先判断编号的奇偶,若为奇数进A队列,若为偶数进B队列,再分别计算A队列和B队列的元素个数,后判断A无元素和只有1个元素的特殊情况,两种情况下再判断B的个数,之后普通情况,另A的元素个数除以2,因为2人为一组,1组输出2个编号后B输出1个编号,但要考虑到A的元素个数为奇数个,故要添加判断,若其为奇数最后一组输出1个。
伪代码:
for (遍历条件)
{
if (编号为奇数)
{
进A;
}
else
{
进B;
}
}
统计A和B的个数
if (A个数为0)
{
全部输出B元素;
}
else if (A元素个数为1)
{
输出A;
全部输出B;
}
else
{
int i = A个数 / 2;
for (n = 1; n <= i; n++)
{
if (n < i)
{
输出A2个元素;
}
else if (n == i && A个数为奇数)
{
输出A1个元元素;
}
else if (n == i && A个数为偶数)
{
输出A2个元素;
}
if (B还有元素)
{
输出B1个元素;
}
}
}
2.2.2 总结解题所用的知识点
-
- queue相关函数的使用
-
- 队列优先输出的顺序
-
- 本题需要考虑A对列的特殊情况,考虑其个数以及奇偶性。
3.阅读代码(0--1分)
找1份优秀代码,理解代码功能,并讲出你所选代码优点及可以学习地方。主要找以下类型代码:
考研题
ACM题解
leecode--栈
leecode--队列
注意:不能选教师布置在PTA的题目。完成内容如下。
3.1 题目及解题代码
可截图,或复制代码,需要用代码符号渲染。
3.2 该题的设计思路及伪代码
链表题目,请用图形方式展示解决方法。同时分析该题的算法时间复杂度和空间复杂度。