赞
踩
对于下面的程序任务,vector、deque 和 list 哪种容器最为适合?解释你的选择的理由。如果没有哪一种容器优于其他容器,也请解释理由。
(a)读取固定数量的单词,将它们按字典序插入到容器中。我们将在下一章中看到,关联容器更适合这个问题。
(b)读取未知数量的单词,总是将单词插入到末尾。删除操作在头部进行。
(c)从一个文件读取未知数量的整数。将这些数排序,然后将它们打印到标准输出。
(a)list,需要在中间插入数据,list最好;
(b)deque,需要在头部和尾部插入或删除元素,选 deque;
(c)vector。需要对读入容器中的数量进行排序,而 vector 支持随机访问,更适合用于此任务。
定义一个 list 对象,其元素类型是int 的 deque。
list<deque<int>> lst;
构成迭代器范围的迭代器有何限制?
begin 和 end 必须均指向同一个容器中的元素或尾元素之后的位置,且我们可以通过反复递增 begin 来到达 end ,即 end 不在 begin 之前。
编写函数,接受一对指向 vector< int > 的迭代器和一个 int 值。在两个迭代器指定的范围中查找给定的值,返回一个布尔值来指出是否找到。
#include<iostream> #include<vector> using std::cout; using std::endl; using std::vector; bool findVal(vector<int>::iterator b, vector<int>::iterator e, int i) { while (b!=e) { if (*b == i) { return true; } ++b; } return false; } int main() { vector<int> iv = {0, 1, 2, 3, 4, 5}; int val = 6; bool res = findVal(iv.begin(), iv.end(), val); if (res) { cout << "找到目标值!" << endl; } else { cout << "没有找到目标值!" << endl; } return 0; }
重写上一题的函数,返回一个迭代器指向找到的元素。注意,程序必须处理未找到给定值的情况。
#include<iostream> #include<vector> using std::cout; using std::endl; using std::vector; vector<int>::iterator findVal(vector<int>::iterator b, vector<int>::iterator e, int i) { while (b!=e) { if (*b == i) { return b; } ++b; } return b; } int main() { vector<int> iv = {0, 1, 2, 3, 4, 5}; int val = 4; // bool res = findVal(iv.begin(), iv.end(), val); if (findVal(iv.begin(), iv.end(), val) != iv.end()) { cout << "找到目标值!" << endl; } else { cout << "没有找到目标值!" << endl; } return 0; }
下面程序有何错误?你应该如何修改它?
list<int> lst1;
list<int>::iterator iter1 = lst1.begin(),iter2 = lst1.end();
while (iter1 < iter2) /* ... */
list 不是随机访问容器,因此迭代器没有重载小于运算符,故不能使用小于运算的形式。改为:
iter1 != iter2
为了索引 int 的 vector 中的元素,应该使用什么类型?
vector<int>::size_type
为了读取 string 的 list 中的元素,应该使用什么类型?如果写入 list,又应该使用什么类型?
list<string>::const_iterator //read
list<string>::iterator //write
begin 和 cbegin 两个函数有什么不同?
begin 返回容器的 iterator 类型,当我们需要写访问时使用;
cbegin 返回容器的 const_iterator 类型,当我们不需要写访问时使用。
下面4个对象分别是什么类型?
vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin(), it2 = v2.begin();
auto it3 = v1.cbegin(), it4 = v2.cbegin();
it1 vector<int>::iterator
it2 vector<int>::const_iterator
it3 vector<int>::const_iterator
it4 vector<int>::const_iterator
对 6 种创建和初始化 vector 对象的方法,每一种都给出一个实例。解释每个 vector 包含什么值。
vector<int> v1; // 默认初始化,空
vector<int> v2 = {0,1,2}; // 列表初始化,包含 0、1、2 这三个值
vector<int> v3(3); // 值初始化,包含 3 个 0
vector<int> v4(3,1); // 包含 3 个 1
vector<int> v5 = v4 // 拷贝,包含和 v4 内容相同
vector<int> v6(v5.begin(),v5.end()) // 初始化两个迭代器前后内容的拷贝
对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同。
对于接受一个容器创建其拷贝的构造函数,要求两者的容器类型和元素类型都要相同;
而对于接受两个迭代器创建拷贝的构造函数,不要求容器类型相同,同时,新容器的元素也不必与原容器的元素类型相同,只要可以转换就行。
如何从一个 list 初始化一个 vector?从一个 vector 又该如何创建?编写代码验证你的答案。
#include<iostream> #include<vector> #include<list> using std::cout; using std::endl; using std::list; using std::vector; int main() { vector<int> v{0, 1, 2, 3, 4}; list<int> l{1, 2, 3}; vector<int> v1(l.begin(), l.end()); for(auto i:v1) { cout << i << " "; } cout << endl; vector<int> v2 = v; for(auto i:v2) { cout << i << " "; } cout << endl; vector<double> v3(v.begin(), v.end()); for(auto i:v3) { cout << i << " "; } cout << endl; return 0; }
编写程序,将一个 list 中的 char 指针(指向 C 风格字符串)元素赋值给一个 vector 中的 string。
#include<iostream> #include<list> #include<vector> #include<string> using std::cout; using std::endl; using std::list; using std::string; using std::vector; int main() { list<const char *> lc = {"one", "tow", "three"}; vector<string> v; v.assign(lc.begin(),lc.end()); for(auto i:v) { cout << i << " "; } cout << endl; return 0; }
编写程序,判定两个 vector 是否相等。
#include<iostream> #include<vector> using std::cout; using std::endl; using std::vector; int main() { vector<int> v1 = {0, 1, 2, 3}; vector<int> v2 = {0, 1, 2}; if (v1==v2) { cout << "相等" << endl; } else { cout << "不相等" << endl; } return 0; }
重写上一题的程序,比较一个 list 中的元素和一个 vector 中的元素。
#include<iostream> #include<vector> #include<list> using std::cout; using std::endl; using std::list; using std::vector; int main() { vector<int> v1 = {0, 1, 2, 3}; list<int> l1 = {0, 1, 2, 3}; vector<int> v2(l1.begin(), l1.end()); if (v1 == v2) { cout << "相等" << endl; } else { cout << "不相等" << endl; } return 0; }
假定 c1 和 c2 是两个容器,下面的比较操作有何限制(如果有的话)?
if (c1 < c2)
(1)不能是无序容器;
(2)两容器类型相同,元素类型相同。
编写程序,从标准输入读取 string 序列,存入一个 deque 中。编写一个循环,用迭代器打印 deque 中的元素。
#include<iostream> #include<deque> #include<string> using std::cin; using std::cout; using std::deque; using std::endl; using std::string; int main() { deque<string> dq; string str; while (cin >> str) { dq.push_back(str); } for (auto iter = dq.cbegin(); iter != dq.cend();++iter) { cout << *iter << " "; } cout << endl; return 0; }
重写上题的程序,用 list 替代 deque。列出程序要做出哪些改变。
#include<iostream> #include<list> #include<string> using std::cin; using std::cout; using std::list; using std::endl; using std::string; int main() { list<string> lit; string str; while (cin >> str) { lit.push_back(str); } for (auto iter = lit.cbegin(); iter != lit.cend();++iter) { cout << *iter << " "; } cout << endl; return 0; }
编写程序,从一个 list< int> 拷贝元素到两个 deque 中。值为偶数的所有元素都拷贝到一个 deque 中,而奇数值元素都拷贝到另一个 deque 中。
#include<iostream> #include<list> #include<deque> using std::cout; using std::deque; using std::endl; using std::list; int main() { list<int> lst = {0, 1, 2, 3, 4, 5, 6}; deque<int> dq1, dq2; // for (auto iter = lst.cbegin(); iter != lst.cend(); ++iter) // { // *iter % 2 ? dq1.push_back(*iter) : dq2.push_back(*iter); // } auto iter = lst.cbegin(); while (iter!=lst.cend()) { *iter % 2 ? dq1.push_back(*iter) : dq2.push_back(*iter); ++iter; } for (const auto &s : dq1) { cout << s << " "; } cout << endl; for (const auto &s : dq2) { cout << s << " "; } cout << endl; return 0; }
如果我们将第 308 页中使用 insert 返回值将元素添加到 list 中的循环程序改写为将元素插入到 vector 中,分析循环将如何工作。
与添加到 list 中一样,循环依然等价于调用 push_front(但 vector 本身并不支持),将标准输入的字符依次插入 vector 的头部,但将非常耗时。
假定 iv 是一个 int 的 vector,下面的程序存在什么错误?你将如何修改?
vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size() / 2;
while (iter != mid)
if (*iter == some_val)
iv.insert(iter, 2 * some_val);
(1)循环没有自增,iter 永远是指向开头元素;
(2)假设没有(1)的问题,在插入新元素后,容器的迭代器将会失效,iter 会指向新插入的元素,自增后又指向 some_val,将无限添加。
修改
vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size() / 2;
while (iter != mid)
{
if (*iter == some_val)
{// 插入后跳出循环
iv.insert(iter, 2 * some_val);
break;
}
++iter;
}
在本节第一个程序(第 309 页)中,若 c.size() 为 1,则 val、val2、val3 和 val4 的值会是什么?
都是 c 容器中第一个元素的拷贝。
编写程序,分别使用 at、下标运算符、front 和 begin 提取一个 vector 中的第一个元素。在一个空 vector 上测试你的程序。
#include<iostream> #include<vector> using std::cout; using std::endl; using std::vector; int main() { vector<int> v1; cout << v1.at(0) << endl; cout << v1[0] << endl; cout << v1.front() << endl; cout << *v1.begin() << endl; return 0; }
对于第 312 中删除一个范围内的元素的程序,如果 elem1 与 elem2 相等会发生什么?如果 elem2 是尾后迭代器,或者 elem1 和 elem2 皆为尾后迭代器,又会发生什么?
(1)相等则不删除元素;
(2)elem2 是尾后迭代器,则删除从 elem1 到最后的所有元素;
(3)都为尾后迭代器,则不删除元素。
使用下面代码定义的 ia,将 ia 拷贝到一个 vector 和一个 list 中。使用单迭代器版本的 erase 从 list 中删除奇数元素,从 vector 中删除偶数元素。
int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
#include<iostream> #include<list> #include<vector> using std::cout; using std::endl; using std::list; using std::vector; int main() { int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89}; list<int> lst; vector<int> v; for (auto i : ia) { lst.push_back(i); v.push_back(i); } auto iterL = lst.begin(); while(iterL != lst.end()) { if (*iterL % 2) { iterL = lst.erase(iterL); } else { ++iterL; } } auto iterV = v.begin(); while(iterV != v.end()) { if (*iterV % 2 == 0) { iterV = v.erase(iterV); } else { ++iterV; } } for (const auto i : lst) { cout << i << " "; } cout << endl; for (const auto i : v) { cout << i << " "; } cout << endl; return 0; }
编写程序,查找并删除 forward_list 中的奇数元素。
#include<iostream> #include<forward_list> using std::cout; using std::endl; using std::forward_list; int main() { forward_list<int> flst = {0, 1, 2, 3, 4, 5, 6, 7}; auto prev = flst.before_begin(), curr = flst.begin(); while(curr!=flst.end()) { if (*curr % 2) { curr = flst.erase_after(prev); } else { ++curr; ++prev; } } for (const auto i : flst) { cout << i << " "; } cout << endl; return 0; }
编写函数,接受一个 forward_list 和两个 string 共三个参数。函数应在链表中查找第一个 string,并将第二个 string 插入到紧接着第一个 string 之后的位置。若第一个 string 未在链表中,则将第二个 string 插入到链表末尾。
#include<iostream> #include<string> #include<forward_list> using std::cout; using std::endl; using std::forward_list; using std::string; void insert_str(forward_list<string> &f, const string &s1, const string &s2) { auto prev = f.before_begin(), iter = f.begin(); while(iter!=f.end()) { if (*iter==s1) { iter = f.insert_after(iter, s2); return; } else { prev = iter; ++iter; } } f.insert_after(prev, s2); } int main() { forward_list<string> flst = {"aaa", "bbb", "ddd"}; insert_str(flst, "bbb", "ccc"); for(const auto &i:flst) { cout << i << " "; } cout << endl; insert_str(flst, "eee", "fff"); for(const auto &i:flst) { cout << i << " "; } cout << endl; return 0; }
假定 vec 包含 25 个元素,那么 vec.resize(100) 会做什么?如果接下来调用 vec.resize(10) 会做什么?
(1)将值初始化的 75 个新元素添加到 vec 末尾;
(2)从 vec 的末尾删除 90 个元素。
接受单个参数的 resize 版本对元素类型有什么限制(如果有的话)?
如果元素类型的类类型,则元素类型必须提供一个默认构造函数。
第 316 页中删除偶数值元素并复制奇数值元素的程序不能用于 list 或 forward_list。为什么?修改程序,使之也能用于这些类型。
list 和 forward_list 不支持随机访问元素,迭代器不支持+2运算,因为链表的元素不是连续的随机内存,不能移动固定数字迭代器访问元素。
对于 list 和 forward_list,添加元素后,指向容器的迭代器仍有效;删除元素,指向容器其他位置的迭代器仍有效。
#include<iostream> #include<list> #include<forward_list> using std::cout; using std::endl; using std::forward_list; using std::list; void copy_odd_lst(list<int> &l) { auto iter = l.begin(); while (iter != l.end()) { if (*iter % 2) { l.insert(iter, *iter); ++iter; } else { iter = l.erase(iter); } } for(const auto &i:l) { cout << i << " "; } cout << endl; } void copy_odd_flst(forward_list<int> &f) { auto iter = f.begin(); auto prev = f.before_begin(); while (iter != f.end()) { if (*iter % 2) { f.insert_after(prev, *iter); prev = iter; ++iter; } else { iter = f.erase_after(prev); } } for(const auto &i:f) { cout << i << " "; } cout << endl; } int main() { list<int> lst = {0, 1, 2, 3}; copy_odd_lst(lst); forward_list<int> flst = {4, 5, 6, 7}; copy_odd_flst(flst); return 0; }
在第 316 页的程序中,像下面语句这样调用 insert 是否合法?如果不合法,为什么?
iter = vi.insert(iter, *iter++);
不合法。虽然上面语句可以正常运行,但是由于在 C++ 中并没有指定函数形参的入栈顺序,因此可能是先输入 iter 这个形参,或是先输入 *iter++ 这个形参。对于这两种情况而言,得到的结果将会不同。
在本节最后一例中,如果不将 insert 的结果赋予 begin ,将会发生什么?编写程序,去掉此赋值语句,验证你的答案。
如果容器是 vector 或 string 以及 deque,迭代器将会失效,程序崩溃。如果是 list 将正常运行。
#include<iostream> #include<vector> #include<list> using std::cout; using std::endl; using std::list; using std::vector; int main() { // vector<int> v = {0, 0, 0, 0, 0, 0}; // auto vBegin = v.begin(); // while (vBegin != v.end()) // { // ++vBegin; // // begin = v.insert(begin, 42); // v.insert(vBegin, 42); // ++vBegin; // } // for (const auto &i : v) // { // cout << i << " "; // } // cout << endl; list<int> lst = {1, 1, 1, 1, 1, 1}; auto lsBegin = lst.begin(); while (lsBegin != lst.end()) { ++lsBegin; // begin = v.insert(begin, 42); lst.insert(lsBegin, 42); ++lsBegin; } for (const auto &i : lst) { cout << i << " "; } cout << endl; return 0; }
假定 vi 是一个保存 int 的容器,其中有偶数值也要奇数值,分析下面循环的行为,然后编写程序验证你的分析是否正确。
iter = vi.begin();
while (iter != vi.end())
if (*iter % 2)
iter = vi.insert(iter, *iter);
++iter;
程序本意是希望找到容器中的奇数并复制。然而,当找到第一个奇数时,在这个数前插入这个数的复制值,并将 iter 指向这个新数,++iter 又将 iter 指向原奇数,无限循环。
解释一个 vector 的 capacity 和 size 有何区别。
size 是指现在 vector 已经保存了的元素的数目;
capacity 是指在不分配新内存的情况下,vector 可以存放元素的最大数目。
一个容器的 capacity 可能小于它的 size 吗?
不可能
为什么 list 或 array 没有 capacity 成员函数?
list 不是连续的内存空间;array 是固定的 size 大小。
编写程序,探究在你的标准实现中,vector 是如何增长的。
#include<iostream> #include<vector> using std::cin; using std::cout; using std::endl; using std::vector; int main() { vector<int> iv; cout << iv.size() << " " << iv.capacity() << endl; int a; while (cin>>a) { iv.push_back(a); cout << iv.size() << " " << iv.capacity() << endl; } return 0; }
解释下面程序片段做了什么:
vector<string> svec;
svec.reserve(1024);
string word;
while (cin >> word)
svec.push_back(word);
svec.resize(svec.size() + svec.size() / 2);
为 svec 申请 1024 个元素内存空间,输入的字符串存入 svec,最后将 vec 扩大元素个数的 0.5 被。
如果上一题的程序读入了 256 个词,在 resize 之后容器的 capacity 可能是多少?如果读入了 512 个、1000 个、或 1048 个呢?
256、512 个:resize 之后没有超过预留空间 1024,则 capacity 没变化;
1000 个:resize 之后超过预留空间 1024 ,则 capacity 会增大不低于 1500;
1024 个:resize 之后超过预留空间 1024 ,则 capacity 会增大不低于 1536。
编写程序,从一个 vector 初始化一个 string。
#include<iostream> #include<vector> #include<string> using std::cout; using std::endl; using std::string; using std::vector; int main() { vector<char> cp{'H', 'i', ' ', 'C', '+', '+'}; string str(cp.begin(), cp.end()); for(const auto &s:str) { cout << s << " "; } cout << endl; return 0; }
假定你希望每次读取一个字符存入一个 string 中,而且知道最少需要读取 100 个字符,应该如何提高程序的性能?
string s;
s.reserve(100);
编写一个函数,接受三个 string 参数是 s、oldVal 和 newVal。使用迭代器及 insert 和 erase 函数将 s 中所有 oldVal 替换为 newVal。测试你的程序,用它替换通用的简写形式,如,将 “tho” 替换为 ”though“,将 “thru” 替换为 “through”。
#include<iostream> #include<string> using std::cout; using std::endl; using std::string; void replace_str(string &s, const string &oldVal, const string &newVal) { auto iter = s.begin(); auto len = oldVal.size(); while (iter!=s.end()) { if (oldVal == string(iter, iter + len)) { iter = s.erase(iter, iter + len); iter = s.insert(iter, newVal.begin(), newVal.end()); iter += len; } else { ++iter; } } } int main() { string str("tho thru"); replace_str(str, "tho", "though"); replace_str(str, "thru", "thrugh"); cout << str << endl; return 0; }
重写上一题的函数,这次使用一个下标和 replace。
#include<iostream> #include<string> using std::cout; using std::endl; using std::string; void replace_str(string &s, const string &oldVal, const string &newVal) { string::size_type pos = 0; auto len = oldVal.size(); while (pos != s.size()) { if (oldVal == string(s, pos, len)) { s.replace(pos, len, newVal); } ++pos; } } int main() { string str("tho thru"); replace_str(str, "tho", "though"); replace_str(str, "thru", "thrugh"); cout << str << endl; return 0; }
编写一个函数,接受一个表示名字的 string 参数和两个分别表示前缀(如"Mr.“或"Ms.”)和后缀(如"Jr.“或"III”)的字符串。使用迭代器及 insert和 append 函数将前缀和后缀添加到给定的名字中,将生成的新 string 返回。
#include<iostream> #include<string> using std::cout; using std::endl; using std::string; string name_add(string &n, const string &pre, const string &post) { n.insert(n.begin(), pre.begin(),pre.end()); n.append(post); return n; } int main() { string name = "Johe"; cout << name_add(name, "Mr.", "III") << endl; return 0; }
重写上一题的函数,这次使用位置和长度来管理 string,并只使用 insert。
#include<iostream> #include<string> using std::cout; using std::endl; using std::string; string name_add(string &n, const string &pre, const string &post) { n.insert(0, pre); n.insert(n.size(), post); return n; } int main() { string name = "Johe"; cout << name_add(name, "Mr.", "III") << endl; return 0; }
编写程序,首先查找 string"ab2c3d7R4E6" 中每个数字字符,然后查找其中每个字母字符。编写两个版本的程序,第一个要使用 find_first_of,第二个要使用 find_first_not_of。
#include<iostream> #include<string> using std::cout; using std::endl; using std::string; void find_num1(const string &str, const string &num) { string::size_type pos = 0; while ((pos = str.find_first_of(num, pos)) != string::npos) { cout << "found number at index: " << pos << ", element is " << str[pos] << endl; ++pos; } } void find_num2(const string &str, const string &let) { string::size_type pos = 0; while ((pos = str.find_first_not_of(let, pos)) != string::npos) { cout << "found number at index: " << pos << ", element is " << str[pos] << endl; ++pos; } } void find_let1(const string &str, const string &let) { string::size_type pos = 0; while ((pos = str.find_first_of(let, pos)) != string::npos) { cout << "found letter at index: " << pos << ", element is " << str[pos] << endl; ++pos; } } void find_let2(const string &str, const string &num) { string::size_type pos = 0; while ((pos = str.find_first_not_of(num, pos)) != string::npos) { cout << "found letter at index: " << pos << ", element is " << str[pos] << endl; ++pos; } } int main() { string s("ab2c3d7R4E6"); string numbers{"123456789"}; string letters{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"}; find_num1(s, numbers); find_let1(s, letters); cout << endl; find_num2(s, letters); find_let2(s, numbers); return 0; }
假定 name 和 numbers 的定义如 325 页所示,numbers.find(name) 返回什么?
string::npos
如果一个字母延伸到中线之上,如 d 或 f,则称其有上出头部分(ascender)。如果一个字母延伸到中线之下,如p或g,则称其有下出头部分(descender)。编写程序,读入一个单词文件,输出最长的既不包含上出头部分,也不包含下出头部分的单词。
#include<iostream> #include<string> #include<fstream> using std::cerr; using std::cout; using std::endl; using std::ifstream; using std::string; int main() { ifstream in("words.txt"); string word, result; if (in) { while (in>>word) { if (word.find_first_of("bdfghijklpqty") == string::npos && word.size() > result.size()) { result = word; } } }else { cerr << "无法打开文件 words.txt" << endl; return 0; } cout << "最长的既不包含上出头部分,也不包含下出头部分的单词是: " << result << endl; return 0; }
编写程序处理一个 vector< string>,其元素都表示整型值。计算 vector 中所有元素之和。修改程序,使之计算表示浮点值的 string 之和。
#include<iostream> #include<vector> #include<string> using std::cout; using std::endl; using std::string; using std::vector; int main() { vector<string> iv = {"0", "1", "2", "3", "4", "5", "6"}; int sum_int = 0; for(const auto s:iv) { sum_int += stoi(s); } cout << sum_int << endl; vector<string> dv(5, "4.56"); double sum_dou = 0.0; for(const auto s:dv) { sum_dou += stod(s); } cout << sum_dou << endl; return 0; }
设计一个类,它有三个 unsigned 成员,分别表示年、月和日。为其编写构造函数,接受一个表示日期的 string 参数。你的构造函数应该能处理不同的数据格式,如 January 1,1900、1/1/1990、Jan 1 1900 等。
#include<iostream> #include<string> #include<vector> using std::cout; using std::endl; using std::string; using std::vector; class Date { private: unsigned year; unsigned month; unsigned day; public: Date(const string &); }; Date::Date(const string &s) { // 24/1/2019 格式 if (s.find("/") != string::npos) { string::size_type pre = s.find_first_of("/"); string::size_type post = s.find_last_of("/"); day = stoi(s.substr(0, pre)); month = stoi(s.substr(pre + 1, post - 1 - pre)); year = stoi(s.substr(post + 1)); } // September 23,2018 格式 else if (s.find(",") != string::npos) { string::size_type blank = s.find_first_of(" "); string::size_type comma = s.find_first_of(","); day = stoi(s.substr(blank + 1, comma - 1 - blank)); year = stoi(s.substr(comma + 1)); vector<string> mons = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; for (size_t i = 0; i != s.size(); ++i) { if (s.find(mons[i]) != string::npos) { month = i + 1; break; } } } // May 1 2020 格式 else { string::size_type preBlank = s.find_first_of(" "); string::size_type postBlank = s.find_last_of(" "); day = stoi(s.substr(preBlank + 1, postBlank - 1 - preBlank)); year = stoi(s.substr(postBlank + 1)); vector<string> mons = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; for (size_t i = 0; i != s.size(); ++i) { if (s.find(mons[i]) != string::npos) { month = i + 1; break; } } } cout << year << " 年 " << month << " 月 " << day << " 日" << endl; } int main() { Date date1("24/1/2019"); Date date2("September 23,2018"); Date date3("May 1 2020"); return 0; }
使用 stack 处理括号化的表达式。当你看到一个左括号,将其记录下来。当你在一个左括号之后看到一个右括号,从 stack 中 pop 对象,直至遇到左括号,将左括号也一起弹出栈。然后将一个值(括号内的运算结果)push 到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果所替代。
傻了,这不是要做个计算器?网上找了一个
#include<iostream> #include<queue> #include<vector> #include<cstring> #include<stack> using namespace std; vector<string>prase(char *str) //分离每个符号 { vector<string>tokens; int len = strlen(str); char *p = (char*)malloc((len + 1) * sizeof(char)); int i = 0, j = 0; while (i < len) //去除空格 { if (str[i] == ' ') { i++; continue; } p[j++] = str[i++]; } p[j] = '\0'; j = 0; len = strlen(p); while (j < len) { char temp[2] = { 0 }; //存储符号 string token; switch (p[j]) { case '+': case '*': case '/': case '(': case ')': temp[0] = p[j]; temp[1] = '\0'; token = temp; tokens.push_back(token); break; case '-': if (p[j - 1] == ')' || isdigit(p[j - 1])) //不能使用--j,会死循环 { temp[0] = p[j]; temp[1] = '\0'; token = temp; tokens.push_back(token); break; } else { temp[0] = '$'; temp[1] = '\0'; token = temp; tokens.push_back(token); break; } default: i = j; while (isdigit(p[i])) i++; char *operand = (char*)malloc((i - j + 1) * sizeof(char)); memset(operand, 0, i - j + 1); memcpy(operand, p + j, i - j); operand[i - j] = '\0'; token = operand; tokens.push_back(token); free(operand); j = i - 1; break; } j++; } free(p); return tokens; } int priority(string opd) { int level; if (opd == "$") level = 3; else if (opd == "*" || opd == "/") level = 2; else if (opd == "+" || opd == "-") level = 1; else if (opd == "(" || opd == ")") level = 0; return level; } void calculate(stack<int>& opdStack, string opt) { if (opt == "+") { int rOpd = opdStack.top(); opdStack.pop(); int lOpd = opdStack.top(); opdStack.pop(); int result = rOpd + lOpd; opdStack.push(result); } else if (opt == "-") { int rOpd = opdStack.top(); opdStack.pop(); int lOpd = opdStack.top(); opdStack.pop(); int result = lOpd - rOpd; opdStack.push(result); } else if (opt == "*") { int rOpd = opdStack.top(); opdStack.pop(); int lOpd = opdStack.top(); opdStack.pop(); int result = lOpd * rOpd; opdStack.push(result); } else if (opt == "/") { int rOpd = opdStack.top(); opdStack.pop(); int lOpd = opdStack.top(); opdStack.pop(); int result = lOpd / rOpd; opdStack.push(result); } else if (opt == "$") { int result = opdStack.top(); opdStack.pop(); result = -result; opdStack.push(result); } } int computationalExp(char *str) { vector<string>tokens = prase(str); stack<int>opdStack; stack<string>optStack; for (int i = 0; i < tokens.size(); i++) { string token = tokens[i]; if (token == "+" || token == "-" || token == "*" || token == "/" || token == "$") { if (optStack.empty()) { optStack.push(token); } else { int tokenPriority = priority(token); string topOptStack = optStack.top(); int optPriority = priority(topOptStack); if (tokenPriority > optPriority) //运算操作符优先于栈顶操作符,则入栈 { optStack.push(token); } else {//否则弹出操作符和操作数进行计算,直至当前操作符优先栈顶操作符时,入栈 while (tokenPriority <= optPriority) { calculate(opdStack, topOptStack); optStack.pop(); if (optStack.size() > 0) { topOptStack = optStack.top(); optPriority = priority(topOptStack); } else { break; } } optStack.push(token); } } } else if (token == "(") { optStack.push(token); } else if (token == ")") { while (optStack.top() != "(") { string topOpt = optStack.top(); calculate(opdStack, topOpt); optStack.pop(); } optStack.pop();//弹出"(" } else { opdStack.push(stoi(token));//操作数入栈 } } while (optStack.size() != 0) { string topOpt = optStack.top(); calculate(opdStack, topOpt); optStack.pop(); } return opdStack.top(); } int main() { char *str = "3+5-6*-9/3+(4+3*7)"; cout << computationalExp(str) << endl; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。