PAT A1057 Stack (30 分)
Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO). The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element). Now you are supposed to implement a stack with an extra operation: PeekMedian -- return the median value of all the elements in the stack. With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤105). Then N lines follow, each contains a command in one of the following 3 formats:
Push key
Pop
PeekMedian
where key is a positive integer no more than 105.
Output Specification:
For each Push command, insert key into the stack and output nothing. For each Pop or PeekMedian command, print in a line the corresponding returned value. If the command is invalid, print Invalid instead.
Sample Input:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
Sample Output:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
知识补充:分块思想
分块思想主要运用于快速查找一个序列中第K大的元素这种应用场景,查询的过程分为2种:在线查询和离线查询,两者区别在于查找数据的过程中,原来的数组中的数据是否会动态变化,若是在动态变化的数组中查找元素则是在线查询,反之为离线查询。
实现的方式是将一个数据量为N的数组,分成\(\sqrt{N}\)个组,Block[N],用于保存每个块中的数据个数,重点是一个组中的数据是连续的,例如{{1,2,3},{4,5,6},{7,8,9}}分三个组,组中数据都是连续的。
还需要一个散列表table[N],用于存放数据元素x保存的个数,其余具体操作都是下面代码实现中。
代码实现:
#include <iostream>
#include <stack>
#include <cmath>
#include <cstring>
using namespace std;
const int N=100010;
int sqrN=316,table[N]= {0},block[316];//sqrN=sqrt(N)
stack<int> st;
int findMedian() {
//idx用于存储分块的块号 sum用于存储当前寻找的第几个元素
int mid=(st.size()+1)/2,sum=0,idx=0;
while(sum+block[idx]<mid) {//寻找到中间位数据所处的块为止
sum+=block[idx++];
}
int bgPos=idx*sqrN;//找到目标块的起始位置也就是第一个元素在table数组中的下标
while(sum+table[bgPos]<mid) {//直到找到中间位置的这个数据为止
sum+=table[bgPos++];//从中间数所在块的第一个元素开始寻找
}
return bgPos;//找到中间元素的值了
}
void push(int x) {
table[x]++;
block[x/sqrN]++;//第x/sqrN个块的元素+1
st.push(x);
}
void del(int x) {//传入栈顶数据并且在对应的块中减少一个数据
table[x]--;//散列表中数据x的元素个数-1
block[x/sqrN]--;
st.pop();
printf("%d\n",x);
}
int main() {
int n;
cin>>n;
string s,s2;
while(n--) {
cin>>s;
if(s=="Push") cin>>s2;
if(s=="Pop") {
if(st.size()==0) printf("Invalid\n");
else del(st.top());
} else if(s=="PeekMedian") {
if(st.size()==0) printf("Invalid\n");
else printf("%d\n",findMedian());
} else {
push(stoi(s2));
}
}
return 0;
}