这个作业属于哪个班级 | 数据结构--网络2011/2012 |
---|---|
这个作业的地址 | DS博客作业02--栈和队列 |
这个作业的目标 | 学习栈和队列的结构设计及运算操作 |
姓名 | 吴俊豪 |
0.PTA得分截图
1.本周学习总结
1.1栈
顺序栈
结构:
如图所示,顺序栈即一堆按照顺序排列的,拥有连续内存地址的储蓄结构的栈,数据由栈顶进入和导出,因此其对数据读取(尤其是栈底数据)时相较于数组和链表的效率略低,但其仅能从栈顶进出的特性对一些特殊(配对类)的问题效果拔群.
操作函数
结构体创建:
typedef int Position;
typedef struct SNode *PtrToSNode;
struct SNode {
ElementType *Data; /* 存储元素的数组 */
Position Top; /* 栈顶指针 */
int MaxSize; /* 堆栈最大容量 */
};
typedef PtrToSNode Stack;
创建并初始化顺序栈
Stack CreateStack( int MaxSize )
{
Stack S = (Stack)malloc(sizeof(struct SNode));
S->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
S->Top = 0;//栈顶
S->MaxSize = MaxSize;
return S;
}
入栈与出栈
bool Push(Stack S, ElementType X)//入栈
{
if (S->Top == S->MaxSize)//满栈
{
printf("Stack Full
");
return false;
}
S->Top++;
S->Data[S->Top] = X;
return true;
}
ElementType Pop(Stack S)//出栈
{
int e;
if (S->Top == 0)空栈
{
printf("Stack Empty
");
return ERROR;
}
e = S->Data[S->Top];
S->Top--;
return e;
}
注:入栈记得检查栈满,出栈记得检查栈空.
链栈
结构
链栈,顾名思义,就是和单链表长的八成像的栈结构,区别在于只能在栈顶进行数据操作.
操作函数
创建结构体
typedef struct SNode //定义链栈结点类型
{
ElemType data;
struct SNode *next; //指向后继结点
} LNode,*LinkStack;
创建并初始化链栈
bool InitStack(LinkStack &S)
{
S=NULL;
return true;
}
入栈与出栈
bool Push(LinkStack &S, int e) //入栈
{
LinkStack p;
p = new Snode; //现场申请现场用
p->data = e; //将e附在新结点的data里
p->next = S;
S = p;
return true;
}
bool Pop(LinkStack &S, int &e) //出栈
{
LinkStack p;
if (S == NULL) //栈满
{
return false;
}
e = S->data; //备份数据
p = S;
S = S->next;
delete p; //释放空间
return true;
}
注:由于入栈时链栈空间可以主动按需申请,因此无需考虑栈满情况
1.2 栈的引用
对于常规计算中出现的优先级问题, 用以往我们学过的字符串似乎比较棘手, 所以可以尝试采用栈来处理优先级.
算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。
例如:
2+3*(7-4)+8/4
得出
2 3 7 4 - * + 8 4 / +
1.3 队列
结构
操作函数
结构体定义
typedef struct QNode{
QElemtype *base;
int front;
int rear;
}SqQueue;
队列创建
void InitQueue(SqQueue *Q)
{
Q->base=(QElemtype*)malloc(sizeof(QElemtype)*QUEUESIZE);
assert(Q->base!=NULL);
Q->front=Q->rear=0;
}
队尾数据入队
Status EnQueue(SqQueue *Q,QElemtype e)
{
if(Q->rear==QUEUESIZE)
{
return ERROR;
}
Q->base[Q->rear]=e;
Q->rear++;
return OK;
}
队首数据出队
Status GetHead(SqQueue *Q,QElemtype *e)
{
if(Q->front==Q->rear)
{
return ERROR;
}
*e=Q->base[Q->front];
return OK;
}
环形队列
拼的不是很圆这是有够抱歉的呢
具体操作步骤和队列大差不差,就是栈满情况为front=rear%m(m为储存节点个数)
2. PTA实验作业
2.1 符号配对
[https://gitee.com/konjac_wjh/web-2011---blog-code/issues/I3G2DB]
2.1.1 解题思路
遍历一遍字符串->抓左括号来入栈->右括号停下查看->匹配就把左出栈->遍历结束在看栈->是为空栈无遗憾 skr~(
2.1.2 知识点
创建栈,进出栈
2.2 银行业务队列简单模拟
[https://gitee.com/konjac_wjh/web-2011---blog-code/issues/I3G2GN]
2.2.2 解题思路
把客人按序号奇数偶数从队尾分装进两个队列, 再用循环按照2A1B输出即可
2.2.2 知识点
创建队列,进出队列
3. 阅读代码
- 无法吃午餐的学生数量
3.1 题目及解题代码
学校的自助午餐提供圆形和方形的三明治,分别用数字 0 和 1 表示。所有学生站在一个队列里,每个学生要么喜欢圆形的要么喜欢方形的。
餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个 栈 里,每一轮:
如果队列最前面的学生 喜欢 栈顶的三明治,那么会 拿走它 并离开队列。
否则,这名学生会 放弃这个三明治 并回到队列的尾部。
这个过程会一直持续到队列里所有学生都不喜欢栈顶的三明治为止。
给你两个整数数组 students 和 sandwiches ,其中 sandwiches[i] 是栈里面第 i 个三明治的类型(i = 0 是栈的顶部), students[j] 是初始队列里第 j 名学生对三明治的喜好(j = 0 是队列的最开始位置)。请你返回无法吃午餐的学生数量。
来源:力扣(LeetCode)
链接:[https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch]
int countStudents(int* students, int studentsSize, int* sandwiches, int sandwichesSize){
int arr[2];
memset(arr, 0, sizeof(arr));
for (int i=0; i<studentsSize; ++i) {
++arr[students[i]];
}
for (int i=0; i<sandwichesSize; ++i) {
if (arr[sandwiches[i]] == 0) break;
--arr[sandwiches[i]];
}
return arr[0] + arr[1];
}
3.2 该题的设计思路
若喜欢栈顶的甜点的学生存在,那么不管他们在队伍的哪个位置,必定会遍历到他。否则,一定无法继续拿掉栈顶甜点。
3.3 难点&优势
难点
要将学生依次入队再依次和甜点数组进行比较,如果相等,则此学生出队,三明治数组元素后移一位。如果不相等,则将学生队列中的队头移至队尾,重复比较。用此方法解有一个问题,就是什么时候循环比较的过程可以结束
由题目可知,当学生队列中的每一个都不喜欢三明治数组里的头元素则循环结束,所以可定义一个用来判断循环能否结束的函数来控制循环次数。最后如果学生队列为空,则返回0,反之,则返回学生队列中的元素个数。
优势
对队列的操作大多为基础且易于理解,用一个新循环来判断循环是否应该结束.