线性表
P1160
#include <cstdio>
const int N = 1e5 + 5;
int left[N], right[N];
bool del[N]; // del记录是否被删过
int main()
{
int n; scanf("%d", &n);
right[0]=1; left[1]=0;
right[1]=n+1; left[n+1]=1; // 0<->1<->n+1
for (int i=2;i<=n;i++) {
int k,p; scanf("%d%d", &k,&p);
if (p==0) {
// 插入到k的左边
int l=left[k];
// l<->k 变成 l<->i<->k
right[l]=i; left[i]=l;
right[i]=k; left[k]=i;
} else {
// 插入到k的右边
int r=right[k];
// k<->r 变成 k<->i<->r
right[k]=i; left[i]=k;
right[i]=r; left[r]=i;
}
}
// 0<->....<->n+1
int m; scanf("%d", &m);
for (int i=1;i<=m;i++) {
int x; scanf("%d",&x);
if (!del[x]) {
int l=left[x],r=right[x];
// l<->x<->r 变成 l<->r
right[l]=r; left[r]=l;
del[x]=true;
}
}
// 0<->....<->n+1
int x=right[0];
// right[x] right[right[x]] ...
while (x!=n+1) {
printf("%d ", x);
x=right[x];
}
return 0;
}
栈
在超市购物的时候,超市入口处往往会放一排购物车。这一排购物车一个插在另一个的后面,顺序排列,第一个一般靠着墙,不好拿。这时候,如果想取走一辆,一般是先取走最后面的一辆,下一个来购物的顾客取走倒数第二辆。与之对应的,如果顾客用完了购物车,要把购物车还回去,那么归还的这辆购物车通常也是放在最后面。在通常情况下,最后面的车会被反复取用,而第一辆很少被用到,除非其他购物车都被取走了。
平常写表达式,一般运算符在数的中间,比如 \(1 + 3 \times 5\),其中 \(+\) 在 \(1\) 和 \(3 \times 5\) 之间,\(\times\) 在 \(3\) 和 \(5\) 中间,这种表达式称为中缀表达式。中缀表达式对人类友好,但对计算机没那么友好。对计算机友好的表达式是“后缀表达式”,顾名思义,后缀表达式中运算符在参数的后面。对于计算机而言,后缀表达式比中缀表达式更容易计算,另外,后缀表达式的运算机制可以避免掉括号,这也是它相对于中缀表达式的一大优势。
计算题:中缀表达式 ((6-3)*2+7)/(5^(3*4+2))
对应的后缀表达式为?
答案
例题:P1449 后缀表达式
#include <cstdio>
#include <cstring>
#include <stack>
using std::stack;
const int N = 55;
char s[N];
int main()
{
scanf("%s", s + 1);
int len = strlen(s + 1);
int num=0;
stack<int> st; // 存储运算数的栈
for (int i = 1; i <= len; i++) {
if (s[i]>='0'&&s[i]<='9') {
// 更新数字
num=num*10+(s[i]-'0');
} else if (s[i]=='.') {
// num就作为一个运算的数字加入到栈中
st.push(num);
num=0;
} else if (s[i]=='@') {
break;
} else {
// +-*/
// 取出栈顶的两个元素
// top() 表示取栈顶
// pop() 表示弹出栈顶
// empty() 返回一个栈是否为空
// true对应空,false对应非空
int x=st.top(); st.pop();
int y=st.top(); st.pop();
// x和y就是最近两次压入栈中的运算数
int z;
if (s[i]=='+') {
z=y+x;
} else if (s[i]=='-') {
z=y-x;
} else if (s[i]=='*') {
z=y*x;
} else {
z=y/x;
}
st.push(z);
}
}
printf("%d\n", st.top());
return 0;
}
P4387
#include <cstdio>
#include <stack>
using std::stack;
const int N = 1e5 + 5;
int in[N], out[N];
int main()
{
int q; scanf("%d", &q);
for (int i = 1; i <= q; i++) {
int n; scanf("%d", &n);
for (int j = 1; j <= n; j++) scanf("%d", &in[j]);
for (int j = 1; j <= n; j++) scanf("%d", &out[j]);
int kout=1; // 表示接下来要去和out[kout]匹配
int kin=1; // 表示接下来要入栈的是in[kin]
stack<int> s;
while (true) {
if (!s.empty() && kout<=n && s.top()==out[kout]) {
s.pop(); kout++;
} else if (kin<=n) {
s.push(in[kin]); kin++;
} else {
break;
}
}
if (kout==n+1) printf("Yes\n");
else printf("No\n");
}
return 0;
}
P2201
#include <cstdio>
#include <stack>
#include <algorithm>
using std::stack;
using std::max;
const int N = 1e6 + 5;
struct Data {
int x,s,maxs;
};
Data a[N]; // 管理光标前的元素、前缀和、最大前缀和
int top; // 给数组a配套的栈顶位置
char op[5];
int main()
{
a[0].s=0; a[0].maxs=-2000; // 要给一个比-1000小的数
int n; scanf("%d",&n);
stack<int> s2; // 管理光标后的元素
for (int i=1;i<=n;i++) {
scanf("%s",op);
char ch=op[0];
if (ch=='I') {
int x; scanf("%d",&x);
// 这里要push一个Data类型的元素
// {x,s,maxs}
top++;
a[top].x = x;
a[top].s = a[top-1].s+x;
a[top].maxs = max(a[top-1].maxs, a[top].s);
} else if (ch=='D') {
top--;
} else if (ch=='L') {
s2.push(a[top].x); top--;
} else if (ch=='R') {
int x=s2.top();
top++;
a[top].x = x;
a[top].s = a[top-1].s+x;
a[top].maxs = max(a[top-1].maxs, a[top].s);
s2.pop();
} else {
int k; scanf("%d",&k);
printf("%d\n", a[k].maxs);
}
}
return 0;
}
队列
选择题:下述代码实现的数据结构是
int data[100], f = 1, r;
void insert(int value) {
data[++r] = value;
}
void pop() {
f++;
}
A. 链表
B. 栈
C. 队列
D. 平衡树
答案
C
P1540
#include <cstdio>
#include <queue>
using std::queue;
const int N = 1005;
bool inq[N]; // inq[i]表示i是否在队列中
int main()
{
int m, n; scanf("%d%d",&m,&n);
queue<int> q;
int cnt=0; // 队列中元素个数
int ans=0;
for (int i=1;i<=n;i++) {
int x; scanf("%d",&x);
if (!inq[x]) {
if (cnt>=m) {
inq[q.front()]=false;
cnt--;
q.pop();
}
q.push(x); inq[x]=true; cnt++;
ans++;
}
}
printf("%d\n",ans);
return 0;
}
P2058
#include <cstdio>
#include <queue>
using std::queue;
const int N = 1e5 + 5;
struct Person {
int t, id;
};
int cnt[N]; // cnt[i] i国家的人在船上有多少个
int main()
{
queue<Person> q;
int n; scanf("%d",&n);
int ans=0; // 船上不同国籍数
for (int i=1;i<=n;i++) {
int t,k; scanf("%d%d",&t,&k);
// 上船
for (int j=1;j<=k;j++) {
int x; scanf("%d",&x);
q.push({t,x}); cnt[x]++;
if (cnt[x]==1) { // 只有0->1说明国籍数+1
ans++;
}
}
// 一天前的人下船
while (q.front().t <= t-86400) {
int x=q.front().id;
cnt[x]--;
if (cnt[x]==0) { // 只有1->0说明国籍数-1
ans--;
}
q.pop();
}
printf("%d\n",ans);
}
return 0;
}