Третья неделя обучения на coursera.org
Структуры и классы - интересная тема. Некоторые задания долго разбирал.
Для начала маленькое задание:
Реализуйте класс, поддерживающий набор строк в отсортированном порядке. Класс должен содержать два публичных метода:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
| class SortedStrings {
public:
void AddString(const string& s) {
// добавить строку s в набор
}
vector<string> GetSortedStrings() {
// получить набор из всех добавленных строк в отсортированном порядке
}
private:
// приватные поля
}; |
|
Пример:
Код
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| void PrintSortedStrings(SortedStrings& strings) {
for (const string& s : strings.GetSortedStrings()) {
cout << s << " ";
}
cout << endl;
}
int main() {
SortedStrings strings;
strings.AddString("first");
strings.AddString("third");
strings.AddString("second");
PrintSortedStrings(strings);
strings.AddString("second");
PrintSortedStrings(strings);
return 0;
} |
|
Вывод
| C++ | 1
2
| first second third
first second second third |
|
Моё решение:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class SortedStrings {
public:
void AddString(const string& s) {
v.push_back(s); //добавим строку
}
vector<string> GetSortedStrings() {
sort(begin(v), end(v)); //отсортируем вектор строк
return v; //и вернем вектор
}
private:
vector<string> v; //так будут строки храниться
}; |
|
Следующее задание: Имена и фамилии
Реализуйте класс для человека, поддерживающий историю изменений человеком своих фамилии и имени.
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| class Person {
public:
void ChangeFirstName(int year, const string& first_name) {
// добавить факт изменения имени на first_name в год year
}
void ChangeLastName(int year, const string& last_name) {
// добавить факт изменения фамилии на last_name в год year
}
string GetFullName(int year) {
// получить имя и фамилию по состоянию на конец года year
}
private:
// приватные поля
}; |
|
Считайте, что в каждый год может произойти не более одного изменения фамилии и не более одного изменения имени. При этом с течением времени могут открываться всё новые факты из прошлого человека, поэтому года́ в последовательных вызовах методов ChangeLastName и ChangeFirstName не обязаны возрастать.
Гарантируется, что все имена и фамилии непусты.
Строка, возвращаемая методом GetFullName, должна содержать разделённые одним пробелом имя и фамилию человека по состоянию на конец данного года.
Если к данному году не случилось ни одного изменения фамилии и имени, верните строку "Incognito".
Если к данному году случилось изменение фамилии, но не было ни одного изменения имени, верните "last_name with unknown first name".
Если к данному году случилось изменение имени, но не было ни одного изменения фамилии, верните "first_name with unknown last name".
Пример
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| int main() {
Person person;
person.ChangeFirstName(1965, "Polina");
person.ChangeLastName(1967, "Sergeeva");
for (int year : {1900, 1965, 1990}) {
cout << person.GetFullName(year) << endl;
}
person.ChangeFirstName(1970, "Appolinaria");
for (int year : {1969, 1970}) {
cout << person.GetFullName(year) << endl;
}
person.ChangeLastName(1968, "Volkova");
for (int year : {1969, 1970}) {
cout << person.GetFullName(year) << endl;
}
return 0;
} |
|
Вывод
| C++ | 1
2
3
4
5
6
7
| Incognito
Polina with unknown last name
Polina Sergeeva
Polina Sergeeva
Appolinaria Sergeeva
Polina Volkova
Appolinaria Volkova |
|
Моё решение:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| #include <iostream>
#include <string>
#include <map>
using namespace std;
struct FullName { //создадим структуру из имени и фамилии
string Name;
string Soname;
};
class Person {
public:
void ChangeFirstName(int year, const string& first_name) {
if (YearNameSoname.count(year) == 0) YearNameSoname[year].Soname = ""; //если такого года еще нет, то добавим пустую фамилию в этот год
YearNameSoname[year].Name = first_name; //добавим указанное имя
}
void ChangeLastName(int year, const string& last_name) {
if (YearNameSoname.count(year) == 0) YearNameSoname[year].Name = ""; //если такого года еще нет, то добавим пустое имя в этот год
YearNameSoname[year].Soname = last_name; //и добавим указанную фамилию
}
string GetFullName(int year) {
if (YearNameSoname.size() == 0) { //если размер = 0
return "Incognito"; //выводим Инкогнито
}
else { //ну или так
for (const auto& i : YearNameSoname) {
if (year < i.first) return "Incognito"; //если искомый год меньше первого года изменения, выводим Инкогнито
break; //сразу выходим из цикла
}
}
//иначе
string nm = "";
string sn = "";
for (const auto& i : YearNameSoname) { //полистаем нашу структуру, (не стал отдельно функцию делать)
//и будем присваивать переменной sn значение фамилии, если она не пустая и пока искомый год больше текущего(в структуре)
if (i.first <= year && i.second.Soname != "") sn = i.second.Soname;
//тоже самое с именем
if (i.first <= year && i.second.Name != "") nm = i.second.Name;
}
if(nm == "") return sn + " with unknown first name"; //условие, если имя пустое(вывод фамилии и текста)
else if(sn == "") return nm + " with unknown last name"; //условие, если фамилия пуста (вывод имени и текста)
else return nm + " " + sn; //вывод имени и фамилии
}
private: //объявим в приватной секции
map<int, FullName> YearNameSoname; //структуру с годом и полным именем
}; |
|
Ещё задача:
Дополните класс из предыдущей задачи «Имена и фамилии — 1» методом GetFullNameWithHistory:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| class Person {
public:
void ChangeFirstName(int year, const string& first_name) {
// добавить факт изменения имени на first_name в год year
}
void ChangeLastName(int year, const string& last_name) {
// добавить факт изменения фамилии на last_name в год year
}
string GetFullName(int year) {
// получить имя и фамилию по состоянию на конец года year
}
string GetFullNameWithHistory(int year) {
// получить все имена и фамилии по состоянию на конец года year
}
private:
// приватные поля
}; |
|
В отличие от метода GetFullName, метод GetFullNameWithHistory должен вернуть не только последние имя и фамилию к концу данного года, но ещё и все предыдущие имена и фамилии в обратном хронологическом порядке. Если текущие факты говорят о том, что человек два раза подряд изменил фамилию или имя на одно и то же, второе изменение при формировании истории нужно игнорировать.
Пример:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| int main() {
Person person;
person.ChangeFirstName(1965, "Polina");
person.ChangeLastName(1967, "Sergeeva");
for (int year : {1900, 1965, 1990}) {
cout << person.GetFullNameWithHistory(year) << endl;
}
person.ChangeFirstName(1970, "Appolinaria");
for (int year : {1969, 1970}) {
cout << person.GetFullNameWithHistory(year) << endl;
}
person.ChangeLastName(1968, "Volkova");
for (int year : {1969, 1970}) {
cout << person.GetFullNameWithHistory(year) << endl;
}
person.ChangeFirstName(1990, "Polina");
person.ChangeLastName(1990, "Volkova-Sergeeva");
cout << person.GetFullNameWithHistory(1990) << endl;
person.ChangeFirstName(1966, "Pauline");
cout << person.GetFullNameWithHistory(1966) << endl;
person.ChangeLastName(1960, "Sergeeva");
for (int year : {1960, 1967}) {
cout << person.GetFullNameWithHistory(year) << endl;
}
person.ChangeLastName(1961, "Ivanova");
cout << person.GetFullNameWithHistory(1967) << endl;
return 0;
} |
|
Вывод:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
| Incognito
Polina with unknown last name
Polina Sergeeva
Polina Sergeeva
Appolinaria (Polina) Sergeeva
Polina Volkova (Sergeeva)
Appolinaria (Polina) Volkova (Sergeeva)
Polina (Appolinaria, Polina) Volkova-Sergeeva (Volkova, Sergeeva)
Pauline (Polina) with unknown last name
Sergeeva with unknown first name
Pauline (Polina) Sergeeva
Pauline (Polina) Sergeeva (Ivanova, Sergeeva) |
|
Моё решение:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
| #include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
struct FullName { //создадим структуру из имени и фамилии
string Name;
string Soname;
};
class Person {
public:
void ChangeFirstName(int year, const string& first_name) {
if (YearNameSoname.count(year) == 0) YearNameSoname[year].Soname = ""; //если такого года еще нет, то добавим пустую фамилию
YearNameSoname[year].Name = first_name; //добавим указанное имя
}
void ChangeLastName(int year, const string& last_name) {
if (YearNameSoname.count(year) == 0) YearNameSoname[year].Name = ""; //если такого года еще нет, то добавим пустое имя
YearNameSoname[year].Soname = last_name; //и добавим указанную фамилию
}
string GetFullName(int year) {
if (YearNameSoname.size() == 0) { //если размер = 0
return "Incognito"; //выводим Инкогнито
}
else {
for (const auto& i : YearNameSoname) {
if (year < i.first) return "Incognito"; //если искомый год меньше первого года изменения, выводим Инкогнито
break; //сразу выходим из цикла
}
}
//иначе
string nm = "";
string sn = "";
for (const auto& i : YearNameSoname) { //полистаем нашу структуру
//и будем присваивать переменной sn значение фамилии, если она не пустая и пока искомый год больше текущего(в структуре)
if (i.first <= year && i.second.Soname != "") sn = i.second.Soname;
if (i.first <= year && i.second.Name != "") nm = i.second.Name; //тоже самое с именем
}
if(nm == "") return sn + " with unknown first name"; //условие, если имя пустое(вывод фамилии и текста)
else if(sn == "") return nm + " with unknown last name"; //условие, если фамилия пуста (вывод имени и текста)
else return nm + " " + sn; //вывод имени и фамилии
}
string GetFullNameWithHistory(int year) {
if (YearNameSoname.size() == 0) { //если размер = 0
return "Incognito"; //выводим Инкогнито
}
else {
for (const auto& i : YearNameSoname) {
if (year < i.first) return "Incognito"; //если искомый год меньше первого года изменения, выводим Инкогнито
break; //сразу выходим из цикла
}
}
//иначе
string nm = "";
string sn = "";
vector<string> secondnames; //вектор предыдущих фамилий
vector<string> firstnames; //вектор предыдущих имен
for (const auto& i : YearNameSoname) { //полистаем нашу структуру
//и будем присваивать переменной sn значение фамилии, если она не пустая и пока искомый год больше текущего(в структуре)
if (i.first <= year && i.second.Soname != "") { //если Фамилия непуста
if (i.second.Soname != sn && sn != "") { //и не повторяется
secondnames.push_back(sn);
}
sn = i.second.Soname; //тут присваиваем
}
if (i.first <= year && i.second.Name != "") { //то же самое с Именем
if (i.second.Name != nm && nm != "") {
firstnames.push_back(nm);
}
nm = i.second.Name;
}
}
//инициализируем переменные в которые будем складывать фамилии и имена в обратном порядке
string secnames_string = "", firstnames_string = "";
if (secondnames.size() > 0) { //если вектор с фамилиями не пуст, то
secnames_string += " (" + secondnames[secondnames.size() - 1]; //добавим в строку пробел, скобку и предыдущую фамилию
if (secondnames.size() > 1) {
for (int i = secondnames.size() - 1; i > 0; --i) {//в обратном порядке
secnames_string += ", " + secondnames[i - 1]; // добавим в строку остальные фамилии
}
}
secnames_string += ")"; //закроем строку скобкой
}
//аналогично с именами
if (firstnames.size() > 0) {
firstnames_string += " (" + firstnames[firstnames.size() - 1];
if (firstnames.size() >1) {
for (int i = firstnames.size() - 1; i > 0; --i) {
firstnames_string += ", " + firstnames[i - 1];
}
}
firstnames_string += ")";
}
//в зависимости от наличия Имени и Фамилии, вернем соответствующие сообщения
if (nm == "") return sn + secnames_string + " with unknown first name";
else if (sn == "") return nm + firstnames_string + " with unknown last name";
else return nm + firstnames_string + " " + sn + secnames_string;
}
private: //объявим в приватной секции
map<int, FullName> YearNameSoname; //структуру с годом и полным именем
}; |
|
Немного переборщил с кодом. Но думаю для собственного понимания пойдет. Можете предложить свою оптимизацию )))
Ещё задача:
Дополните класс Person из задачи «Имена и фамилии — 2» конструктором, позволяющим задать имя и фамилию человека при рождении, а также сам год рождения. Класс не должен иметь конструктора по умолчанию.
При получении на вход года, который меньше года рождения:- методы GetFullName и GetFullNameWithHistory должны отдавать "No person";
- методы ChangeFirstName и ChangeLastName должны игнорировать запрос.
Кроме того, необходимо объявить константными все методы, которые по сути ими являются.
Пример:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| int main() {
Person person("Polina", "Sergeeva", 1960);
for (int year : {1959, 1960}) {
cout << person.GetFullNameWithHistory(year) << endl;
}
person.ChangeFirstName(1965, "Appolinaria");
person.ChangeLastName(1967, "Ivanova");
for (int year : {1965, 1967}) {
cout << person.GetFullNameWithHistory(year) << endl;
}
return 0;
} |
|
Вывод:
| C++ | 1
2
3
4
| No person
Polina Sergeeva
Appolinaria (Polina) Sergeeva
Appolinaria (Polina) Ivanova (Sergeeva) |
|
Моё решение:
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
| #include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
struct FullName { //создадим структуру из имени и фамилии
string Name;
string Soname;
};
class Person {
public:
Person(const string& first_name, const string& last_name, int year) {
YearNameSoname[year] = { first_name, last_name };
birth_year = year;
for (auto& i : YearNameSoname) {
if (i.first < year) YearNameSoname.erase(i.first);
}
}
void ChangeFirstName(int year, const string& first_name) {
for (auto& i : YearNameSoname) {
if (year > i.first) {
if (YearNameSoname.count(year) == 0) YearNameSoname[year].Soname = ""; //если такого года еще нет, то добавим пустую фамилию
YearNameSoname[year].Name = first_name; //добавим указанное имя
}
break;//сразу выходим
}
}
void ChangeLastName(int year, const string& last_name) {
for (auto& i : YearNameSoname) {
if (year > i.first) {
if (YearNameSoname.count(year) == 0) YearNameSoname[year].Name = ""; //если такого года еще нет, то добавим пустое имя
YearNameSoname[year].Soname = last_name; //и добавим указанную фамилию
}
break; //сразу выходим
}
}
string GetFullName(int year) const {
if (birth_year != 0 && year < birth_year) return "No person";
else if (YearNameSoname.size() == 0) { //если размер = 0
return "Incognito"; //выводим Инкогнито
}
else {
for (const auto& i : YearNameSoname) {
if (year < i.first) return "Incognito"; //если искомый год меньше первого года изменения, выводим Инкогнито
break; //сразу выходим из цикла
}
}
//иначе
string nm = "";
string sn = "";
for (const auto& i : YearNameSoname) { //полистаем нашу структуру
//и будем присваивать переменной sn значение фамилии, если она не пустая и пока искомый год больше текущего(в структуре)
if (i.first <= year && i.second.Soname != "") sn = i.second.Soname;
if (i.first <= year && i.second.Name != "") nm = i.second.Name; //тоже самое с именем
}
if (nm == "") return sn + " with unknown first name"; //условие, если имя пустое(вывод фамилии и текста)
else if (sn == "") return nm + " with unknown last name"; //условие, если фамилия пуста (вывод имени и текста)
else return nm + " " + sn; //вывод имени и фамилии
}
string GetFullNameWithHistory(int year) const {
if (birth_year != 0 && year < birth_year) return "No person";
else if (YearNameSoname.size() == 0) { //если размер = 0
return "Incognito"; //выводим Инкогнито
}
else {
for (const auto& i : YearNameSoname) {
if (year < i.first) return "Incognito"; //если искомый год меньше первого года изменения, выводим Инкогнито
break; //сразу выходим из цикла
}
}
//иначе
string nm = "";
string sn = "";
vector<string> secondnames; //вектор предыдущих фамилий
vector<string> firstnames; //вектор предыдущих имен
for (const auto& i : YearNameSoname) { //полистаем нашу структуру
//и будем присваивать переменной sn значение фамилии, если она не пустая и пока искомый год больше текущего(в структуре)
if (i.first <= year && i.second.Soname != "") {
if (i.second.Soname != sn && sn != "") {
secondnames.push_back(sn);
}
sn = i.second.Soname;
}
if (i.first <= year && i.second.Name != "") {
if (i.second.Name != nm && nm != "") {
firstnames.push_back(nm);
}
nm = i.second.Name;
}
}
//инициализируем переменные в которые будем складывать фамилии и имена в обратном порядке
string secnames_string = "", firstnames_string = "";
if (secondnames.size() > 0) { //если вектор с фамилиями не пуст, то
secnames_string += " (" + secondnames[secondnames.size() - 1]; //добавим в строку пробел, скобку и предыдущую фамилию
if (secondnames.size() > 1) {
for (int i = secondnames.size() - 1; i > 0; --i) {//в обратном порядке
secnames_string += ", " + secondnames[i - 1]; // добавим в строку остальные фамилии
}
}
secnames_string += ")"; //закроем строку скобкой
}
//аналогично с именами
if (firstnames.size() > 0) {
firstnames_string += " (" + firstnames[firstnames.size() - 1];
if (firstnames.size() >1) {
for (int i = firstnames.size() - 1; i > 0; --i) {
firstnames_string += ", " + firstnames[i - 1];
}
}
firstnames_string += ")";
}
if (nm == "") return sn + secnames_string + " with unknown first name";
else if (sn == "") return nm + firstnames_string + " with unknown last name";
else return nm + firstnames_string + " " + sn + secnames_string;
}
private: //объявим в приватной секции
map<int, FullName> YearNameSoname; //структуру с годом и полным именем
int birth_year = 0;
}; |
|
Продолжение следует...
|