这个作业属于哪个班级 | C语言--网络2011/2012 |
---|---|
这个作业的地址 | DS博客作业02--栈和队列 |
这个作业的目标 | 学习栈和队列的结构设计及运算操作 |
名字 | 黎钊涵 |
0. 展示PTA总分
1.本章学习总结
1.1 栈
栈结构的定义和特点
- 栈(stack)是一个特殊的线性表,是限定仅在一端(通常是表尾)进行插入和删除操作的线性表
- 先进后出、后进先出
- 插入元素到栈顶(即表尾)的操作,称为入栈
- 从栈顶(即表尾)删除最后一个元素的操作,称为出栈
顺序栈结构体
struct SNode {
ElementType* Data; /* 存储元素的数组 */
Position Top; /* 栈顶指针 */
int MaxSize;
};
初始化栈
void InitStack(SqStack* S)
{
S=new SqStack; //分配一个顺序栈空间,首地址放在S中
S->top=-1; //栈顶指针置为-1
}
入栈
void PushStack(Stack S, ElementType x)//入栈
{
if (S->Top == S->MaxSize)
{
printf("Stack Full
");
return;
}
S->Top++;
S->Data[S->Top] = x;
}
出栈
ElementType PopStack(Stack S)
{
if (S->Top == -1)
{
printf("Stack Empty
");
return 0;
}
return S->Data[S->Top--];
}
栈空
int StackEmpty(Stack S)
{
if (S->Top == -1)
return 1;
else
return 0;
}
链栈(链栈是运算受限的单链表,插入和删除仅在栈顶处执行,头指针就是栈顶,不需要头结点,空栈相当于头指针指向空)
结构体定义
typedef int Elmetype;
struct SNode
{
Elmetype data;
struct SNode* next;
};
typedef struct SNode* LinkStack;
进栈
void Push(LinkStack& S, Elmetype X)
{
LinkStack NewS = new SNode;
/*数据载入*/
NewS->data = X;
/*头插法插入新数据*/
NewS->next = S->next;
S->next = NewS;
}
出栈
bool Pop(LinkStack& S, Elmetype& e)
{
/*首先要判断栈顶是否为空*/
if (S->next == NULL)
{
return false;
}
e = S->next->data;
LinkStack delSNode = S->next;
S->next = delSNode->next;
delete delSNode;
return true;
}
1.2 栈的应用
- 数制转换
十进制数转八进制数代码如下
public class Conversion
{
public static void conversion(int N)
{
ArrayStack<Integer> stack = new ArrayStack<>();
while (N != 0)
{
stack.push(N % 8);
N /= 8;
}
while (!stack.isEmpty())
{
System.out.print(stack.pop());
}
}
public static void main(String[] args)
{
conversion(2007);
}
}
- 括号匹配检验
在编程过程中,如果有括号没有对应的另一半进行配对,编译器就会报错,可以用栈来实现前后括号匹配的检验,如下
public class Match
{
public static boolean match(String s)
{
ArrayStack<Character> stack = new ArrayStack<>();
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
switch (c)
{
case ')':
if (!stack.isEmpty() && stack.pop() == '(')
{
break;
}
else
{
return false;
}
case ']':
if (!stack.isEmpty() && stack.pop() == '[')
{
break;
}
else
{
return false;
}
case '}':
if (!stack.isEmpty() && stack.pop() == '{')
{
break;
}
else
{
return false;
}
default:
stack.push(c);
break;
}
}
return stack.isEmpty();
}
public static void main(String[] args)
{
System.out.println(match("{[()]()[{}]}"));
System.out.println(match("{[()]}}"));
}
}
- 迷宫求解
求迷宫从入口到出口的所有路径伪代码如下
初始化,将起点加入堆栈;
while(堆栈不为空)
{
取出栈顶位置为当前位置;
如果 当前位置是终点,
则 使用堆栈记录的路径标记从起点至终点的路径;
否则
{
按照从下、右、上、左的顺序将当前位置下一个可以探索的位置入栈;
如果 当前位置的四周均不通
则 当前位置出栈;
}
}
1.3 队列
队列的定义和特点
- 队列是一种先进先出的线性表。在表一端插入(队尾),在另一端(队头)删除
- 逻辑结构:与同线性表相同,仍为一对一关系
- 存储结构:顺序队或链队,以循环顺序队列更常见
结构体定义
typedef struct
{
ElemType data[MaxSize];
int front, rear;
}SqQueue;
typedef SqQueue* Queue;
初始化
void InitQueue(Queue Q)
{
Q = (Queue)malloc(sizeof(SqQueue)*Max);
Q->front = Q->rear = 0;
}
入队
bool EnQueue(Queue Q,ElemType e)
{
if(Q->rear == MaxSize)
return false;
Q->data[Q->rear++] = e;
return true;
}
出队
bool DeQueue(Queue Q,ElemType &e)
{
if(Q->front == Q->rear)
return false;
e = Q->data[Q->front++];
return true;
}
判断是否为空
bool QueueEmpty(Queue Q)
{
return (Q->front == Q->rear);
}
销毁
void DestroyQueue(Queue Q)
{
free(Q);
}
环形队列
结构体定义
typedef struct
{
ElemType data[MaxSize];
int front, rear;
}SqQueue;
typedef SqQueue* Queue;
初始化
void InitQueue(Queue Q)
{
Q = (Queue)malloc(sizeof(SqQueue)*Max);
Q->front = Q->rear = 0;
}
入队
bool EnQueue(Queue Q,ElemType e)
{
if((Q->rear +1) % MaxSize == Q->front)
return false;
Q->data[Q->rear] = e;
Q->rear = (Q->rear + 1) % MaxSize;
return true;
}
出队
bool DeQueue(Queue Q,ElemType &e)
{
if(Q->front == Q->rear)
return false;
e = Q->data[Q->front];
Q->front = (Q->front + 1) % MaxSize;
return true;
}
判断是否为空
bool QueueEmpty(Queue Q)
{
return (Q->front == Q->rear);
}
销毁
void DestroyQueue(Queue Q)
{
free(Q);
}
链式队列
结构体定义
typedef struct QNode /* 声明链式队列的结点 */
{
int data;
struct QNode *next;
}Node;
typedef struct QueuePoint /* 声明链式队列的首尾指针 */
{
Node *front;
Node *rear;
};
typedef QueuePoint* Queue;
初始化
Queue InitQueue (Queue Q)
{
Q = (Queue)malloc(sizeof(QueuePoint));
Q->front = Q->rear = NULL;
return Q;
}
入队
void EnQueue(Queue Q,ElemType e)
{
Node* p;
p = (Node*)malloc(sizeof(Node));
p->data = e;
p->next = NULL;
if(Q->rear == NULL)
Q->front = Q->rear = p;
else
{
Q->rear->next = p;
Q->rear = p;
}
}
出队
bool DeQueue(Queue Q,ElemType &e)
{
Node* p;
if(Q->rear == NULL)
return false;
p = Q->front;
if(Q->front == Q->rear)
Q->front = Q->rear = NULL;
else
Q->front = Q->front->next;
e = p->data;
free(p);
return true;
}
判断是否为空
bool QueueEmpty(Queue Q)
{
return (Q->rear == NULL);
}
销毁
void DestroyQueue(Queue Q)
{
Node* pre = Q->front,* p;
if(pre != NULL)
{
p = pre->next;
while(p != NULL)
{
free(pre);
pre = p;p = p->next;
}
free(pre);
}
free(Q);
}
舞伴问题
int QueueLen(SqQueue Q)//队列长度
{
int sum = 0;
int i;
for (i = Q->front + 1; i <= Q->rear; i++)//front总在数前一位
{
sum++;
}
return sum;
//return Q->rear - Q->front;
}
int EnQueue(SqQueue &Q, Person e)//加入队列
{
if(Q->rear >= MAXQSIZE)
return 0;
//if(Q->rear >= MAXQSIZE) return 0;
Q->data[Q->rear++] = e;
return 1;
}
int QueueEmpty(SqQueue &Q)//队列是否为空
{
return (Q->front == Q->rear);
}
int DeQueue(SqQueue &Q, Person &e)//出队列
{
if(QueueEmpty(Q))
return 0;
e = Q->data[Q->front++];
return 1;
}
void DancePartner(Person dancer[], int num) //配对舞伴
{
Person male,female;
int i;
//将男生女生数组全部入队
for(i = 0; i < num; i ++)
{
if(dancer[i].sex == 'F')
EnQueue(Fdancers,dancer[i]);
else
EnQueue(Mdancers,dancer[i]);
}
while(QueueLen(Fdancers) != 0 && QueueLen(Mdancers) != 0)
{
DeQueue(Fdancers,male);
cout<<male.name<<" ";
DeQueue(Mdancers,female);
cout<<female.name <<endl;
}
}
2.PTA实验作业
2.1 符号配对(本题用C++作答,此段代码用C则编译错误)
#include<iostream>
#include<cstdlib>
using namespace std;
//#define ERROR NULL
const int MaxSize=109;
typedef char ElementType;
struct Stack{
ElementType Symbol[MaxSize];
int Top;
};
Stack* Create();
bool Push(Stack* S,ElementType X);
ElementType Pop(Stack* S);
ElementType getTop(Stack* S);///获取栈顶元素
int main()
{
Stack* S=Create();
char str[1000],stacktop;
int i,flag=0,flag2=0,flag_i=0;
while(true)
{
cin.getline(str,1000); ///用gets发生编译错误
if(str[0]=='.')
break;///一行一行地读取,遇到'.'时结束
for(i=0;str[i]!=' ';i++)
{
flag_i=0;
/** 遇到左符号,入栈*/
if(str[i]=='('||str[i]=='['||str[i]=='{')
Push(S,str[i]);
if(str[i]=='/'&&str[i+1]=='*')
{
flag_i=1;///遇到/*的标志
Push(S,str[i]);
Push(S,str[i+1]);
/// i++; 若在此处使i++,则下面的if语句中i值被改变
}
/** 遇到右符号,与栈顶符号配对*/
if(str[i]==')')
{
if(S->Top==-1)///栈为空,则当前右符号缺少左符号,结束循环
{
cout<<"NO"<<endl;
cout<<"?-"<<str[i]<<endl;
flag=1;///栈空时判断是否YES的标志
flag2=1;///跳出while循环的标志
break;
}
stacktop=getTop(S);
if(stacktop!='(')///栈顶元素与当前右符号不匹配,结束循环
{
flag2=1;
break;
}
else
Pop(S); ///匹配则出栈
}
if(str[i]==']')
{
if(S->Top==-1)
{
cout<<"NO"<<endl;
cout<<"?-"<<str[i]<<endl;
flag=1;
flag2=1;
break;
}
stacktop=getTop(S);
if(stacktop!='[')
{
flag2=1;
break;
}
else
Pop(S);
}
if(str[i]=='}')
{
if(S->Top==-1)
{
cout<<"NO"<<endl;
cout<<"?-"<<str[i]<<endl;
flag=1;
flag2=1;
break;
}
stacktop=getTop(S);
if(stacktop!='{')
{
flag2=1;
break;
}
else
Pop(S);
}
if(str[i]=='*'&&str[i+1]=='/')
{
if(S->Top==-1)
{
cout<<"NO"<<endl;
cout<<"?-*/"<<endl;
flag=1;flag2=1;
break;
}
stacktop=getTop(S);
if(stacktop!='*')
{
flag2=1;
break;
}
else
{
Pop(S);
Pop(S);
}
i++;/// */比较完毕后i同样++
}
if(flag_i)
i++;/// 缺少该语句将使 /*/ 被判定为配对成功
}
if(flag2)
break;
}
if(S->Top!=-1)///栈不空,则栈顶元素缺少右符号
{
cout<<"NO"<<endl; ///YES NO 注意大写
if(getTop(S)=='*')
cout<<"/*-?"<<endl;
else
cout<<Pop(S)<<"-?";
}
else if(!flag)///栈空且flag==0,全部配对成功
cout<<"YES";
system("pause");
delete S;
return 0;
}
Stack* Create()
{
Stack* S=new Stack;
S->Top=-1;
return S;
}
bool Push(Stack* S,ElementType X)
{
if(S->Top==MaxSize-1)
return false;
S->Symbol[++(S->Top)]=X;
return true;
}
ElementType Pop(Stack* S)
{
// if(S->Top==-1)
// return ERROR;
return S->Symbol[(S->Top)--];
}
ElementType getTop(Stack* S)
{
ElementType top=Pop(S);
Push(S,top);
return top;
}
2.1.1解题思路及伪代码
把比较特殊的/和/用< >代替,创建一个栈然后把找到的对应符号放入栈中,然后进行比较得到符号是否匹配
int main
{
static char ch1[1000], ch2[1000], ch[10000];//ch放代码,ch2放找到的符号,ch1用于符号匹配
for(i = 0;; i++)
{
找到对应符号然后放入ch2中//用<>代替两个的符号
}
int flag=1 用于记录
for (i = 0; i < k; i++)
{
if ch2中符号是左符号,放入栈中
else if ch2中符号是右符号
{
if 栈中存在符号,并且和ch2和栈中符号匹配,则消除栈中该符号
else 输出NO 和对应缺少的符号,flag=0
}
}
if flag=1同时栈中无符号 输出YES
else
{ 输出 NO
根据栈中情况输出对应缺少符号
}
}
2.1.2总结解题所用的知识点
- 顺序栈的结构
- 顺序栈的出栈入栈操作
- 递归函数的调用
- 标准输入输出流的运用
2.2 银行业务队列简单模拟
2.2.1 解题思路及伪代码
思路
伪代码
输入人数k
创建队列q,p
for (i = 0; i < k; i++)
{
cin >> n;//输入编号
if (n % 2) 编号为奇数则入奇数的栈;
else 编号为偶数则入偶数的栈 ;
}
for (i = 0; i < k; i++)
{
if (i == 0)//对第一个数据输出处理空格
if ((i + 1) % 3)//对a窗口处理
{
if (!q1.empty()//判断是否处理完毕
未处理完毕打出a窗口的编号;
else 处理完毕直接打出b窗口的所有编号;
}
else//对b窗口处理
{
if (!q2.empty())//判断是否处理完毕
未处理完毕打出b窗口的编号
else 处理完毕直接打出b窗口的所有编号
}
}
return 0;
}
2.2.2 总结解题所用的知识点
- 学会运用queue容器。
- 掌握了队列的创建,判空,入队,出队等操作
- 懂得了对两个队列的判断,当A或B两个有一个队列为空就退出循环,然后单独输出剩余队列
3.阅读代码
3.1 题目及解题代码
Stack CreateStack(int MaxSize)//双栈结构即为两个栈共享一块空间
{
Stack stack = (struct SNode *)malloc(sizeof(struct SNode));//先为栈分配一个空间
stack->Data = (int *)malloc(sizeof(ElementType)* MaxSize);//为栈分配一个Macsize大小的数组空间存放值
stack->Top1 = -1;//栈1空
stack->Top2 = MaxSize;//栈2空
stack->MaxSize = MaxSize;//
return stack;
}
bool Push(Stack S, ElementType X, int Tag)//入栈操作
{
if (!S)//这个栈空间不存在,分配失败的时候
return false;
if (S->Top1+1==S->Top2)//栈满的情况
{
printf("Stack Full
");
return false;
}
if (Tag == 1)
S->Data[++S->Top1] = X;//++在前先取数据使用后自加
else
S->Data[--S->Top2] = X;
return true;
}
ElementType Pop(Stack S, int Tag)
{
if (!S)
return ERROR;
if (Tag == 1)
{
if (S->Top1 == -1)//空栈时
{
printf("Stack %d Empty
",Tag);
return ERROR;
}
return S->Data[S->Top1--];//出栈top1向前移动
}
if (S->Top2 == S->MaxSize)
{
printf("Stack %d Empty
", Tag);
return ERROR;
}
return S->Data[S->Top2++];//出栈top2向后移动
}