CMU 15-445 Project #0 - C++ Primer

news2024/11/15 23:43:41

Project #0 - C++ Primer

  • 一、题目链接
  • 二、准备工作
    • 1.项目构建
    • 2.代码测试
    • 3.代码格式化
    • 4.压缩与提交
  • 三、部分实现

在这里插入图片描述

一、题目链接


二、准备工作

以下操作在题目文档中均有提及,这里进行简要整理。

1.项目构建

首先需要从远程仓库克隆项目文件,由于该仓库会随每年的课程一起更新,所以需要根据课程时间指定相应分支。

git clone --branch v20221128-2022fall https://github.com/cmu-db/bustub.git

下载下来后需要在项目根目录下执行 build_support/packages.sh 安装BusTub需要的包,具体执行哪个脚本因操作系统而异。

随后在项目根目录执行以下命令,通过cmake构建项目,这里的 -DCMAKE_BUILD_TYPE=Debug 表示在调试模式下构建项目,即在没有优化的情况下,使用带有调试符号的方式构建库或可执行文件。

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make

2.代码测试

本项目通过GoogleTest完成代码测试及评分,题目文件为 src/include/primer/p0_trie.h,测试文件为 test/primer/starter_trie_test.cpp,测试文件中的每一个 TEST 对应一个测试单元。

我们在刚才创建的build目录下,通过以下命令执行测试,这里需要注意的是,需要去掉测试文件的代码中的 DISABLED_ 前缀以激活对应测试单元。

make starter_trie_test
./test/starter_trie_test

执行运行命令后控制台会打印测试结果,[ OK ] 即对应单元测试通过,如果有 [ DISABLED ] 则表示对应单元中的 DISABLED_ 前缀没有删除。

atreus@MacBook-Pro % ./test/starter_trie_test
Running main() from gmock_main.cc
[==========] Running 5 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from StarterTest
[ RUN      ] StarterTest.TrieNodeInsertTest
[       OK ] StarterTest.TrieNodeInsertTest (0 ms)
[ RUN      ] StarterTest.TrieNodeRemoveTest
[       OK ] StarterTest.TrieNodeRemoveTest (0 ms)
[ RUN      ] StarterTest.TrieInsertTest
[       OK ] StarterTest.TrieInsertTest (0 ms)
[----------] 3 tests from StarterTest (0 ms total)

[----------] 2 tests from StarterTrieTest
[ RUN      ] StarterTrieTest.RemoveTest
[       OK ] StarterTrieTest.RemoveTest (0 ms)
[ RUN      ] StarterTrieTest.ConcurrentTest1
[       OK ] StarterTrieTest.ConcurrentTest1 (184 ms)
[----------] 2 tests from StarterTrieTest (184 ms total)

[----------] Global test environment tear-down
[==========] 5 tests from 2 test suites ran. (184 ms total)
[  PASSED  ] 5 tests.
atreus@MacBook-Pro % 

我们也可以自己指定测试用例:

TEST(StarterTest, MyTest) {
  Trie trie;
  bool success;
  success = trie.Insert<int>("a", 1);
  EXPECT_EQ(success, true);
  EXPECT_EQ(trie.GetValue<int>("a", &success), 1);

  success = trie.Insert<int>("abc", 3);
  EXPECT_EQ(success, true);
  EXPECT_EQ(trie.GetValue<int>("abc", &success), 3);

  success = trie.Insert<int>("ab", 2);
  EXPECT_EQ(success, true);
  EXPECT_EQ(trie.GetValue<int>("ab", &success), 2);

  success = trie.Remove("ab");
  EXPECT_EQ(success, true);
  trie.GetValue<int>("ab", &success);
  EXPECT_EQ(success, false);

  success = trie.Insert<int>("ab", 5);
  EXPECT_EQ(success, true);
  EXPECT_EQ(trie.GetValue<int>("ab", &success), 5);
}

3.代码格式化

代码最终要提交到在线网站,如果代码风格不遵循Google C++ Style Guide会直接被判零分,因此我们需要对代码进行格式化。

在build目录下执行 make format 通过python脚本自动格式化代码,然后执行 make check-lintmake check-clang-tidy-p0 检查格式化结果,控制台将打印代码格式问题,依次进行修改即可。

如果完成格式话要求的话输出大致如下:

atreus@MacBook-Pro % make format             
Built target format
atreus@MacBook-Pro % make check-lint         
Built target check-lint
atreus@MacBook-Pro % make check-clang-tidy-p0
Enabled checks:
    bugprone-argument-comment
    bugprone-assert-side-effect
    bugprone-bad-signal-to-kill-thread
    ......
    readability-uniqueptr-delete-release
    readability-uppercase-literal-suffix
    readability-use-anyofallof

Checking: /Users/atreus/CLionProjects/bustub/src/primer/p0_trie.cpp

Built target check-clang-tidy-p0
atreus@MacBook-Pro % 

4.压缩与提交

我们通过 zip 命令压缩 p0_trie.h 文件。

这里需要注意的是,压缩文件时文件名中需要包含完整的 src/include/primer/p0_trie.h 路径,因此我们在项目根目录下进行压缩:

atreus@MacBook-Pro % zip project0-submission.zip ./src/include/primer/p0_trie.h  # 压缩
updating: src/include/primer/p0_trie.h (deflated 72%)
atreus@MacBook-Pro % unzip -l project0-submission.zip  # 检查压缩文件内容
Archive:  project0-submission.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
    13702  05-31-2023 00:00   src/include/primer/p0_trie.h
---------                     -------
    13702                     1 file
atreus@MacBook-Pro % 

代码需要提交到以下网址进行评测,提交前需要以CMU进行注册:

https://www.gradescope.com/courses/424375/

如果评测成功结果大致如下:

在这里插入图片描述

其实这个关于线上测试有个小技巧,因为线上评测的用例比本地提供的要复杂一些,但是它只会提供给你最中结果,而不是像LeetCode一样给出失败的测试用例。

不过我们可以通过以下的函数从在线测试平台上获取测试文件的源代码,从而查看测试用例。我们只需要将对应函数放在 p0_trie.h 文件中,然后在任意一个函数中调用 ShowTestCase() 即可,这里的测试文件文件名 testfile 可以参考在线测试平台的输出以及本地目录结构。

#define SEP "====================================================================================================="
void ShowTestCase() {
    static bool tag = true;  // 通过静态变量保证只输出一次
    if (tag) {
        std::string testfile = "/autograder/bustub/test/primer/grading_starter_trie_test.cpp";  // 文件名
        std::ifstream in_file;                                                                  // 读文件流
        char line_buffer[256] = {0};                                                        // 行缓冲区

        in_file.open(testfile, std::ios::in);  // 以读模式打开文件
        if (in_file) { // 文件打开成功
            std::cout << "\n\n\n\n\n" << SEP << "\n" << testfile << "\n" << SEP << std::endl;
            while (in_file.getline(line_buffer, sizeof(line_buffer))) {
                std::cout << line_buffer << std::endl;
            }
            std::cout << SEP << "\n\n\n\n\n" << std::endl;
            in_file.close();
        } else {  // 文件打开失败
            std::cout << "\n\n\n\n\n" << SEP << "\n" << "can not open \"" << testfile << "\".\n" << SEP << "\n\n\n\n\n"
                      << std::endl;
        }

        tag = false;
    }
}

三、部分实现

Insert

template<typename T>
bool Insert(const std::string &key, T value) {
    std::unique_lock <std::shared_mutex> lock(shared_mutex_);  // 通过unique_lock使用互斥锁

    if (key.empty()) {
        return false;
    }

    auto cur_node = &root_;  // 用于对节点进行遍历
    for (int i = 0; i < static_cast<int>(key.size()); i++) {
        char cur_c = key.at(i);  // 本次要插入的字符

        if (i == static_cast<int>(key.size()) - 1) {  // 处理最后一个字符
            /* 如果待插入位置已经存在一个节点了,需要判断它是不是值节点,否则直接插入 */
            if ((*cur_node)->HasChild(cur_c)) {
                auto next_node = (*cur_node)->GetChildNode(cur_c);  // 待插入位置的节点

                if ((*next_node)->IsEndNode()) {  // key对应的位置已经存在一个值节点了
                    return false;
                }

                /* 用一个TrieNodeWithValue节点替换这个TrieNode节点 */
                auto new_node = std::make_unique < TrieNodeWithValue < T >> (std::move(*(*next_node)), value);
                (*cur_node)->RemoveChildNode(cur_c);
                (*cur_node)->InsertChildNode(cur_c, std::move(new_node));
            } else {
                /* 直接插入 */
                (*cur_node)->InsertChildNode(cur_c, std::make_unique < TrieNodeWithValue < T >> (cur_c, value));
            }
        } else {
            /* 如果当前字符对应的节点已经存在直接向下遍历,否则需要先插入再访问 */
            if ((*cur_node)->HasChild(cur_c)) {
                cur_node = (*cur_node)->GetChildNode(cur_c);
            } else {
                cur_node = (*cur_node)->InsertChildNode(cur_c, std::make_unique<TrieNode>(cur_c));
            }
        }
    }

    return true;
}

Remove

bool Remove(const std::string &key) {
    std::vector < std::unique_ptr < TrieNode > * > records;  // 记录访问过的节点,用于后续删除

    std::unique_lock <std::shared_mutex> lock(shared_mutex_);  // 通过unique_lock使用互斥锁

    /* 按照key查找节点 */
    records.emplace_back(&root_);
    for (int i = 0; i < static_cast<int>(key.size()); i++) {
        std::unique_ptr <TrieNode> *next_node = (*records.at(i))->GetChildNode(key.at(i));
        if (next_node == nullptr) {  // 满足条件的子节点不存在,查找失败
            return false;
        }
        records.emplace_back(next_node);  // 将每一个访问过的节点入队
    }

    /* key对应的节点为一个非值节点,查找失败 */
    if (!(*records.at(static_cast<int>(records.size()) - 1))->IsEndNode()) {
        return false;
    }

    /* 从下到上依次删除节点 */
    for (int i = static_cast<int>(records.size()) - 1; i > 0; i--) {
        /* 如果待删除的节点有孩子,只需要将is_end_置为false即可,否则需要从父节点中删除当前节点 */
        /* 这里一个更好的做法是将这个TrieNodeWithValue节点转换为TrieNode节点,这样能节省一定内存 */
        if ((*records.at(i))->HasChildren()) {
            (*records.at(i))->SetEndNode(false);
        } else {
            (*records.at(i - 1))->RemoveChildNode(key.at(i - 1));
        }

        /* 下一个要处理的节点为值节点,停止删除 */
        if ((*(*records.at(i - 1))).IsEndNode()) {
            break;
        }
    }

    return true;
}

GetValue

template<typename T>
T GetValue(const std::string &key, bool *success) {
    std::shared_lock <std::shared_mutex> lock(shared_mutex_);  // 通过shared_lock使用共享锁

    *success = true;

    if (key.empty()) {
        *success = false;
        return {};
    }

    /* 按照key查找节点 */
    std::unique_ptr <TrieNode> *cur_node = &root_;  // 用于对节点进行遍历
    for (char c : key) {
        cur_node = (*cur_node)->GetChildNode(c);
        if (cur_node == nullptr) {
            *success = false;
            return {};
        }
    }

    /* 查找失败 */
    if (!(*cur_node)->IsEndNode()) {
        *success = false;
        return {};
    }

    /* 检查范型T和实际存储的数据类型是否一致 */
    auto result = dynamic_cast<TrieNodeWithValue <T> *>(&(*(*cur_node)));
    if (result == nullptr) {
        *success = false;
        return {};
    }

    return result->GetValue();
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/593397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GB28181——实时视频显示

一、主要实现功能 1、支持四路设备接入 2、实时视频分屏显示 3、接入设备信息存储 二、待完善功能&#xff08;现阶段&#xff09; 1、设备的删除 &#xff08;已更新&#xff09; 2、语音对讲 &#xff08;暂时不处理&#xff09; 3、视频输出通道的实时修改 &#xff08;已更…

Nginx详细解说

1 什么是Nginx Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的。从2004年发布至今&#xff0c;凭借开源的力量&#xff0c;已经接近成熟与完善。 Nginx功能丰富&#xff0c;可作为HTTP服务器&#xff0c;也可作为反向代理服务器&#xff0c;邮件服务器。支…

科技云报道:大模型的中场战事,深入垂直行业腹地

科技云报道原创。 自从OpenAI于2022年11月推出ChatGPT后&#xff0c;一场波及全球科技界的“AI海啸”就此爆发。 自今年以来&#xff0c;国内已有超过30家企业入局大模型赛道。从百度“文心一言”、阿里“通义千问”的发布&#xff0c;到网易“玉言”、科大讯飞“星火”、昆仑…

Centos7匹配Locust+prometheus+grafana性能监控平台

一、安装Loust 之前已写过&#xff0c;这里忽略一万字。。。 Locust初次体验【解决webUI没数据】_Vikesgao的博客-CSDN博客 二、安装prometheus Prometheus 是一个开源的服务监控系统和时序数据库&#xff0c;其提供了通用的数据模型和快捷数据采集、存储和查询接口。它的核心…

LLM:LLaMA模型和微调的Alpaca模型

待写 LLaMA模型 论文原文:https://arxiv.org/abs/2302.13971v1 预训练数据 模型架构 模型就是用的transformer的decoder,所以在结构上它与GPT是非常类似的,只是有一些细节需要注意一下。 1、RMS Pre-Norm 2、SwiGLU激活函数 3、RoPE旋转位置编码 Alpaca模型 [Stanford …

cuda编程学习——CUDA全局内存性能优化(八)

前言 参考资料&#xff1a; 高升博客 《CUDA C编程权威指南》 以及 CUDA官方文档 CUDA编程&#xff1a;基础与实践 樊哲勇 文章所有代码可在我的GitHub获得&#xff0c;后续会慢慢更新 文章、讲解视频同步更新公众《AI知识物语》&#xff0c;B站&#xff1a;出门吃三碗饭 …

Python3数据分析与挖掘建模(8)检验

1. 假设检验 1.1 概述 假设检验是一种统计推断方法&#xff0c;用于对一个或多个总体参数提出关于其取值的假设&#xff0c;并根据样本数据对这些假设进行检验。假设检验的目的是根据样本数据提供统计上的证据&#xff0c;以便对总体参数的假设进行接受或拒绝。 在假设检验中…

JAVA基础 - 如何使用ClassLoader?

1. CLASSLOADER是什么 ClassLoader&#xff0c;类加载器。用于将CLASS文件动态加载到JVM中去&#xff0c;是所有类加载器的基类(Bootstrap ClassLoader不继承自ClassLoader)&#xff0c;所有继承自抽象的ClassLoader的加载器&#xff0c;都会优先判断是否被父类加载器加载过&a…

C++数据结构:二叉树之二(二叉搜索树)

文章目录 前言一、二叉搜索树的概念二、代码详解1、构建节点2、构建二叉树类3、插入方法4、删除方法5、四种遍历方法6、测试代码 总结 前言 前文已经讲了二叉树概念&#xff0c;并搞出一个数组存储的没写具体实用意义的二叉树&#xff0c;这篇文章将讲解二叉树的另一种存储方式…

限量内测名额释放:微信云开发管理工具新功能

我们一直收到大家关于云数据库管理、快速搭建内部工具等诉求&#xff0c;为了给大家提供更好的开发体验&#xff0c;结合大家的诉求&#xff0c;云开发团队现推出新功能「管理工具」&#xff0c;现已启动内测&#xff0c;诚邀各位开发者参与内测体验。 什么是「管理工具」 管…

当节点内存管理遇上 Kubernetes:自动调度与控制

原理 在现代的容器化环境中&#xff0c;节点资源的管理是一个重要的任务。特别是对于内存资源的管理&#xff0c;它直接影响着容器应用的性能和可用性。在 Kubernetes 中&#xff0c;我们可以利用自动调度和控制的机制来实现对节点内存的有效管理。本文将介绍一种基于 Bash 脚…

EM中等效原理

EM中等效原理 一、基本简介 电磁等效定理对于简化许多问题的解是有用的。此外&#xff0c;它们还提供了对麦克斯韦系统电磁场行为的物理见解。它们与唯一性定理和惠更斯原理密切相关。一个应用是它们在研究来自孔径天线或来自激光腔输出的辐射中的用途。 等效源原理&#xf…

3.2 掌握RDD算子

一、准备工作 &#xff08;一&#xff09;准备文件 1、准备本地系统文件 2、把文件上传到HDFS &#xff08;二&#xff09;启动Spark Shell 1、启动HDFS服务 2、启动Spark服务 3、启动Spark Shell 二、掌握转换算子 &#xff08;一&#xff09;映射算子 - map() …

Sketch在线版免费使用,Windows也能用的Sketch!

Sketch 的最大缺点是它对 Windows/PC 用户不友好。它是一款 Mac 工具&#xff0c;无法在浏览器中运行。此外&#xff0c;使用 Sketch 需要安装其他插件才能获得更多响应式设计工具。然而&#xff0c;现在有了 Sketch 网页版工具即时设计替代即时设计&#xff01; 即时设计几乎…

通达信凹口平量柱选股公式,倍量柱之后调整再上升

凹口平量柱是一组量柱形态&#xff0c;表现为量柱两边高、中间扁平或圆底的形态。如下图所示&#xff0c;左右各有一根高度持平的高量柱&#xff0c;中间夹杂着三五根甚至更多根低量柱。 凹口平量柱选股公式需要结合量柱以及K线&#xff0c;主要考虑以下三点&#xff1a; 1、倍…

git各阶段代码修改回退撤销操作

git push origin master 的含义是将本地当前分支的提交推送到名为 origin 的远程仓库的 master 分支上。 各阶段代码修改回退撤销的操作 case1 git checkout -- . 修改了文件内容但没还有git add 或git commit时撤销当前目录下所有文件的修改 case2 当完成了git add 之后&a…

项目管理:面对未知的挑战时,如何获取和使用信息?

一项实验展示了人们在面对未知的挑战时&#xff0c;对信息的获取和使用的影响。在下面的实验中&#xff0c;三组人被要求步行到十公里外的三个村庄。 第一组人没有任何信息&#xff0c;只跟着向导走。他们在走了短短的两三公里后就开始抱怨和情绪低落&#xff0c;同时感到疲惫…

2022年天府杯全国大学生数学建模竞赛E题地铁线路的运营与规划解题全过程文档及程序

2022年天府杯全国大学生数学建模竞赛 E题 地铁线路的运营与规划 原题再现&#xff1a; 地铁是一种非常绿色快捷的交通出行方式&#xff0c;全国各大城市也都在如火如荼地进行地铁线路建设与规划。但乘坐地铁有时候会感觉特别拥挤&#xff0c;这一时期我们称为高峰期。如何合理…

sqlserver中的merge into语句

merge into语句是用来合并两张表的数据的&#xff0c;比如我们想把一张表的数据批量更新到另外一张表&#xff0c;就可以用merge into语句。具体有哪些业务场景呢&#xff1f; 1.数据同步 2.数据转换 3.基于源表对目标表进行增&#xff0c;删&#xff0c;改的操作。 实践步骤…

JavaScript了解调用带参函数,无参函数的代码

以下为JavaScript了解调用带参函数&#xff0c;无参函数的程序代码和运行截图 目录 前言 一、带参函数 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 二、无参函数 2.1 运行流程及思想 2.2 代码段 2.3 JavaScript语句代码 2.4 运行截图 前言…