第五章 数据结构一(向量、队列、栈) 共8道题
part 1 向量
例题5.1 完数和盈数
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdio>
#include <vector>
using namespace std;
int SumOfFactor(int num) {
vector<int> factor;
int result = 0;
for (int i = 1; i < num; ++i) {
if (num % i == 0) {
factor.push_back(i);
}
}
for (int i = 0; i < factor.size(); ++i) {
result += factor[i];
}
return result;
}
int main() {
vector<int> E, G;
for (int i = 2; i <= 60; ++i) {
if (i == SumOfFactor(i)) {
E.push_back(i);
}
if (i < SumOfFactor(i)) {
G.push_back(i);
}
}
printf("E:");
for (int i = 0; i < E.size(); ++i) {
printf(" %d", E[i]);
}
printf(" G:");
for (int i = 0; i < G.size(); ++i) {
printf(" %d", G[i]);
}
return 0;
}
- 数组的限制:必须在创建数组时确定其大小 -->向量:变长数组(向量的容量大于元素所需的实际容量,重新分配数组时,数组的大小呈双倍增长)
- 向量基础
#include <vector>
vector<typename> name; // 定义
name.empty() name.size() //是否为空,返回元素个数
name.push_back() name.pop_pack() // 尾部添加、删除元素
name.insert(pos, ele) erase() clear() // 在某个位置插入,删除 清空向量
name.begin() end() // 首元素迭代器,尾元素后一个位置的迭代器
part 2 队列
例题5.2 约瑟夫问题NO.2
约瑟夫问题No.2_vjudge
约瑟夫问题No.2_poj-openjudge-百炼oj
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdio>
#include <queue>
using namespace std;
int main() {
int n, p, m; // n个小孩 从p开始顺时针报数,到m出圈
while (scanf("%d %d %d", &n, &p, &m) != EOF) {
if (n == 0 && p == 0 && m == 0) {
break;
}
queue<int> kids;
for (int i = 1; i <= n; ++i) {
kids.push(i);
}
for (int i = 0; i < p - 1; ++i) {
kids.push(kids.front());
kids.pop();
}
while (!kids.empty()) {
for (int i = 0; i < m - 1; ++i) {
kids.push(kids.front());
kids.pop();
}
if (kids.size() == 1) {
printf("%d\n", kids.front());
}
else {
printf("%d,", kids.front());
}
kids.pop();
}
}
return 0;
}
- 队列:先进先出;队尾插入,队头删除
- 队列基础
#include <queue>
queue<typename> name; //定义
name.empty() name.size() //是否为空,返回元素个数
name.push() name.pop() // 添加、删除元素
name.front() name.back() //获取队头,队尾元素
- 利用queue队列模拟循环队列:将队首元素重新压入队尾,再弹出
说句题外话,会断点debug之后,感觉自己写的bug真的是脑瘫bug
例题5.3 猫狗收容所
INPUT:
6 1 1 1 -1 2 0 1 2 2 -1 2 1
OUTPUT:
1 -1 2
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdio>
#include <queue>
using namespace std;
struct animal {
int order;
int type;
animal(int t, int o): type(t), order(o){
}
};
int main() {
int n;
int order = 0;
queue<animal> cats;
queue<animal> dogs;
scanf("%d", & n);
for (int i = 0; i < n; ++i) {
int m, t;
scanf("%d %d", &m, &t);
if (m == 1) {
if (t > 0) {
dogs.push(animal(t, order++));
}
else {
cats.push(animal(t, order++));
}
}
else {
if (t == 0 && !dogs.empty() && !cats.empty()) {
if (dogs.front().order < cats.front().order) {
printf("%d ", dogs.front().type);
dogs.pop();
}
else {
printf("%d ", cats.front().type);
cats.pop();
}
}
else if (t == 0 && dogs.empty() && !cats.empty()) {
printf("%d ", cats.front().type);
cats.pop();
}
else if (t == 0 && !dogs.empty() && cats.empty()) {
printf("%d ", dogs.front().type);
dogs.pop();
}
else if (t == 1 && !dogs.empty()) {
printf("%d ", dogs.front().type);
dogs.pop();
}
else if(t == -1 && !cats.empty()) {
printf("%d ", cats.front().type);
cats.pop();
}
}
}
return 0;
}
- 如果需要在队列里push一个自己创建的结构体,需要声明结构体的构造函数。
- 猫狗队列需要判断元素都不为零/有一方为0情况时的操作,考虑判断条件时应全面,尤其是特殊情况的考虑!(根据情况、题目条件权衡具体判断到多细致)
part 3 栈
例题5.4 Zero-complexity Transposition
KY109 Zero-complexity Transposition
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
stack<string> list;
for (int i = 0; i < n; ++i) {
string str;
cin >> str;
list.push(str);
}
while (!list.empty()) {
if (list.size() != 1) {
cout << list.top() << " ";
list.pop();
}
else {
cout << list.top() << endl;
list.pop();
}
}
}
return 0;
}
- 栈只能由栈顶进行操作,后进先出
- 栈基础
#include <stack>
stack<typename> name; //栈的定义
name.empty() name.size() //是否为空,返回元素个数
name.push() name.pop() // 添加、删除元素
name.top() // 栈顶元素
- 本题输入超出32位整型int示数(最大值 2的31次方 - 1 214748364)范围,也可以利用64位整型long long(最大值 2的64次方 - 1),其输入格式如下:(也可以直接用cin,系统之间没有差异)
例题5.5 括号匹配问题
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <string>
#include <stack>
using namespace std;
int main() {
string str;
while (cin >> str) {
string ans(str.size(), ' ');
stack<int> leftbrackets;
for(int i = 0; i < str.size(); ++i){
if (str[i] == '(') {
leftbrackets.push(i);
}
else if (str[i] == ')') {
if (!leftbrackets.empty()) {
leftbrackets.pop(); // 匹配上了pop
}
ans[i] = '?';
}
}
while (!leftbrackets.empty()) {
ans[leftbrackets.top()] = '$';
leftbrackets.pop();
}
cout << str << endl;
cout << ans << endl;
}
return 0;
}
- string初始化,string( size_type length, char ch ),length个ch初始化
#include<bits/stdc++.h>
c++万能头文件,包含了目前c++所包含的所有头文件。有的oj支持有的不支持,vs是不支持万能头的,需要我们自己去手动添加。(tips:新手敲代码不要图方便使用万能头噢~)- 栈用来存左括号的下标,在最终判断左括号时就可以直接取下标输出了。
例题5.6 简单计算器
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <cstdio>
#include <string>
#include <stack>
#include <cctype>
using namespace std;
double GetNumber(string str, int& index) {
double num = 0;
while (isdigit(str[index])) {
num = num * 10 + str[index] - '0';
index++;
}
return num;
}
int Priority(char c) {
if (c == '#') {
return 0;
}
else if (c == '$') {
return 1;
}
else if (c == '+' || c == '-') {
return 2;
}
else {
return 3;
}
}
double Calculate(double a, double b, char oper) {
if (oper == '+') {
return a + b;
}
else if (oper == '-') {
return a - b;
}
else if (oper == '*') {
return a * b;
}
else {
return a / b;
}
}
int main() {
string str;
while (getline(cin, str)) {
if (str == "0") {
break;
}
int index = 0;
stack<char> oper;
stack<double> data;
str += '$';
oper.push('#');
while (index < str.size()) {
if (str[index] == ' ') {
index++;
}
else if (isdigit(str[index])) {
data.push(GetNumber(str, index));
}
else {
if (Priority(str[index]) > Priority(oper.top())) {
oper.push(str[index]);
index++;
}
else {
double y = data.top();
data.pop();
double x = data.top();
data.pop();
char op = oper.top();
oper.pop();
data.push(Calculate(x, y, op));
}
}
}
printf("%.2f\n", data.top());
}
return 0;
}
- cctype头文件,该库的功能:负责字符分类功能
如isalpha()
和字符转换功能如tolower()
,isdigit() : Check if character is decimal digit - 当运算符栈顶元素的优先级大于当前位置运算符的优先级时,将栈顶运算符和最近进栈的两个数进行运算(注意运算符顺序,pop出来是逆序)
- #表示最低优先级,最先入栈,为了将表达式的第一个符号压入;$倒数第二优先级,为了将式中的最低优先级符号进行运算。
- 运算后不需要移动index!!这样才能持续的计算
习题5.1 堆栈的使用
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdio>
#include <stack>
using namespace std;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
if (n == 0) {
break;
}
char mode;
stack<int> num;
for (int i = 0; i < n; ++i) {
scanf(" %c", &mode);
if (mode == 'P') {
int a;
scanf(" %d", &a);
num.push(a);
}
else if (mode == 'O') {
if (!num.empty()) {
num.pop();
}
}
else if(mode == 'A'){
if (!num.empty()) {
printf("%d\n", num.top());
}
else {
printf("E\n");
}
}
}
printf("\n");
}
return 0;
}
- while大循环中读取整数n的scanf(%d)能识别
\n
但不能消除\n
,后续如果接scanf(%c)读取的是\n,可以用getchar()来消除,也可以直接用cin - 对于scanf()而言,读取字符%c很特殊。
- %c前不加空格,scanf将读取标准输入流中的第一个字符
- %c前加空格,scanf将读取标准输入流中第一个非空白字符,可以实现屏蔽空白字符的作用
习题5.2 计算表达式
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <cstdio>
#include <stack>
#include <string>
#include <cctype>
using namespace std;
double GetNumber(string str, int& index) {
double num = 0;
while (isdigit(str[index])) {
num = num * 10 + str[index] - '0';
index++;
}
return num;
}
int Priority(char c) {
if (c == '#') {
return 0;
}
else if (c == '$') {
return 1;
}
else if (c == '+' || c == '-') {
return 2;
}
else {
return 3;
}
}
double Calculate(double x, double y, char oper) {
if (oper == '+') {
return x + y;
}
else if (oper == '-') {
return x - y;
}
else if (oper == '*') {
return x * y;
}
else {
return x / y;
}
}
int main() {
string str;
while (getline(cin, str)) {
stack<double> data;
stack<char> oper;
int index = 0;
str += '$';
oper.push('#');
while (index < str.size()) {
if (isdigit(str[index])) {
data.push(GetNumber(str, index));
}
else {
if (Priority(str[index]) > Priority(oper.top())) {
oper.push(str[index]);
index++;
}
else {
double y = data.top();
data.pop();
double x = data.top();
data.pop();
data.push(Calculate(x, y, oper.top()));
oper.pop();
}
}
}
printf("%d\n", int(data.top()));
data.pop();
}
return 0;
}