CS106L Spring 2024 Assignment

课程主页: 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's containers and pointers

简介

start code:

main.cpp - 源代码文件

students.txt - 所有学生的姓名，一行一个，形如 Xxxxx Xxxxx

本次作业需要从所有名字中找出与自己名字匹配的一项，当且仅当某个名字的首字母缩写和自己名字相同时匹配，然后采用任意策略从所有匹配项中找到唯一的一项

Part 1: Get all applicants

本部分需要读取文件中所有名字到 std::set<std::string> 或 std::unordered_set<std::string> 中

思路:

std::ifstream 配合 std::stringstream 即可

代码:

Copy
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;
}

Part 2: Find matches

本部分需要找出所有匹配项放入 std::queue<const std::string*>

思路:

std::set 有序可二分，我名字缩写为TG, 故，先二分找到 T 开头的名字的左右边界，而后遍历该区间找到匹配项即可

代码:

Copy
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;
}

然后要从匹配项中取出唯一一项，我这里随机取出一项

完整代码:

Copy
/*
Assignment 2: Marriage Pact

This assignment asks you to discover your one true love using containers and pointers.
There are two parts: implement get_applicants and find_matches.

Submit to Paperless by 11:59pm on 2/1/2024.
*/

#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 << "Your true love is " << trueLove << '\n';

return 0;
}

Assignment 3: Make a Class

知识点: class, constructor overloading, const-correctness

简介

start code:

class.h - 类的定义文件 (头文件)

class.cpp - 类的实现

main.cpp - 主要文件 (实例化并运行)

本次作业需要自行实现一个类，并满足如下要求:

必须有一个自定义的构造函数

必须有一个默认构造函数

必须有私有成员

必须有共有成员

必须有至少一个getter方法以及一个setter方法

const-correctness

const-correctness 是一个原则，鼓励使用 const 关键字来防止改变不应该 / 不需要被改变的值，有助于减少错误以及提高代码可读性 (清晰度), 还有获得编译器优化的机会

在本次作业中，主要反映在 getter 方法以及 setter 方法的参数上

代码

class.h

Copy
// Blank header file

#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

Copy
// Blank cpp file

#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

Copy
#include <memory>
#include <iostream>
#include "class.h"

/*
* Assigment 3: Make a class!
* Requirements:
* Must have a custom constructor
* Must have a default constructor
- i.e. constructor overloading
* Must have private members (functions and/or variables)
* Must have public members (functions)
* Must have at least one getter function
* Must have at least one setter function
*/

int main() {
// initialize class and run this file
auto stu = std::make_unique<Student>("Nanomoa", 20, "12345678", "Computer Science");

std::cout << "Name: " << stu->getName() << '\n';
std::cout << "Age: " << stu->getAge() << '\n';
std::cout << "ID: " << stu->getId() << '\n';
std::cout << "Dept: " << stu->getDept() << '\n';

// or
auto stu1 = std::make_unique<Student>();

stu1->setName("Nanomoa");
stu1->setAge(20);
stu1->setId("12345678");
stu1->setDept("Computer Science");

std::cout << "Name: " << stu1->getName() << '\n';
std::cout << "Age: " << stu1->getAge() << '\n';
std::cout << "ID: " << stu1->getId() << '\n';
std::cout << "Dept: " << stu1->getDept() << '\n';

return 0;
}

Assignment 4: Weather Forecast

知识点: template function, lambda

简介

start code:

main.cpp 主要代码文件

output,txt 输出文件

已知某周中每天不同时段的华氏温度，本次作业需要配合template function和lambda 对其做一些处理

Part 1: Temperature Converter

使用 Template Function 实现函数 convert_f_to_c, 将华氏温度转换为摄氏温度，返回一个double 类型的值

注意: 传入华氏温度的类型未知

转换公式: (Fahrenheit−32)×5÷9( Fahrenheit - 32) \times 5 \div 9(Fahrenheit−32)×5÷9

代码:

Copy
template<typename Type>
double convert_f_to_c(Type f) {
return (static_cast<double>(f) - 32) * 5 / 9;
}

Part 2: The Weekly Forecast

完善实现函数 get_forecast 完成结果统计

函数模板:

Copy
template<typename Function>
std::vector<double> get_forecast(std::vector<std::vector<double>> readings, Function fn) {
// TODO
}

注意: 此处的 fn 需要接受一个lambda作为参数

我们只需要遍历每一天，之后调用fn计算后存入结果即可

代码:

Copy
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;
}

Part 3: Putting it all together

我们需要在 main 函数中调用上面实现的函数完成如下功能:

将 readings 转为摄氏温度并输出到output.txt

统计出每天的最高温度并输出到output.txt

统计出每天的最低温度并输出到output.txt

统计出每天的平均温度并输出到output.txt

其中2~4条需要实现对应的lambda作为参数传入get_forecast函数

代码:

Copy
// TODO: Convert temperatures to Celsius and output to 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: Find the maximum temperature for each day and output to 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: Find the minimum temperature for each day and output to 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: Find the average temperature for each day and output to 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();
}

完整代码:

Copy
/*
Assignment 4: Weather Forecast

This assignment works with template functions and lambdas to become the best weather forecaster
at the Stanford Daily. Be sure to read the assignment details in the PDF.

Submit to Paperless by 11:59pm on 5/10/2024.
*/

// TODO: import anything from the STL that might be useful!
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <numeric>

// TODO: write convert_f_to_c function here. Remember it must be a template function that always returns
// a 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: Convert temperatures to Celsius and output to 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: Find the maximum temperature for each day and output to 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: Find the minimum temperature for each day and output to 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: Find the average temperature for each day and output to 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;
}