DS博客作业02--栈和队列
| 这个作业属于哪个班级 | 数据结构--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | DS博客作业02--栈和队列 |
| 这个作业的目标 | 学习栈和队列的结构设计及运算操作 |
| 黄帅 | |
0.PTA得分截图
1.本周学习总结(0-5分)
1.1 栈
栈的代码定义
typedef struct {
ElemType data[MaxSize];//存放元素
int top=-1;//栈顶指针,下标
}SqStack;//顺序栈的类型
进栈
bool Push(SqStack &s,ElemType e)
{
if(s->top == MAXSIZE - 1) //判断是否栈满
{
return false;
}
s->data[s->top++] = e; //入栈
return true;
}
出栈
bool Pop(SqStack &s,ElemType e)
{
if(StackEmpty(s)) //判断是否为空栈
{
return false;
}
e = s->data[s->top--]; //退栈
return true;
}
取栈顶元素
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1) //判断栈空
return false;
e=s->data[s->top];//栈顶元素赋值为e
return true;
}
判断栈空
bool StackEmpty(SqStack s)
{
if(s->top == -1) //栈为空返回true
{
return true;
}
return false;
}
判断栈满
int FullStack(SqStack s)
{
if (s->top == MaxSize-1)
return true;
else
return false;
}
销毁栈
void DestroyStack(SqStack s)
{
delete s;
}
链栈的结构、操作函数
定义
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}Node,*Stack;
初始化
bool InitStack(Stack &s)
{
s = NULL;
return true;
}
进栈
void Push(Stack& s, ElemType e)
{
Stack p;
p = new Node;
p->data = e; //新建节点p
p->next = s->next; //插入*p节点作为开始节点
s->next = p;
}
出栈
bool Pop(Stack& s, ElemType& e)
{
Stack p;
if (StackEmpty(s)) //栈空的情况
return false;
p = s->next; //p指向开始节点,从栈顶开始出栈
e = p->data;
s->next = p->next; //删除*p节点
delete p; //释放*p节点
return true;
}
取栈顶元素
bool GetTop(SqStack &s,ElemType e)
{
if(StackEmpty(s)) //判断是否为空栈
{
return false;
}
e = s->data; //取栈顶
return true;
}
判断栈空
bool StackEmpty(Stack *s)
{
if(s == NULL)
{
return true;
}
return false;
}
销毁栈
void DestroyStack(Stack &s)
{
Stack p;
while (s!=NULL)
{ p=s;
s=s->next;
delete p;
}
}
1.2 栈的应用
表达式
中缀表达式:运算符在操作数中间
后缀表达式:运算符在操作数之后
中缀表达式转为后缀表达式:
建立一个栈用于存放运算符,每个运算符号进栈时都要比较一下其和栈顶的的符号优先级大小
优先级比栈顶运算符高的入栈
优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出
1.3 队列
画一个队列的图形,介绍如下内容。
定义
typedef struct
{ ElemType data[MaxSize];
int front,rear; //队首和队尾指针
}Queue;
typedef Queue *SqQueue;
基本操作:
初始化
void InitQueue(SqQueue &q)
{ q=new Queue;
q->front=q->rear=-1;
}
判断栈空
bool QueueEmpty(SqQueue q)
{
return(q->front==q->rear);
}
判断栈满
bool QueueFULL(SqQueue q)
{
return(q->rear==MaxSize-1);
}
进队
bool enQueue(SqQueue &q,ElemType e)
{
if (q->rear+1==MaxSize) return false;
//队满上溢出
q->rear=q->rear+1;
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;
e=q->data[q->front];
return true;
}
销毁队列
void DestroyQueue(SqQueue &q)
{
delete q;
}
环形队列的结构、操作函数
结构
typedef struct
{ElemType data[MaxSize] ;//存放队中元素
int front, rear;//队头和队尾指针
}SqQueue;
初始化
void InitQueue( SqQueue * &.q)
{ q= (SqQueue * )malloc( sizeof(SqQueue));
q-> front=q-> rear=0;
}
入队列
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;
}
队空
void QueueEmpty(SqQueue * &q)
{
return(q-> front==q-> rear);
}
销毁
void DestroyQueue(SqQueue * &q)
{
free(q);
}
链队列的结构、操作函数
结构
typedef struct qnode
{ElemType data;//存放元素
struct qnode * next;//下一个结点指针
} DatalNode;//链队数据结点的类
初始化
void InitQueue( LinkQuNde * &.q)
{ q= (LinkQuNde * )malloc( sizeof(LinkQuNde));
q-> front=q-> rear=NULL;
}
入队列
void enQueue(LinkQuNode * &q, ElemType e)
{
DataNode*p;
p= (DataNode * )malloc( sizeof( 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;
队空
bool QueueEmpty(LinkQueue * &q)
{
return(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;P=P- > next;//pre、p同步后移
}
free(pre);//释放最后一个数据结点
}
free(q);//释放链队结点
队列应用
6-4 另类循环队列
只设队列头指针Front,不设尾指针Rear,而是另设Count记录队列中元素个数。编写算法实现队列的入队和出队操作。
ElementType DeleteQ(Queue Q)
{
if (Q->Count == 0)
{
printf("Queue Empty\n");
return ERROR;
}
Q->Count--;
ElementType X;
X= Q->Data[Q->Front];
Q->Front = (Q->Front + 1) % Q->MaxSize;
return X;
}
bool AddQ(Queue Q, ElementType X)
{
if (Q->Count == Q->MaxSize)
{
printf("Queue Full\n");
return false;
}
Q->Data[(Q->Front + Q->Count) % Q->MaxSize] = X;
Q->Count++;
return true;
}
2.PTA实验作业(4分)
此处请放置下面2题代码所在码云地址(markdown插入代码所在的链接)。如何上传VS代码到码云
2.1 符号配对
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main()
{
stack <char>str;
int i = 0, k = 0, count = 0;
char sum[100];
char select[100];
while (sum[k] = getchar())
{
if (sum[k] == '(' || sum[k] == '{' || sum[k] == '[' || sum[k] == ')' || sum[k] == ']' || sum[k] == '}')
{
select[i++] = sum[k];
count++;
}
else
{
if (sum[k] == '/')
{
sum[++k] = getchar();
if (sum[k] == '*')
{
select[i++] = '<';
count++;
}
}
else if (sum[k] == '*')
{
sum[++k] = getchar();
if (sum[k] == '/')
{
select[i++] = '>';
count++;
}
}
}
if (sum[k] == '.')
{
sum[++k] = getchar();
if (sum[k] == '\n')
break;
}
k++;
}
for (i = 0; i < count; i++)
{
if (select[i] == '(' || select[i] == '[' || select[i] == '{' || select[i] == '<')
{
str.push(select[i]);
}
else
{
if (select[i] == ')' || select[i] == ']' || select[i] == '}' || select[i] == '>')
{
if (str.empty())break;
if ((select[i] == ')' && str.top() == '(') || (select[i] == ']' && str.top() == '[') || (select[i] == '}' && str.top() == '{') || (select[i] == '>' && str.top() == '<'))
str.pop();
else
break;
}
}
}
if (str.empty() && i == count)
cout << "YES";
else
{
cout << "NO" << endl;
if (str.empty())
{
if (select[i] == '<')
cout << "/*-?";
else if (select[i] == '>')
cout << "?-*/";
else if (select[i] == '(' || select[i] == '[' || select[i] == '{')
cout << select[i] << "-?";
else
cout << "?-" << select[i];
}
else
{
if (str.top() == '<')
cout << "/*-?";
else if (str.top() == '>')
cout << "?-*/";
else if (str.top() == '(' || str.top() == '[' || str.top() == '{')
cout << str.top() << "-?";
else
cout << "?-" << str.top();
}
}
return 0;
}
2.1.1 解题思路及伪代码
思路:
把各种题目要求的符号都存入一个数组中,其中/* ,*/符号的处理是,判断后以‘<’,‘>’的形式存入数组
再利用for循环遍历数组依次入栈,若能配对则出栈,不能则break
最后再判断要输出的内容
stack <char>str
int i = 0, k = 0, count = 0
char sum[100]
char select[100]
while (sum[k] = getchar())
if sum[k] == '(' '{' '[' ')' ']' '}'
select[i++] = sum[k]
count++
end if
else
if sum[k] == '/'
sum[++k] = getchar()
if sum[k] == '*'
select[i++] = '<'
count++
end if
end if
else if sum[k] == '*'
sum[++k] = getchar()
if (sum[k] == '/')
select[i++] = '>'
count++
end if
end if
if sum[k] == '.'
sum[++k] = getchar()
if sum[k] == '\n'
break;
end if
k++
end while
for i=0 to count
if select[i] 都是左符号
入栈
end if
else
if 都是右符号
if 栈空 break
if 各符号配对
出栈
else
break
end if
end for
if栈空且i=len
输出yes
else if栈空
输出no
else
输出栈顶和no
return 0;
2.1.2 总结解题所用的知识点
读取字符,读取/**/
出栈,入栈 :左符号入栈,右符号配对时出栈,判断出栈或入栈或break
2.2 银行业务队列简单模拟
#include "stdio.h"
#include "iostream"
using namespace std;
#define MaxSize 1000
typedef struct
{
int data[MaxSize];
int front, rear;
} SqQueue;
void InitQueue(SqQueue*& q);
int main()
{
int num[MaxSize];
int n;
int i;
int e;
int count=0;
SqQueue* A, * B;
cin >> n;
for (i = 0; i < n; i++)
{
cin >> num[i];
}
InitQueue(A);
InitQueue(B);
for (i = 0; i < n; i++)
{
if (num[i] % 2 == 1)
{
A->rear = (A->rear + 1) % MaxSize;
A->data[A->rear] = num[i];
}
else
{
B->rear = (B->rear + 1) % MaxSize;
B->data[B->rear] = num[i];
}
}
while (A->front != A->rear || B->front != B->rear)
{
for (i = 1; i <= 2; i++)
{
if (A->front != A->rear)
{
A->front = (A->front + 1) % MaxSize;
e = A->data[A->front];
count++;
if (count < n)
{
cout << e<<' ';
}
else
{
cout << e;
}
}
}
if (B->front != B->rear)
{
B->front = (B->front + 1) % MaxSize;
e = B->data[B->front];
count++;
if (count < n)
{
cout << e << ' ';
}
else
{
cout << e;
}
}
}
return 0;
}
void InitQueue(SqQueue*& q)
{
q = (SqQueue*)malloc(sizeof(SqQueue));
q->front = q->rear = 0;
}
2.2.1 解题思路及伪代码
思路:
先把编号都存入一个数组中,再利用for循环,把奇数的编号压入A栈,偶数的编号压入B栈,再利用while循环,先进行2次A栈的出队,再进行一次B栈的出队,直到A、B栈都空
int num[MaxSize]
int n
int i
int e
int count=0
SqQueue* A, * B
cin >> n
for i=0 to n
cin >> num[i]
end for
InitQueue(A)
InitQueue(B)
for i=0 to n
if (num[i] % 2 == 1)
then
A->rear = (A->rear + 1) % MaxSize
A->data[A->rear] = num[i]
end if
else
B->rear = (B->rear + 1) % MaxSize
B->data[B->rear] = num[i]
end for
while (A->front != A->rear || B->front != B->rear)
for i=1 to 2
if (A->front != A->rear)
then
A->front = (A->front + 1) % MaxSize
e = A->data[A->front]
count++
if (count < n)
then
cout << e<<' '
end if
else
cout << e
end if
end for
if B->front != B->rear
B->front = (B->front + 1) % MaxSize
e = B->data[B->front]
count++
if count < n
then
cout << e << ' '
else
cout << e
end if
end if
end while
return 0
2.2.2 总结解题所用的知识点
队列的出队和入队
输出顺序的判断
3.阅读代码(0--1分)
3.1 题目及解题代码
考研题
题目:一个正读和反读都相同的字符序列称为“回文”。例如“abcba”和“1221”是回文,而“abcde”不是回文。试写一个算法,要求利用栈的基本运算识别一个以@为结束符的字符序列是否是回文。
Status HuiWen(String str)
{
InitStack(&s1);//构造两个空栈
InitStack(&s2);
i=0;
while(str[i++]!='@')
Push(&s1,ch);//将字符压入栈s1
length=StackLength(s1);//length表示字符个数
for(i=0;i<length/2;i++)
Push(&s2,Pop(&s1,&e);//将s1中一半的字符逐个压入s2中
if(length%2!=0) //如果栈中元素为奇数个,需要去除s1的栈顶元素,也就是字符序列中间的一个字符
Pop(&s1,&e);
for(i=0;i<length/2;i++)
if(Pop(&s1,&e1)!=Pop(&s2,&e2))//e1和e2不等
return false; //有一个不相等就不是回文,直接结束程序
printf(yes);//运行到此步说明两栈字符相等
DestroyStack(s1); //销毁
DestroyStack(s2);
}//end
3.2 该题的设计思路及伪代码。
思路:将字符序列顺序压入栈1中,然后将栈1中的一半的字符(这里取商的下界,也就是说如果长度为5,一半表示2,长度为7,一半表示3)逐个压入栈2中,如果两个栈相等,那么是回文,否则不是
InitStack(&s1)构造两个空栈
InitStack(&s2)
i=0
while str[i++]!='@'
Push(&s1,ch) 将字符压入栈s1
end while
length=StackLength(s1)length表示字符个数
for i=0 to length/2
Push(&s2,Pop(&s1,&e) 将s1中一半的字符逐个压入s2中
end for
if length%2!=0 如果栈中元素为奇数个,需要去除s1的栈顶元素,也就是字符序列中间的一个字符
Pop(&s1,&e)
end if
for i=0 to length/2
if Pop(&s1,&e1)!=Pop(&s2,&e2) e1和e2不等
return false 有一个不相等就不是回文,直接结束程序
end if
end for
printf(yes)运行到此步说明两栈字符相等
DestroyStack(s1) //销毁
DestroyStack(s2)
}//end
时间复杂度:O(n)
空间复杂度:O(n)
3.3 分析该题目解题优势及难点。
考察学生是否熟练栈的应用
需要考虑字符的个数,若是偶数可直接将一半的字符逐个压入栈中,若是奇数则需要去除栈顶元素