DS博客作业02--栈和队列
| 这个作业属于哪个班级 | 数据结构--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | DS博客作业02--栈和队列 |
| 这个作业的目标 | 学习栈和队列的结构设计及运算操作 |
| 姓名 | 王鑫 |
0.PTA得分截图
1.本周学习总结
1.1栈
- 顺序栈(存储的空间是顺序的)
栈只能在一端进行插入和删除,设置顺序栈的的结构体时,用一个top来表示用来删除和插入的栈顶。顺序栈就像一个特殊的数组,只对top表示下标的栈元素改动。
typedef struct {
elementType data[Max];//存放数据
int top;//用来插入删除
int MaxSize;//堆栈最大容量
}SqStack;
top=-1;//栈空条件
top=MaxSize-1;//栈满条件
top++;st->data[st->top]=e;//进栈操作
e=st->data[st->top];top--;//退栈操作
- 初始化栈
void InitStack(SqStack& s)
{
s = new Stack;
s->top = -1;
}
- 销毁栈
void DestroyStack(SqStack& s)
{
delete s;
}
- 进栈
bool Push(SqStack& s, ElementType e)
{
if (s->top == MaxSize - 1)//如果栈为满的时候
return false;//返回错误
s->top++;
s->data[s->top] = e;
return true;
}
- 出栈
bool Pop(SqStack& s, ElementType& e)
{
if (s->top == -1)//栈为空的时候,返回false
return false;
e = s->data[s->top];//取栈顶元素
s->top--;//栈顶指针-1
return true;
}
- 取栈顶元素
bool GetTop(SqStack* s, ElementType& e)
{
if (s->top == -1)//栈为空的时候,返回false
return false;
e = s->data[s->top];//取元素,并不移动指针
return true;
}
- 链栈(采用链式存储数据,空间分配不是顺序的)
数据定义
typedef struct linkknode
{
ElementType data;//数据域
struct linknode* next;//指针域
}LiNode, * LiStack;
链栈的操作函数
- 初始化栈
void InitStack(SqStack& s)
{
s = new Stack;
s->next = NULL;
}
- 销毁栈
void DestroyStack(SqStack& s)
{
LiStack node;
while (s != NULL)
{
node = s;
s = s->next;
delete node;
}
}
- 判断栈是否为空
bool StackEmpty(LiStack s)
{
return (s->next == NULL);
}
- 进栈//头插法来插入
bool Push(SqStack& s, ElementType e)
{
LiStack p;
p = new LiNode;//申请新的节点
p->data = e;//赋值给它
p->next = s->next;//插入p节点
s->next = p;
}
- 出栈
bool Pop(SqStack& s, ElementType& e)
{
LiStack p;
if (s->next == NULL)//栈为空的时候,返回false
return false;
p = s->next;
e = p->data;
s->next = p->next;//删除p节点
delete p;//释放p节点
return true;
}
- 取栈顶元素
bool GetTop(SqStack* s, ElementType& e)
{
if (s->next == NULL)//栈为空的时候,返回false
return false;
e = s->next->data;//取元素,并不移动指针
return true;
}
1.2栈的应用
之前做小学生口算系统时,做有优先级的运算时,不好做处理。现在学习了栈,可以运用栈的先进后出的特点来实现优先级运算。
中缀表达式 a+b*c+(d*e+f)*g
转为后缀 abc*+de*f+g*+
遍历中缀表达式
if 算子直接->postexp[]
else 运算符
switch (运算符)
{
case'(':进数组postexp[]
case')':Pop()出栈e
while (直到出栈的e为')')
{
e->postexp;
Pop(),出栈e
}
case'+':
case'-':
while (直到栈为空)
{
GetTop//取栈顶
if (栈顶e! = '(')
{
出栈;
进数组postexp;
}
else
break;
}
进栈我们现在遍历到的运算符
case'*':
case'/':
while (直到栈为空)
{
GetTop//取栈顶
if (栈顶为'+' || '-')
break;
if (栈顶e! = '*'||'/')
{
出栈;
进数组postexp;
}
else
break;
}
进栈我们现在遍历到的运算符
default:
while (*exp旧数组为数字)
{
进新数组;
exp++;
}
}
while (栈不为空时)
{
出栈;
进新数组postexp;
}
postexp[i] = 0;//结束标志
后缀表达式求值
遍历后缀表达式
遇见数字入栈
遇见操作符时一次出栈操作数 b,a 做运算 a op b ,结果入栈
遍历完成后栈内的那个元素即是结果
1.3队列
队列和栈的不同就是队列两个端口都能用,不过一般队头出队,队尾进队。
这样队列的特点就是先进先出。队列的结构体设计,有两个指针,一个用来表示队头一个用来表示队尾。
typedef struct
{
ElemType data[MaxSize];
int front, rear;//队头和队尾指针
}Queue;
front=rear;//队空的条件
rear=MaxSize-1;//队满条件
rear++;data[rear]=e;//e进队
front++;e=data[front];//e出队
- 初始化队列
void InitQueue(SqQueue& q)
{
q = new Queue;
q->front = q->rear = -1;
}
- 销毁队列
void DestroyQueue(SqQueue& q)
{
delete q;
}
- 判断函数是否为空
bool QueueEmpty(SqQueue q)
{
return (q->front == q->rear);
}
- 进队列
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;
}
使用队列的时候,可能因为front前出队留下的空位,导致rear=MaxSize-1作为队满条件不满足,出现假溢出。
这时候我们逻辑上让这个队列前后连接起来,形成一个环状的顺序表,称为环形队列或循环队列。
环形队列结构的结构体设计和不同的队列没有什么不同
typedef struct
{
ElemType data[MaxSize];
int front, rear;//队头和队尾指针
}Queue;
- 初始化环形队列
void InitQueue(SqQueue& q)
{
q->new Queue;
q->front = q->rear = 0;//设置在最初的一位数上
}
- 销毁环形队列
void DestroyQueue(SqQueue& q)
{
delete q;
}
- 判断环形队列是否为空
void 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->rear == q->front)//队空
return false;
e = q->data[q->front];
q->front = (q->front + 1) % MaxSize;
return true;
}
链式队列存储
队列用链式存储时,设立两个指针来指向队头和队尾。但这两个指针里面没有存放数据。
- 链队列结构体设计
typedef struct qnode {
ElemType data;
struct qnode* next;
}QNode;
//链队列中头指针为指针类型
typedef struct
{
QNode* front;
QNode* rear;
}LinkQueue;
- 初始化链队
//这个是带头节点的链队
Status InitQueue(LinkQueue& Q)
{
Q.front = Q.rear = new QNode;
if (!Q.front)exit(OVERFLOW);
Q.front->next == NULL;
return OK;
}
- 判断是否为空
Status QueueEmpty(LinkQueue& Q)
{
return (Q.front == Q.rear);
}
//取链队的队头元素
Status GetHead(LinkQueue& Q,ElemType &e)
{
if (Q.front == Q.rear)return ERROR;
e = Q.front->next->data;//除头结点的第一个节点的数据
return OK;
}
- 入队和出队
Status EnQueue(LinkQueue& Q, ElemType& e)
{
p = new QNode;
if (!p)exit(OVERFLOW);
p->data = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
Status DeQueue(LinkQueue& Q, ElemType& e)
{
if (Q.front == Q.rear)return ERROR;
p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;//最后一个元素被删,改队尾
delete p;
return OK;
}
2.PTA实验作业
2.1符号配对
2.1.1伪代码
将数据传入字符型数组st
for (直到st的结尾)
{
if (st为"/*")
{
进s[];//用<代替/*
}
else if (st == '(' || '[' || '{')
{
进s[];//进栈
}
else if (st为 * / )
{
if (栈顶为 < )
{
Pop()//出栈
}
else
{
printf("NO\n");
if (top - 1)//栈内无元素
printf("?-*/\n");//缺失左符号
else
printf("%c-?\n", c);//缺失右符号
结束函数//return 0
}
}
else if (st == ')' || ']' || '}')
{
if[s的栈顶是三个之中的一个配对符号]
{
出栈
}
else
if (top == -1栈内无元素)
printf("?-%c\n", st[i]);
else
printf("%c-?\n", c);//缺失右符号
< 要单独处理
结束函数
}
}
if(top == -1)//在经过上面的处理后,栈内为空
{
输出:YES;
}
else
{
输出:NO
输出:栈内第一个 - ? ;
}
2.1.1解题思路
遍历数组
if算子
进新的数组
else
判断与前一位的优先级
前一位高则出栈,进新数组直到比现在这位低的优先级,然后进栈本位
前一位没有比本位高,进栈本位
2.1.2 总结解题所用知识点
-
1.char ch[1000];//用来和栈内符号匹配 比较灵活
ch[')'] = '(';
ch[']'] = '[';
ch['}'] = '{';
用空间来换时间,设立一个字符型数组,用它们的ASCII码做下标,之后我们
就可以更灵活的来找匹配的符号。像:
s[top] == ch[st[i]]
我们要找')'的时候就能用ch[')']来表示我们要找的'(' -
2.题目中有'/'和'/',这两个都是两个字符,我们判断出后可以使用'<'和'>'来代替入栈,这样后期符号匹配比较好找
2.2银行业务队列简单模拟
2.2.1伪代码
for (i < max; i++)
{
奇数进 odd栈
偶数进 even栈
}
while (i < max)
{
if (flag < 2)
{
if (odd不为空)
{
输出e
flag++;
}
}
else
{
even出栈
输出even出栈的元素
flag = 0;
}
if (i != max - 1)//还没到最后一位数
cout << " ";//数字后输出空格
if (odd为空,even不为空)
(
将odd剩下的按格式输出
}
else if(even为空,odd不为空)
{
将even剩下的按格式输出
}
2.2.1解题思路
分两个队列odd和even,分别为奇数偶数
每输出两个奇数,就输出一个偶数
if其中一个为空的时候
将剩下的输出
3.阅读代码
3.1题目及解题代码
3.2该题的设计思路
先按照身高排队
再根据前面人数再排
遍历(从高到矮)
如果k=0,放到第一个,
k有数字就判断已经进去的人,来判断本次放在哪
3.3难点
- 有两个判断顺序的标准,先用一个标准拍好序,再根据第二个标准做第二次调整
3.3 O(n)
因为遍历一遍后还要再判断本次位置,O(n^2)
空间复杂度:O(n),即为排序需要使用的栈空间