コースホームページ: CS106L
宿題リスト#
宿題番号 | 宿題タイトル | 宿題リンク |
---|---|---|
Assignment 1 | SimpleEnroll | 完了する |
Assignment 2 | Marriage Pact | 完了する |
Assignment 3 | Make a class! | 完了する |
Assignment 4 | Weather Forecast | 完了する |
... | ... | ... |
Assignment 1: SimpleEnroll#
現在はできません。この宿題のネットワークドライブは外部に公開されていません(おそらく
Assignment 2: Marriage Pact#
知識点: STL のコンテナとポインタ
概要#
開始コード:
main.cpp
- ソースコードファイルstudents.txt
- すべての学生の名前、一行に一つ、形式は Xxxxx Xxxxx
この宿題では、すべての名前の中から自分の名前と一致するものを見つける必要があります。名前のイニシャルが自分の名前と一致する場合にのみ一致し、その後、任意の戦略を用いてすべての一致項目から唯一の項目を見つけます。
パート 1: すべての応募者を取得#
この部分では、ファイル内のすべての名前を std::set<std::string>
または std::unordered_set<std::string>
に読み込む必要があります。
考え方:
std::ifstream
と std::stringstream
を組み合わせれば良いです。
コード:
std::set<std::string> get_applicants(std::string filename) {
std::set<std::string> result;
std::ifstream ifs(filename);
if (ifs.is_open()) {
std::stringstream ss;
ss << ifs.rdbuf();
std::string line;
while (std::getline(ss, line)) {
result.insert(line);
}
}
return result;
}
パート 2: 一致を見つける#
この部分では、すべての一致項目を std::queue<const std::string*>
に格納する必要があります。
考え方:
std::set
は順序があり二分探索が可能です。私の名前のイニシャルはTGなので、まず T で始まる名前の左右の境界を二分探索で見つけ、その後その範囲を遍歴して一致項目を見つけます。
コード:
std::queue<const std::string*> find_matches(std::set<std::string> &students) {
std::queue<const std::string*> result;
std::string Prefix("T");
auto itLeft = students.lower_bound(Prefix);
std::string nextPrefix("U");
auto itRight = students.lower_bound(nextPrefix);
for (auto it = itLeft; it != itRight; it++) {
const std::string& name = *it;
std::stringstream ss(name);
std::string first, last;
ss >> first >> last;
if(last[0] != 'G') {
continue;
}
result.push(&name);
}
return result;
}
次に、一致項目から唯一の項目を取り出す必要があります。ここではランダムに一つを選びます。
完全なコード:
/*
Assignment 2: Marriage Pact
この宿題では、コンテナとポインタを使用してあなたの真実の愛を見つけることを求めています。
2つの部分があります: get_applicants と find_matches を実装します。
2024年2月1日午後11時59分までにPaperlessに提出してください。
*/
#include <iostream>
#include <string>
#include <queue>
#include <set>
#include <fstream>
#include <sstream>
#include <random>
std::set<std::string> get_applicants(std::string filename) {
std::set<std::string> result;
std::ifstream ifs(filename);
if (ifs.is_open()) {
std::stringstream ss;
ss << ifs.rdbuf();
std::string line;
while (std::getline(ss, line)) {
result.insert(line);
}
}
return result;
}
std::queue<const std::string*> find_matches(std::set<std::string> &students) {
std::queue<const std::string*> result;
std::string Prefix("T");
auto itLeft = students.lower_bound(Prefix);
std::string nextPrefix("U");
auto itRight = students.lower_bound(nextPrefix);
for (auto it = itLeft; it != itRight; it++) {
const std::string& name = *it;
std::stringstream ss(name);
std::string first, last;
ss >> first >> last;
if(last[0] != 'G') {
continue;
}
result.push(&name);
}
return result;
}
int main() {
auto students = get_applicants("students.txt");
for (const auto& name : students) {
std::cout << name << std::endl;
}
auto matches = find_matches(students);
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1, static_cast<int>(matches.size()));
int rand_int = distribution(generator);
int position = 1;
std::string trueLove;
while (!matches.empty()) {
const std::string* name = matches.front();
matches.pop();
trueLove = *name;
if (position == rand_int) {
break;
}
position++;
}
std::cout << "あなたの真実の愛は " << trueLove << '\n';
return 0;
}
Assignment 3: クラスを作成する#
知識点:クラス、コンストラクタのオーバーロード、const の正しさ
概要#
開始コード:
class.h
- クラスの定義ファイル(ヘッダファイル)class.cpp
- クラスの実装main.cpp
- 主要ファイル(インスタンス化して実行)
この宿題では、自分でクラスを実装し、以下の要件を満たす必要があります:
- カスタムコンストラクタを持つこと
- デフォルトコンストラクタを持つこと
- プライベートメンバーを持つこと
- パブリックメンバーを持つこと
- 少なくとも 1 つのgetterメソッドと 1 つのsetterメソッドを持つこと
const の正しさ#
const の正しさは、変更すべきでない / 変更する必要のない値を変更しないようにconst
キーワードを使用することを奨励する原則であり、エラーを減らし、コードの可読性(明確さ)を向上させ、コンパイラの最適化の機会を得るのに役立ちます。
この宿題では、主に getter メソッドおよび setter メソッドの引数に反映されます。
コード#
- class.h
// 空のヘッダファイル
#include <string>
class Student {
private:
std::string name;
int age;
std::string id;
std::string dept;
public:
Student();
Student(const std::string& _name, int _age, const std::string& _id, const std::string& _dept);
void setName(const std::string& _name);
const std::string& getName() const;
void setAge(int _age);
int getAge() const;
void setId(const std::string& _id);
const std::string& getId() const;
void setDept(const std::string& _dept);
const std::string& getDept() const;
};
- class.cpp
// 空のcppファイル
#include "class.h"
Student::Student() = default;
Student::Student(const std::string& _name, int _age, const std::string& _id, const std::string& _dept) {
this->name = _name;
this->age = _age;
this->id = _id;
this->dept = _dept;
}
void Student::setName(const std::string& _name) {
this->name = _name;
}
const std::string &Student::getName() const {
return this->name;
}
void Student::setAge(int _age) {
this->age = _age;
}
int Student::getAge() const {
return this->age;
}
void Student::setId(const std::string &_id) {
this->id = _id;
}
const std::string &Student::getId() const {
return this->id;
}
void Student::setDept(const std::string &_dept) {
this->dept = _dept;
}
const std::string &Student::getDept() const {
return this->dept;
}
- main.cpp
#include <memory>
#include <iostream>
#include "class.h"
/*
* 宿題 3: クラスを作成する!
* 要件:
* カスタムコンストラクタを持つこと
* デフォルトコンストラクタを持つこと
- すなわち、コンストラクタのオーバーロード
* プライベートメンバー(関数および/または変数)を持つこと
* パブリックメンバー(関数)を持つこと
* 少なくとも1つのgetter関数を持つこと
* 少なくとも1つのsetter関数を持つこと
*/
int main() {
// クラスを初期化してこのファイルを実行
auto stu = std::make_unique<Student>("Nanomoa", 20, "12345678", "Computer Science");
std::cout << "名前: " << stu->getName() << '\n';
std::cout << "年齢: " << stu->getAge() << '\n';
std::cout << "ID: " << stu->getId() << '\n';
std::cout << "学科: " << stu->getDept() << '\n';
// または
auto stu1 = std::make_unique<Student>();
stu1->setName("Nanomoa");
stu1->setAge(20);
stu1->setId("12345678");
stu1->setDept("Computer Science");
std::cout << "名前: " << stu1->getName() << '\n';
std::cout << "年齢: " << stu1->getAge() << '\n';
std::cout << "ID: " << stu1->getId() << '\n';
std::cout << "学科: " << stu1->getDept() << '\n';
return 0;
}
Assignment 4: 天気予報#
知識点:テンプレート関数、ラムダ
概要#
開始コード:
main.cpp
主要コードファイルoutput.txt
出力ファイル
ある週の毎日の異なる時間帯の華氏温度が与えられています。この宿題では、template function
とlambda
を使用していくつかの処理を行う必要があります。
パート 1: 温度変換器#
Template Function
を使用して関数 convert_f_to_c
を実装し、華氏温度を摂氏温度に変換し、double
型の値を返します。
注意: 入力される華氏温度の型は不明です。
変換公式:
コード:
template<typename Type>
double convert_f_to_c(Type f) {
return (static_cast<double>(f) - 32) * 5 / 9;
}
パート 2: 週間予報#
関数 get_forecast
を実装して結果を集計します。
関数テンプレート:
template<typename Function>
std::vector<double> get_forecast(std::vector<std::vector<double>> readings, Function fn) {
// TODO
}
注意: ここでの fn
はlambda
を引数として受け取る必要があります。
私たちは毎日を遍歴し、その後fn
を呼び出して結果を格納するだけです。
コード:
template<typename Function>
std::vector<double> get_forecast(std::vector<std::vector<double>> readings, Function fn) {
std::vector<double> result;
result.reserve(readings.size());
for (const auto& day : readings) {
result.push_back(fn(day));
}
return result;
}
パート 3: すべてをまとめる#
main
関数内で上記の実装した関数を呼び出し、以下の機能を完成させる必要があります:
readings
を摂氏温度に変換し、output.txt
に出力する- 毎日の最高温度を集計し、
output.txt
に出力する - 毎日の最低温度を集計し、
output.txt
に出力する - 毎日の平均温度を集計し、
output.txt
に出力する
その中で2~4は、対応するlambda
を引数としてget_forecast
関数に渡す必要があります。
コード:
// TODO: 温度を摂氏に変換し、output.txtに出力
for (auto& vec : readings) {
for (auto& item : vec) {
item = convert_f_to_c(item);
}
}
std::ofstream ofs("output.txt");
if (ofs.is_open()) {
for (auto& vec : readings) {
for (auto& item : vec) {
ofs << item << " ";
}
ofs << '\n';
}
ofs.close();
}
// TODO: 毎日の最高温度を見つけてoutput.txtに出力
auto maximum_temps = [](const std::vector<double>& day) -> double {
return *std::max_element(day.begin(), day.end());
};
auto max_temps = get_forecast(readings, maximum_temps);
ofs.open("output.txt", std::ios_base::app);
if (ofs.is_open()) {
for (auto& item : max_temps) {
ofs << item << " ";
}
ofs << '\n';
ofs.close();
}
// TODO: 毎日の最低温度を見つけてoutput.txtに出力
auto minimum_temps = [](const std::vector<double>& day) -> double {
return *std::min_element(day.begin(), day.end());
};
auto min_temps = get_forecast(readings, minimum_temps);
ofs.open("output.txt", std::ios_base::app);
if (ofs.is_open()) {
for (auto& item : min_temps) {
ofs << item << " ";
}
ofs << '\n';
ofs.close();
}
// TODO: 毎日の平均温度を見つけてoutput.txtに出力
auto average_temps = [](const std::vector<double>& day) -> double {
double sum = std::accumulate(day.begin(), day.end(), 0.0);
return sum / static_cast<double>(day.size());
};
auto avg_temps = get_forecast(readings, average_temps);
ofs.open("output.txt", std::ios_base::app);
if (ofs.is_open()) {
for (auto& item : avg_temps) {
ofs << item << " ";
}
ofs << '\n';
ofs.close();
}
完全なコード:#
/*
Assignment 4: 天気予報
この宿題では、テンプレート関数とラムダを使用してスタンフォードデイリーで最高の天気予報士になることを目指します。
PDFの宿題の詳細を必ず読んでください。
2024年5月10日午後11時59分までにPaperlessに提出してください。
*/
// TODO: STLから役立つものをインポートする!
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <numeric>
// TODO: convert_f_to_c関数をここに書いてください。常に
// doubleを返すテンプレート関数であることを忘れないでください。
template<typename Type>
double convert_f_to_c(Type f) {
return (static_cast<double>(f) - 32) * 5 / 9;
}
template<typename Function>
std::vector<double> get_forecast(std::vector<std::vector<double>> readings, Function fn) {
std::vector<double> result;
result.reserve(readings.size());
for (const auto& day : readings) {
result.push_back(fn(day));
}
return result;
}
int main() {
std::vector<std::vector<double>> readings = {
{70, 75, 80, 85, 90},
{60, 65, 70, 75, 80},
{50, 55, 60, 65, 70},
{40, 45, 50, 55, 60},
{30, 35, 40, 45, 50},
{50, 55, 61, 65, 70},
{40, 45, 50, 55, 60}
};
// TODO: 温度を摂氏に変換し、output.txtに出力
for (auto& vec : readings) {
for (auto& item : vec) {
item = convert_f_to_c(item);
}
}
std::ofstream ofs("output.txt");
if (ofs.is_open()) {
for (auto& vec : readings) {
for (auto& item : vec) {
ofs << item << " ";
}
ofs << '\n';
}
ofs.close();
}
// TODO: 毎日の最高温度を見つけてoutput.txtに出力
auto maximum_temps = [](const std::vector<double>& day) -> double {
return *std::max_element(day.begin(), day.end());
};
auto max_temps = get_forecast(readings, maximum_temps);
ofs.open("output.txt", std::ios_base::app);
if (ofs.is_open()) {
for (auto& item : max_temps) {
ofs << item << " ";
}
ofs << '\n';
ofs.close();
}
// TODO: 毎日の最低温度を見つけてoutput.txtに出力
auto minimum_temps = [](const std::vector<double>& day) -> double {
return *std::min_element(day.begin(), day.end());
};
auto min_temps = get_forecast(readings, minimum_temps);
ofs.open("output.txt", std::ios_base::app);
if (ofs.is_open()) {
for (auto& item : min_temps) {
ofs << item << " ";
}
ofs << '\n';
ofs.close();
}
// TODO: 毎日の平均温度を見つけてoutput.txtに出力
auto average_temps = [](const std::vector<double>& day) -> double {
double sum = std::accumulate(day.begin(), day.end(), 0.0);
return sum / static_cast<double>(day.size());
};
auto avg_temps = get_forecast(readings, average_temps);
ofs.open("output.txt", std::ios_base::app);
if (ofs.is_open()) {
for (auto& item : avg_temps) {
ofs << item << " ";
}
ofs << '\n';
ofs.close();
}
return 0;
}