通过截图

在线测试

本地测试

总览

代码风格

我们的代码必须遵循 Google C++ Style Guide。在线检测网站使用 Clang 自动检查源代码的质量。如果我们的提交未通过任何这些检查,您的项目成绩将为零。
对于 Google C++ Style Guide ,我们可以看这里 google-styleguide
对于如何测试,我们可以在 build 目录下,执行以下代码

$ make format
$ make check-lint
$ make check-clang-tidy-p0

以下命令会提示你哪里需要修正,但这不重要,我们先得实现功能,然后再去改这些,这里推荐 vscode 一键格式化代码,把风格设置为 Google,可以避免很多麻烦。

如何测试

test/primer/starter_test.cpp:测试代码
src/include/primer/p0_starter.h:实现代码

本地测试

我们先需要取把测试代码中的 DISABLED_ 前缀去掉,直接查找替换很快的。
在主目录下:

cd build
make starter_trie_test
./test/starter_trie_test

便可看见 project0的本地测试结果

在线测试

登录 https://www.gradescope.com/
注册
入口代码:PXWVR5
学校选 Carnegie Mellon University
还有一些问题可以看这里 https://15445.courses.cs.cmu.edu/fall2022/faq.html
登录进去大概你们就知道怎么测试了,总之在线测试比本地测试更加严格!但是在线测试毕竟没有本地测试那么方便,我们可以根据一些技巧将在线测试集拉下来。
这是这位大佬发出来的:https://blog.csdn.net/freedom1523646952/article/details/122274850

#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <vector>void GetTestFileContent() {static bool first_enter = true;if (first_enter) {//  截取gradescope日志输出文件名/*std::vector<std::string> all_filenames = {"/autograder/bustub/test/primer/grading_starter_test.cpp","/autograder/bustub/test/execution/grading_update_executor_test.cpp","/autograder/bustub/test/execution/grading_nested_loop_join_executor_test.cpp","/autograder/bustub/test/execution/grading_limit_executor_test.cpp","/autograder/bustub/test/execution/grading_executor_benchmark_test.cpp","/autograder/bustub/test/concurrency/grading_lock_manager_3_test.cpp","/autograder/bustub/test/buffer/grading_parallel_buffer_pool_manager_test.cpp","/autograder/bustub/test/buffer/grading_lru_replacer_test.cpp","/autograder/bustub/test/execution/grading_executor_integrated_test.cpp","/autograder/bustub/test/execution/grading_sequential_scan_executor_test.cpp","/autograder/bustub/test/concurrency/grading_lock_manager_1_test.cpp","/autograder/bustub/test/execution/grading_distinct_executor_test.cpp","/autograder/bustub/test/buffer/grading_buffer_pool_manager_instance_test.cpp","/autograder/bustub/test/concurrency/grading_lock_manager_2_test.cpp","/autograder/bustub/test/concurrency/grading_transaction_test.cpp","/autograder/bustub/test/buffer/grading_leaderboard_test.cpp","/autograder/bustub/test/container/grading_hash_table_verification_test.cpp","/autograder/bustub/test/concurrency/grading_rollback_test.cpp","/autograder/bustub/test/container/grading_hash_table_concurrent_test.cpp","/autograder/bustub/test/container/grading_hash_table_page_test.cpp","/autograder/bustub/test/concurrency/grading_lock_manager_detection_test.cpp","/autograder/bustub/test/container/grading_hash_table_leaderboard_test.cpp","/autograder/bustub/test/container/grading_hash_table_scale_test.cpp","/autograder/bustub/test/container/grading_hash_table_test.cpp","/autograder/bustub/test/execution/grading_aggregation_executor_test.cpp","/autograder/bustub/test/execution/grading_insert_executor_test.cpp","/autograder/bustub/test/execution/grading_delete_executor_test.cpp","/autograder/bustub/test/execution/grading_hash_join_executor_test.cpp""/autograder/bustub/test/execution/grading_sequential_scan_executor_test.cpp","/autograder/bustub/test/execution/grading_update_executor_test.cpp","/autograder/bustub/test/execution/grading_executor_test_util.h","/autograder/bustub/src/include/execution/plans/mock_scan_plan.h",};*/std::vector<std::string> filenames = {"/autograder/bustub/test/execution/grading_executor_integrated_test.cpp","/autograder/bustub/test/execution/grading_executor_benchmark_test.cpp",};std::ifstream fin;for (const std::string &filename : filenames) {fin.open(filename, std::ios::in);if (!fin.is_open()) {std::cout << "cannot open the file:" << filename << std::endl;continue;}char buf[200] = {0};std::cout << filename << std::endl;while (fin.getline(buf, sizeof(buf))) {std::cout << buf << std::endl;}fin.close();}first_enter = false;}
}

我们可以将它插入到我们的测试文件,filenames 写在线测试集文件的位置信息,这个一般在你提交一次后的报错信息中会有,然后就可以得到测试文件了,复制下来替换本地测试文件便可接着 Debug。

Trie

注意事项

Trie 也叫字典树,讲解我主要看的是这个:https://zhuanlan.zhihu.com/p/67431582
官方讲解也很重要:
https://15445.courses.cs.cmu.edu/fall2022/project0/
然后便可以根据每个函数上面的 TODO 提示,进行Coding了。
这里讲几个我碰到的点:

  1. 不需要再添加成员变量了,文件中已经提供了所需要的文件。
  2. vscode 远程开发不会提示报错,所以需要经常执行测试文件进行查看哪里出错。
  3. 当传入参数为指针,且为判断标志的变量,在函数初始时应该初始化为 false,当满足条件的时候才能返回 true
  4. 对 unique_ptr 可以采用 get 成员函数增加美观性
  5. 寻找目标 value 时,不要光看是不是 endNode,也要看 key 是否对应。

代码实现

// ===----------------------------------------------------------------------===//
//
//                          BusTub
//
//  p0_trie.h
//
//  Identification: src/include/primer/p0_trie.h
//
//  Copyright (c) 2015-2022, Carnegie Mellon University Database Group
//
// ===----------------------------------------------------------------------===//#pragma once#include <memory>
#include <stack>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
#include "common/exception.h"
#include "common/rwlatch.h"namespace bustub {/*** TrieNode is a generic container for any node in Trie.*/
class TrieNode {public:/*** TODO(P0): Add implementation** @brief Construct a new Trie Node object with the given key char.* is_end_ flag should be initialized to false in this constructor.** @param key_char Key character of this trie node*/explicit TrieNode(char key_char) {this->key_char_ = key_char;this->is_end_ = false;this->children_.clear();}/*** TODO(P0): Add implementation** @brief Move constructor for trie node object. The unique pointers stored* in children_ should be moved from other_trie_node to new trie node.** @param other_trie_node Old trie node.*/TrieNode(TrieNode &&other_trie_node) noexcept {this->key_char_ = other_trie_node.key_char_;this->is_end_ = other_trie_node.is_end_;this->children_.swap(other_trie_node.children_);}/*** @brief Destroy the TrieNode object.*/virtual ~TrieNode() = default;/*** TODO(P0): Add implementation** @brief Whether this trie node has a child node with specified key char.** @param key_char Key char of child node.* @return True if this trie node has a child with given key, false otherwise.*/bool HasChild(char key_char) const { return children_.find(key_char) != children_.end(); }/*** TODO(P0): Add implementation** @brief Whether this trie node has any children at all. This is useful* when implementing 'Remove' functionality.** @return True if this trie node has any child node, false if it has no child node.*/bool HasChildren() const { return !children_.empty(); }/*** TODO(P0): Add implementation** @brief Whether this trie node is the ending character of a key string.** @return True if is_end_ flag is true, false if is_end_ is false.*/bool IsEndNode() const { return this->is_end_; }/*** TODO(P0): Add implementation** @brief Return key char of this trie node.** @return key_char_ of this trie node.*/char GetKeyChar() const { return this->key_char_; }/*** TODO(P0): Add implementation** @brief Insert a child node for this trie node into children_ map, given the key char and* unique_ptr of the child node. If specified key_char already exists in children_,* return nullptr. If parameter `child`'s key char is different than parameter* `key_char`, return nullptr.** Note that parameter `child` is rvalue and should be moved when it is* inserted into children_map.** The return value is a pointer to unique_ptr because pointer to unique_ptr can access the* underlying data without taking ownership of the unique_ptr. Further, we can set the return* value to nullptr when error occurs.** @param key Key of child node* @param child Unique pointer created for the child node. This should be added to children_ map.* @return Pointer to unique_ptr of the inserted child node. If insertion fails, return nullptr.*/std::unique_ptr<TrieNode> *InsertChildNode(char key_char, std::unique_ptr<TrieNode> &&child) {if (HasChild(key_char) || key_char != child->key_char_) {return nullptr;}children_[key_char] = std::forward<std::unique_ptr<TrieNode>>(child);return &children_[key_char];}/*** TODO(P0): Add implementation** @brief Get the child node given its key char. If child node for given key char does* not exist, return nullptr.** @param key Key of child node* @return Pointer to unique_ptr of the child node, nullptr if child*         node does not exist.*/std::unique_ptr<TrieNode> *GetChildNode(char key_char) {auto node = children_.find(key_char);if (node != children_.end()) {return &(node->second);}return nullptr;}/*** TODO(P0): Add implementation** @brief Remove child node from children_ map.* If key_char does not exist in children_, return immediately.** @param key_char Key char of child node to be removed*/void RemoveChildNode(char key_char) {auto node = children_.find(key_char);if (node != children_.end()) {children_.erase(key_char);}}/*** TODO(P0): Add implementation** @brief Set the is_end_ flag to true or false.** @param is_end Whether this trie node is ending char of a key string*/void SetEndNode(bool is_end) { this->is_end_ = is_end; }protected:/** Key character of this trie node */char key_char_;/** whether this node marks the end of a key */bool is_end_{false};/** A map of all child nodes of this trie node, which can be accessed by each* child node's key char. */std::unordered_map<char, std::unique_ptr<TrieNode>> children_;
};/*** TrieNodeWithValue is a node that mark the ending of a key, and it can* hold a value of any type T.*/
template <typename T>
class TrieNodeWithValue : public TrieNode {private:/* Value held by this trie node. */T value_;public:/*** TODO(P0): Add implementation** @brief Construct a new TrieNodeWithValue object from a TrieNode object and specify its value.* This is used when a non-terminal TrieNode is converted to terminal TrieNodeWithValue.** The children_ map of TrieNode should be moved to the new TrieNodeWithValue object.* Since it contains unique pointers, the first parameter is a rvalue reference.** You should:* 1) invoke TrieNode's move constructor to move data from TrieNode to* TrieNodeWithValue.* 2) set value_ member variable of this node to parameter `value`.* 3) set is_end_ to true** @param trieNode TrieNode whose data is to be moved to TrieNodeWithValue* @param value*/TrieNodeWithValue(TrieNode &&trieNode, T value) : TrieNode(std::forward<TrieNode>(trieNode)) {this->value_ = value;SetEndNode(true);}/*** TODO(P0): Add implementation** @brief Construct a new TrieNodeWithValue. This is used when a new terminal node is constructed.** You should:* 1) Invoke the constructor for TrieNode with given key_char.* 2) Set value_ for this node.* 3) set is_end_ to true.** @param key_char Key char of this node* @param value Value of this node*/TrieNodeWithValue(char key_char, T value) : TrieNode(key_char) {this->value_ = value;SetEndNode(true);}/*** @brief Destroy the Trie Node With Value object*/~TrieNodeWithValue() override = default;/*** @brief Get the stored value_.** @return Value of type T stored in this node*/T GetValue() const { return value_; }
};/*** Trie is a concurrent key-value store. Each key is string and its corresponding* value can be any type.*/
class Trie {private:/* Root node of the trie */std::unique_ptr<TrieNode> root_;/* Read-write lock for the trie */ReaderWriterLatch latch_;public:/*** TODO(P0): Add implementation** @brief Construct a new Trie object. Initialize the root node with '\0'* character.*/Trie() {auto *root = new TrieNode('\0');root_.reset(root);}/*** TODO(P0): Add implementation** @brief Insert key-value pair into the trie.** If key is empty string, return false immediately.** If key alreadys exists, return false. Duplicated keys are not allowed and* you should never overwrite value of an existing key.** When you reach the ending character of a key:* 1. If TrieNode with this ending character does not exist, create new TrieNodeWithValue* and add it to parent node's children_ map.* 2. If the terminal node is a TrieNode, then convert it into TrieNodeWithValue by* invoking the appropriate constructor.* 3. If it is already a TrieNodeWithValue,* then insertion fails and return false. Do not overwrite existing data with new data.** You can quickly check whether a TrieNode pointer holds TrieNode or TrieNodeWithValue* by checking the is_end_ flag. If is_end_ == false, then it points to TrieNode. If* is_end_ == true, it points to TrieNodeWithValue.** @param key Key used to traverse the trie and find correct node* @param value Value to be inserted* @return True if insertion succeeds, false if key already exists*/template <typename T>bool Insert(const std::string &key, T value) {if (key.empty()) {return false;}latch_.WLock();auto c = key.begin();auto pre_child = &root_;while (c != key.end()) {auto cur = c++;// 若当前节点将为 end 节点,跳出循环进行特殊处理if (c == key.end()) {break;}// 如果该字符不存在 则直接创建if (!pre_child->get()->HasChild(*cur)) {pre_child = pre_child->get()->InsertChildNode(*cur, std::make_unique<TrieNode>(*cur));} else {// 存在则直接跳过pre_child = pre_child->get()->GetChildNode(*cur);}}// 此时c为end 退回一个c--;auto end_node = pre_child->get()->GetChildNode(*c);// 若最后一个节点存在,且已经为 end 则插入失败if (end_node != nullptr && end_node->get()->IsEndNode()) {latch_.WUnlock();return false;}// 若最后一个节点存在,且不为 end 则转为 TrieNodeWithValueif (end_node != nullptr) {auto new_node = new TrieNodeWithValue(std::move(**end_node), value);end_node->reset(new_node);latch_.WUnlock();return true;}//  节点不存在,则直接插入pre_child = pre_child->get()->InsertChildNode(*c, std::make_unique<TrieNode>(*c));auto new_node = new TrieNodeWithValue(std::move(**pre_child), value);pre_child->reset(new_node);latch_.WUnlock();return true;}/*** TODO(P0): Add implementation** @brief Remove key value pair from the trie.* This function should also remove nodes that are no longer part of another* key. If key is empty or not found, return false.** You should:* 1) Find the terminal node for the given key.* 2) If this terminal node does not have any children, remove it from its* parent's children_ map.* 3) Recursively remove nodes that have no children and is not terminal node* of another key.** @param key Key used to traverse the trie and find correct node* @return True if key exists and is removed, false otherwise*/bool Remove(const std::string &key) {// 为空返回if (key.empty()) {return false;}latch_.WLock();// 含义为,第二个元素 TrieNode 需要删除 keyChar 等于第一个元素的节点std::stack<std::tuple<char, std::unique_ptr<TrieNode> *>> s;auto c = key.begin();auto pre_child = &root_;while (c != key.end()) {auto cur = c++;if (pre_child->get()->HasChild(*cur)) {s.push(std::make_tuple(*cur, pre_child));// 到下一个 keypre_child = pre_child->get()->GetChildNode(*cur);continue;}// 存在key没有的现象latch_.WUnlock();return false;}// 开始删除while (!s.empty()) {std::tuple<char, std::unique_ptr<TrieNode> *> temp = s.top();s.pop();auto key = std::get<0>(temp);auto del_node = std::get<1>(temp);// 若被删除的节点没有孩子,则可以直接删除auto flag = (*del_node)->GetChildNode(key);if (flag != nullptr && (*flag)->HasChildren()) {continue;}(*del_node)->RemoveChildNode(key);}latch_.WUnlock();return true;}/*** TODO(P0): Add implementation** @brief Get the corresponding value of type T given its key.* If key is empty, set success to false.* If key does not exist in trie, set success to false.* If given type T is not the same as the value type stored in TrieNodeWithValue* (ie. GetValue<int> is called but terminal node holds std::string),* set success to false.** To check whether the two types are the same, dynamic_cast* the terminal TrieNode to TrieNodeWithValue<T>. If the casted result* is not nullptr, then type T is the correct type.** @param key Key used to traverse the trie and find correct node* @param success Whether GetValue is successful or not* @return Value of type T if type matches*/template <typename T>T GetValue(const std::string &key, bool *success) {// 这个初始化很重要,如果没有找到就直接返回 false,卡这里好久*success = false;latch_.RLock();auto pre_child = &root_;auto c = key.begin();while (c != key.end()) {auto cur = c++;auto next_node = pre_child->get()->GetChildNode(*cur);if (!next_node) {*success = false;break;}// 若是目标尾节点,返回值// 这里犯了个错,并非只要是 end 节点就是所需要的节点,key也得对,所以要 key == end 时if (next_node->get()->IsEndNode() && c == key.end()) {// 若所需要类型和存储的类型不同也失败auto flag_node = dynamic_cast<TrieNodeWithValue<T> *>(next_node->get());if (!flag_node) {*success = false;break;}*success = true;latch_.RUnlock();return flag_node->GetValue();}// 切换到下个pre_child = next_node;}latch_.RUnlock();return {};}
};
}  //  namespace bustub

2022 CMU15-445 Project0 Trie相关推荐

  1. 【蓝桥杯Web】大一小白参与蓝桥杯模拟赛二期web组体会

    目录 前言 一.相关比赛介绍 1.ACM国际大学生程序设计竞赛 2.蓝桥杯 3.GPLT团队程序设计天梯赛 4.leetcode周赛和双周赛 5.PAT 二.蓝桥杯 1.应该参加蓝桥杯吗? 2.如何进 ...

  2. 中国水环境治理市场需求前景与十四五战略规划建议报告2022版

    中国水环境治理市场需求前景与十四五战略规划建议报告2022版 -------------------------------------  <修订日期>:2022年2月 <出版单位& ...

  3. 2022第三届全国大学生网络安全精英赛练习题(7)

    全国大学生网络安全精英赛 2022第三届全国大学生网络安全精英赛练习题(7) 文章目录 全国大学生网络安全精英赛 2022第三届全国大学生网络安全精英赛练习题(7) 总结 601.在实体特征的鉴别中, ...

  4. 全球及中国农药市场需求走势与十四五发展商机研究报告2022版

    全球及中国农药市场需求走势与十四五发展商机研究报告2022版 --------------------------------------- <修订日期>:2021年12月 <报告价 ...

  5. 联合省选2022游记

    Day 0 昨晚将某谷头像换成了麻美桑,顺势奶一波学姐: 身体好轻,怀着这么幸福的感觉战斗还是第一次 体が軽い,こんな幸せな気持ちで戦うなんて初めて 已经没什么好怕的了 もう何も怖くない 因为我不再是 ...

  6. 全球及中国轮胎行业发展方向与销售前景状况分析报告2022年

    全球及中国轮胎行业发展方向与销售前景状况分析报告2022年 --------------------------------------- <修订日期>:2021年12月 <报告价格 ...

  7. 2022年1月份报告合集(共222份)

    合集名称:2022年1月份报告合集 数量:222份 下载链接:2022年1月份报告合集(共222份).zip-行业报告文档类资源-CSDN下载 包含内容: 2021 游戏行业研究报告-21页.pdf ...

  8. ICML 2022|达摩院多模态模型OFA,实现模态、任务和架构三个统一

    作者:霜清.钟煌.鸿侠 通用统一的预训练大模型逐渐成为AI研究的一大趋势,本文将介绍达摩院提出的多模态模型OFA,是如何实现架构.模态.任务的三个统一. 近年来,基于大规模无监督数据的预训练逐渐成为深 ...

  9. 2022最新淘宝天猫商品详情接口采集方法

    目前商品信息比较全的接口 一.mtop.taobao.detail.getdetail 目前这个接口风控比较严,21年升级之后,基本上都需要登录了.但正常新设备和新版本APP不登录情况下,也可以跑成功 ...

最新文章

  1. 3.集--LinkedTransferQueue得知
  2. 亮剑:PHP,我的未来不是梦(11)
  3. exit(),_exit()的区别
  4. kafka创建topic_Kafka实战宝典:一文带解决Kafka常见故障处理
  5. 今日头条 mysql_今日头条的核心技术细节是什么?
  6. AC双链路冷备份详解及配置原理
  7. jQuery中的join方法
  8. css3mediaquery移动端网页字体适应屏幕代码
  9. PHP获取<textarea>换行空白格处理
  10. 【避坑指南】GD32 KEIL中SW Device没有识别芯片,jlink下载不进去的问题
  11. 蚂蚁课堂学习笔记之springAop和Ioc
  12. linux下安装tecplot记录
  13. 视频教程-鼎捷易飞ERP视频教程-ERP
  14. 索尼微单连android手机软件,(收藏)如何将手机连接上SONY微单的WIFI进行遥控拍摄...
  15. Oracle 数据库实例
  16. 菜菜PyTorch深度学习框架最全笔记(第一次课)
  17. Echarts中国地图各省份区域设置不同的颜色
  18. 国密浏览器是什么?有哪些?有什么特点?
  19. WinDbg 常用指令
  20. PCB设计中数字地、模拟地、数字电源、模拟电源的处理方式

热门文章

  1. 索爱手机手机白屏或重启
  2. int最大值表示方法
  3. 支付宝接口 - 即时到账交易接口 对接 整理 1
  4. Ubuntu16.04解决文件名中文变问号
  5. 利用远程云服务器跑深度学习模型
  6. 【LEDE】树莓派上玩LEDE终极指南-81-从U盘启动(并不推荐)
  7. 最新手机号码验证正则表达式
  8. WIN32 API:绘图函数
  9. 一个淘淘商城项目送给你,愿你有一个灿烂的前程!
  10. 在信息技术下的创客教育新型研究