diff --git a/notebook/docs/C++/1.iostream.md b/notebook/docs/C++/1.iostream.md new file mode 100644 index 00000000..8b6e613a --- /dev/null +++ b/notebook/docs/C++/1.iostream.md @@ -0,0 +1,28 @@ +1. `cout`: 用于标准输出,可以使用`<<`操作符将数据输出到屏幕上。 + + ```cpp + std::cout << "Hello, world!" << std::endl; + ``` + +2. `cin`: 用于标准输入,可以使用`>>`操作符从用户输入中读取数据。 + ```cpp + int num; + std::cin >> num; + ``` + +3. `endl`: 输出换行符并刷新输出缓冲区。 + ```cpp + std::cout << "Hello" << std::endl; + ``` + +4. `cerr`: 用于输出错误信息,通常用于标准错误流。 + + ```cpp + std::cerr << "Error: something went wrong!" << std::endl; + ``` + +5. `fixed`和`setprecision`: 用于控制浮点数的输出精度。 + ```cpp + double num = 3.14159; + std::cout << std::fixed << std::setprecision(2) << num << std::endl; + ``` diff --git a/notebook/docs/C++/10.algorithm.md b/notebook/docs/C++/10.algorithm.md new file mode 100644 index 00000000..ae4a237e --- /dev/null +++ b/notebook/docs/C++/10.algorithm.md @@ -0,0 +1,89 @@ +1. **查找和比较**: + - `find`:在范围内查找元素。 + - `find_if`:在范围内查找满足指定条件的元素。 + - `count`:统计范围内满足条件的元素个数。 + - `count_if`:统计范围内满足指定条件的元素个数。 + - `equal`:比较两个范围是否相等。 + - `lexicographical_compare`:按字典序比较两个范围。 + +```cpp +#include +#include +#include +using namespace std; + +int main() { + vector vec = {1, 2, 3, 4, 5}; + + // 查找元素 + auto it = find(vec.begin(), vec.end(), 3); + if (it != vec.end()) { + cout << "Element found: " << *it << endl; + } + + // 查找满足条件的元素 + auto it2 = find_if(vec.begin(), vec.end(), [](int x) { return x > 3; }); + if (it2 != vec.end()) { + cout << "Element > 3 found: " << *it2 << endl; + } + + // 统计元素个数 + int num = count(vec.begin(), vec.end(), 2); + cout << "Number of 2s: " << num << endl; + + // 比较两个范围 + vector vec2 = {1, 2, 3}; + bool result = equal(vec.begin(), vec.end(), vec2.begin(), vec2.end()); + if (result) { + cout << "Vectors are equal" << endl; + } else { + cout << "Vectors are not equal" << endl; + } + + return 0; +} +``` + +2. **排序和操作**: + - `sort`:对范围内的元素进行排序。 + - `reverse`:反转范围内的元素顺序。 + - `copy`:将范围内的元素复制到另一个位置。 + - `remove`:移除范围内满足条件的元素(不会改变容器大小)。 + - `remove_if`:移除范围内满足指定条件的元素(不会改变容器大小)。 + - `transform`:对范围内的元素执行指定操作。 + +```cpp +#include +#include +#include +using namespace std; + +int main() { + vector vec = {5, 3, 1, 4, 2}; + + // 排序 + sort(vec.begin(), vec.end()); + + // 反转元素顺序 + reverse(vec.begin(), vec.end()); + + // 复制元素到另一个位置 + vector vec2(5); + copy(vec.begin(), vec.end(), vec2.begin()); + + // 移除元素 + vec.erase(remove(vec.begin(), vec.end(), 3), vec.end()); + + // 对元素执行操作 + transform(vec.begin(), vec.end(), vec.begin(), [](int x) { return x * 2; }); + + // 输出元素 + for (auto& num : vec) { + cout << num << " "; + } + cout << endl; + + return 0; +} +``` + diff --git a/notebook/docs/C++/2.fstream.md b/notebook/docs/C++/2.fstream.md new file mode 100644 index 00000000..4592f507 --- /dev/null +++ b/notebook/docs/C++/2.fstream.md @@ -0,0 +1,87 @@ +1. `std::ifstream`: 用于从文件中读取数据的输入流对象。常用的成员函数包括: + + - `open(const char* filename)`: 打开指定文件名的文件。 + - `close()`: 关闭文件。 + - `is_open()`: 判断文件是否已经打开。 + - `good()`: 判断文件流状态是否良好。 + + ```cpp + #include + #include + + int main() { + std::ifstream inputFile; + inputFile.open("input.txt"); + + if (inputFile.is_open()) { + std::cout << "File opened successfully." << std::endl; + // 读取文件内容 + std::string line; + while (std::getline(inputFile, line)) { + std::cout << line << std::endl; + } + inputFile.close(); + } else { + std::cerr << "Unable to open file." << std::endl; + } + + return 0; + } + ``` + +2. `std::ofstream`: 用于向文件中写入数据的输出流对象。常用的成员函数包括: + - `open(const char* filename)`: 创建或打开指定文件名的文件。 + - `close()`: 关闭文件。 + - `is_open()`: 判断文件是否已经打开。 + - `good()`: 判断文件流状态是否良好。 + + ```cpp + #include + #include + + int main() { + std::ofstream outputFile; + outputFile.open("output.txt"); + + if (outputFile.is_open()) { + std::cout << "File opened successfully." << std::endl; + // 写入数据到文件 + outputFile << "Hello, world!" << std::endl; + outputFile << 42 << std::endl; + outputFile.close(); + } else { + std::cerr << "Unable to open file." << std::endl; + } + + return 0; + } + ``` + +3. `std::fstream`: 同时支持读写操作的文件流对象。常用的成员函数包括: + - `open(const char* filename, std::ios_base::openmode mode)`: 打开指定文件名的文件,并指定打开模式(例如`std::ios::in`表示读取模式,`std::ios::out`表示写入模式)。 + - `close()`: 关闭文件。 + - `is_open()`: 判断文件是否已经打开。 + - `good()`: 判断文件流状态是否良好。 + + ```cpp + #include + #include + + int main() { + std::fstream file; + file.open("data.txt", std::ios::out | std::ios::app); + + if (file.is_open()) { + std::cout << "File opened successfully." << std::endl; + // 写入数据到文件 + file << "Appended line." << std::endl; + file.close(); + } else { + std::cerr << "Unable to open file." << std::endl; + } + + return 0; + } + ``` + +这些函数和对象使得在C++中进行文件输入输出操作变得简单和方便。 \ No newline at end of file diff --git a/notebook/docs/C++/3.string.md b/notebook/docs/C++/3.string.md new file mode 100644 index 00000000..865c4f6f --- /dev/null +++ b/notebook/docs/C++/3.string.md @@ -0,0 +1,76 @@ +1. `std::string`: C++中的字符串类,提供了丰富的成员函数用于字符串操作。常用的成员函数包括: + - `size()`: 返回字符串的长度。 + - `length()`: 返回字符串的长度。 + - `empty()`: 判断字符串是否为空。 + - `clear()`: 清空字符串内容。 + - `substr(pos, len)`: 返回从位置`pos`开始长度为`len`的子字符串。 + - `find(str, pos)`: 在字符串中查找子字符串`str`,并返回第一次出现的位置。 + - `replace(pos, len, str)`: 替换字符串中从位置`pos`开始长度为`len`的子串为字符串`str`。 + - `append(str)`: 在字符串末尾追加字符串`str`。 + - `insert(pos, str)`: 在指定位置插入字符串`str`。 + + ```cpp + #include + #include + + int main() { + std::string str = "Hello, world!"; + + // 使用成员函数进行字符串操作 + std::cout << "Length: " << str.length() << std::endl; + std::cout << "Substring: " << str.substr(0, 5) << std::endl; + + str.replace(7, 5, "C++"); + std::cout << "Replaced: " << str << std::endl; + + str.append(" Goodbye!"); + std::cout << "Appended: " << str << std::endl; + + str.insert(0, "Greetings, "); + std::cout << "Inserted: " << str << std::endl; + + return 0; + } + ``` + +2. `std::getline()`: 从输入流中读取一行数据并存储到字符串中。 + ```cpp + #include + #include + + int main() { + std::string line; + std::cout << "Enter a line of text: "; + std::getline(std::cin, line); + std::cout << "You entered: " << line << std::endl; + + return 0; + } + ``` + +3. 字符串查找和比较函数: + - `std::string::find(str, pos)`: 在字符串中查找子字符串`str`,并返回第一次出现的位置。 + - `std::string::rfind(str, pos)`: 在字符串中从后向前查找子字符串`str`,并返回第一次出现的位置。 + - `std::string::find_first_of(str, pos)`: 在字符串中查找任意字符集合`str`中的字符,返回第一次出现的位置。 + - `std::string::find_last_of(str, pos)`: 在字符串中从后向前查找任意字符集合`str`中的字符,返回第一次出现的位置。 + - `std::string::compare(str)`: 比较字符串与`str`,返回大小关系(0表示相等,负数表示小于,正数表示大于)。 + + ```cpp + #include + #include + + int main() { + std::string str = "Hello, world!"; + + if (str.find("world") != std::string::npos) { + std::cout << "Substring found!" << std::endl; + } + + if (str.compare("Hello, C++!") == 0) { + std::cout << "Strings are equal." << std::endl; + } + + return 0; + } + ``` + diff --git a/notebook/docs/C++/4.ctime.md b/notebook/docs/C++/4.ctime.md new file mode 100644 index 00000000..0d687e30 --- /dev/null +++ b/notebook/docs/C++/4.ctime.md @@ -0,0 +1,43 @@ +1. `time_t time(time_t* timer)`: 返回当前的日历时间作为一个 `time_t` 对象。如果 `timer` 不是 NULL,则结果也存储在 `timer` 指向的变量中。 +2. `struct tm *localtime(const time_t* timer)`: 将日历时间 `timer` 转换为本地时间表示(`struct tm`),包括年、月、日、时、分和秒等字段。 +3. `struct tm *gmtime(const time_t* timer)`: 类似于 `localtime`,但它将日历时间 `timer` 转换为协调世界时(UTC)。 +4. `time_t mktime(struct tm* timeptr)`: 将表示日历时间的 `struct tm` 对象转换为 `time_t` 对象。 +5. `char* asctime(const struct tm* timeptr)`: 将 `struct tm` 对象转换为人类可读的字符串,表示日期和时间的格式为 "Www Mmm dd hh:mm:ss yyyy\n",其中 Www 是星期几,Mmm 是月份,dd 是日期,hh:mm:ss 是时间,yyyy 是年份。 +6. `char* ctime(const time_t* timer)`: 等同于 `asctime(localtime(timer))`。它将 `time_t` 对象转换为人类可读的字符串,表示本地时间。 +7. `clock_t clock(void)`: 返回程序自执行开始以来或上一次调用 `clock()` 以来消耗的处理器时间。返回的值以时钟滴答数表示,可以使用 `CLOCKS_PER_SEC` 将其转换为秒。 + +```c++ +#include +#include + +int main() { + // 获取当前时间 + time_t now = time(0); + std::cout << "当前时间为:" << ctime(&now); + + // 将当前时间转换为本地时间 + struct tm *localTime = localtime(&now); + std::cout << "本地时间为:" << asctime(localTime); + + // 将当前时间转换为UTC时间 + struct tm *utcTime = gmtime(&now); + std::cout << "UTC时间为:" << asctime(utcTime); + + // 将本地时间结构体转换为时间戳 + time_t localTimestamp = mktime(localTime); + std::cout << "本地时间的时间戳为:" << localTimestamp << std::endl; + + // 测量程序执行时间 + clock_t start = clock(); + for (int i = 0; i < 1000000; ++i) { + // 一些计算任务 + } + clock_t end = clock(); + double elapsedSeconds = double(end - start) / CLOCKS_PER_SEC; + std::cout << "程序执行时间为:" << elapsedSeconds << " 秒" << std::endl; + + return 0; +} + +``` + diff --git a/notebook/docs/C++/5.chrono.md b/notebook/docs/C++/5.chrono.md new file mode 100644 index 00000000..8d47ce68 --- /dev/null +++ b/notebook/docs/C++/5.chrono.md @@ -0,0 +1,58 @@ +1. **时长类型**: + - `std::chrono::duration`:表示时间段。例如,`std::chrono::duration` 表示基于整数的时间段,而 `std::chrono::duration` 表示基于浮点数的时间段。 + - `std::chrono::hours`、`std::chrono::minutes`、`std::chrono::seconds`、`std::chrono::milliseconds`、`std::chrono::microseconds`、`std::chrono::nanoseconds`:具有不同单位的特定时长类型。 + +2. **时间点类型**: + - `std::chrono::time_point`:表示时间点。它在时钟类型和时长类型上进行模板化。 + - `std::chrono::system_clock`、`std::chrono::steady_clock`、`std::chrono::high_resolution_clock`:`` 提供的时钟类型。 + +3. **时钟函数**: + - `std::chrono::duration_cast`:将一个时长转换为具有不同刻度的另一个时长。 + - `std::chrono::time_point_cast`:将一个时间点转换为具有不同时钟的另一个时间点。 + - `std::chrono::system_clock::now()`:根据系统时钟获取当前时间。 + - `std::chrono::steady_clock::now()`:根据稳定时钟(单调时钟)获取当前时间。 + - `std::chrono::high_resolution_clock::now()`:如果可用,根据高分辨率时钟获取当前时间。 + +4. **实用函数**: + - `std::chrono::duration_values`:提供时长类型的最小值和最大值。 + - `std::chrono::time_point::min()`、`std::chrono::time_point::max()`:返回时间点类型的最小值和最大值。 + +5. **算术运算**: + - 时长类型支持算术运算,如加法(`operator+`)、减法(`operator-`)、乘法(`operator*`)、除法(`operator/`)以及比较运算(`operator==`、`operator!=`、`operator<` 等)。 + +6. **时长字面值**: + - 可以使用字面值后缀,如 `h`、`min`、`s`、`ms`、`us`、`ns` 来创建时长字面值。例如,`5s` 表示 5 秒。 + +这里是一个简单的示例,演示了这些功能: + +```cpp +#include +#include + +int main() { + using namespace std::chrono; + + // 定义时长 + auto 秒 = seconds(10); + auto 毫秒 = 5ms; + + // 添加时长 + auto 总时长 = 秒 + 毫秒; + + // 获取当前时间点 + auto 开始 = steady_clock::now(); + + // 等待 2 秒 + std::this_thread::sleep_for(2s); + + // 计算经过的时间 + auto 结束 = steady_clock::now(); + auto 经过时间 = duration_cast(结束 - 开始); + + std::cout << "总时长:" << 总时长.count() << " 毫秒\n"; + std::cout << "经过时间:" << 经过时间.count() << " 秒\n"; + + return 0; +} +``` + diff --git a/notebook/docs/C++/6.vector.md b/notebook/docs/C++/6.vector.md new file mode 100644 index 00000000..225bf444 --- /dev/null +++ b/notebook/docs/C++/6.vector.md @@ -0,0 +1,82 @@ +1. **构造函数**: + - `vector`:创建一个空的向量,元素类型为 `T`。 + - `vector(size_type count)`:创建包含 `count` 个默认构造的元素的向量。 + - `vector(size_type count, const T& value)`:创建包含 `count` 个值为 `value` 的元素的向量。 + - `vector(InputIterator first, InputIterator last)`:使用迭代器范围 `[first, last)` 中的元素创建向量。 + +2. **元素访问**: + - `vector::operator[]`:通过索引访问元素。 + - `vector::at(size_type pos)`:通过位置访问元素,如果越界会抛出 `std::out_of_range` 异常。 + - `vector::front()`:返回第一个元素的引用。 + - `vector::back()`:返回最后一个元素的引用。 + - `vector::data()`:返回指向底层数据的指针。 + +3. **迭代器**: + - `vector::begin()`:返回指向第一个元素的迭代器。 + - `vector::end()`:返回指向最后一个元素后面位置的迭代器。 + - `vector::rbegin()`:返回指向最后一个元素的逆向迭代器。 + - `vector::rend()`:返回指向第一个元素前面位置的逆向迭代器。 + +4. **容量**: + - `vector::size()`:返回向量中元素的数量。 + - `vector::max_size()`:返回向量能容纳的最大元素数量。 + - `vector::empty()`:检查向量是否为空。 + - `vector::reserve(size_type new_cap)`:为向量预留至少能容纳 `new_cap` 个元素的空间。 + - `vector::capacity()`:返回向量当前能容纳的元素数量。 + +5. **修改容器**: + - `vector::push_back(const T& value)`:在向量末尾添加一个元素。 + - `vector::pop_back()`:移除向量末尾的元素。 + - `vector::insert(iterator pos, const T& value)`:在指定位置插入一个元素。 + - `vector::erase(iterator pos)`:移除指定位置的元素。 + - `vector::clear()`:清空向量中的所有元素。 + +6. **比较**: + - `vector::operator==`、`vector::operator!=`、`vector::operator<`、`vector::operator<=`、`vector::operator>`、`vector::operator>=`:用于比较两个向量的操作符。 + +7. **其他操作**: + - `vector::swap(vector& other)`:交换两个向量的内容。 + - `vector::emplace_back(Args&&... args)`:在向量末尾构造一个元素。 + - `vector::shrink_to_fit()`:将向量的容量调整为其当前元素数量。 + +```c++ +#include +#include + +int main() { + // 创建一个空的整数向量 + std::vector numbers; + + // 在向量末尾添加元素 + numbers.push_back(10); + numbers.push_back(20); + numbers.push_back(30); + + // 使用迭代器遍历向量并输出元素 + std::cout << "Vector elements:"; + for (auto it = numbers.begin(); it != numbers.end(); ++it) { + std::cout << " " << *it; + } + std::cout << std::endl; + + // 访问向量的第一个和最后一个元素 + std::cout << "First element: " << numbers.front() << std::endl; + std::cout << "Last element: " << numbers.back() << std::endl; + + // 检查向量是否为空 + std::cout << "Is the vector empty? " << (numbers.empty() ? "Yes" : "No") << std::endl; + + // 获取向量的大小和容量 + std::cout << "Vector size: " << numbers.size() << std::endl; + std::cout << "Vector capacity: " << numbers.capacity() << std::endl; + + // 清空向量 + numbers.clear(); + + std::cout << "Vector size after clear: " << numbers.size() << std::endl; + + return 0; +} + +``` + diff --git a/notebook/docs/C++/7.list.md b/notebook/docs/C++/7.list.md new file mode 100644 index 00000000..5b824e04 --- /dev/null +++ b/notebook/docs/C++/7.list.md @@ -0,0 +1,150 @@ +1. **构造函数**: + - `list()`:创建一个空链表。 + - `list(const list& other)`:拷贝构造函数,用另一个链表初始化当前链表。 + +2. **赋值和交换**: + - `operator=`:将一个链表赋值给另一个链表。 + - `assign`:用特定数量的元素或范围内的元素替换链表的内容。 + - `swap`:交换两个链表的内容。 + +3. **迭代器相关**: + - `begin`:返回指向第一个元素的迭代器。 + - `end`:返回指向最后一个元素之后的位置的迭代器。 + - `rbegin`:返回指向最后一个元素的反向迭代器。 + - `rend`:返回指向第一个元素之前的位置的反向迭代器。 + +4. **容量**: + - `empty`:判断链表是否为空。 + - `size`:返回链表中元素的数量。 + - `max_size`:返回链表最大可容纳的元素数量。 + +5. **访问元素**: + - `front`:返回第一个元素的引用。 + - `back`:返回最后一个元素的引用。 + +6. **修改容器**: + - `push_front`:在链表的开头插入一个元素。 + - `pop_front`:移除链表的第一个元素。 + - `push_back`:在链表的末尾插入一个元素。 + - `pop_back`:移除链表的最后一个元素。 + - `insert`:在指定位置插入一个或多个元素。 + - `erase`:移除指定位置或范围内的一个或多个元素。 + - `clear`:移除链表的所有元素。 + +7. **其他操作**: + - `splice`:将另一个链表的元素移动到当前链表的指定位置。 + - `merge`:将两个有序链表合并为一个有序链表。 + - `sort`:对链表进行排序。 + - `reverse`:反转链表中的元素顺序。 + + + +1. **构造函数**: + + ```cpp + #include + #include + using namespace std; + + int main() { + // 创建空链表 + list mylist; + + // 用另一个链表初始化当前链表 + list otherlist = {1, 2, 3}; + list mylist2(otherlist); + + return 0; + } + ``` + +2. **赋值和交换**: + + ```cpp + // 赋值 + mylist = otherlist; + + // 用特定数量的元素或范围内的元素替换链表的内容 + mylist.assign(5, 10); // 用5个值为10的元素替换mylist的内容 + + // 交换两个链表的内容 + mylist.swap(otherlist); + ``` + +3. **迭代器相关**: + ```cpp + // 使用迭代器访问元素 + list::iterator it = mylist.begin(); + for (; it != mylist.end(); ++it) { + cout << *it << " "; + } + ``` + +4. **容量**: + ```cpp + // 判断链表是否为空 + if (mylist.empty()) { + cout << "链表为空" << endl; + } + + // 返回链表中元素的数量 + cout << "链表中元素的数量:" << mylist.size() << endl; + ``` + +5. **访问元素**: + ```cpp + // 返回第一个元素的引用 + int firstElement = mylist.front(); + + // 返回最后一个元素的引用 + int lastElement = mylist.back(); + ``` + +6. **修改容器**: + ```cpp + // 在链表的开头插入一个元素 + mylist.push_front(100); + + // 移除链表的第一个元素 + mylist.pop_front(); + + // 在链表的末尾插入一个元素 + mylist.push_back(200); + + // 移除链表的最后一个元素 + mylist.pop_back(); + + // 在指定位置插入一个或多个元素 + list::iterator it = mylist.begin(); + advance(it, 2); // 移动迭代器到第三个位置 + mylist.insert(it, 777); + + // 移除指定位置或范围内的一个或多个元素 + it = mylist.begin(); + advance(it, 1); // 移动迭代器到第二个位置 + mylist.erase(it); + + // 移除链表的所有元素 + mylist.clear(); + ``` + +7. **其他操作**: + ```cpp + // 将另一个链表的元素移动到当前链表的指定位置 + list anotherlist = {9, 8, 7}; + list::iterator pos = mylist.begin(); + advance(pos, 2); // 移动到第三个位置 + mylist.splice(pos, anotherlist); + + // 将两个有序链表合并为一个有序链表 + list sortedlist1 = {1, 3, 5}; + list sortedlist2 = {2, 4, 6}; + sortedlist1.merge(sortedlist2); + + // 对链表进行排序 + mylist.sort(); + + // 反转链表中的元素顺序 + mylist.reverse(); + ``` + diff --git a/notebook/docs/C++/8.map.md b/notebook/docs/C++/8.map.md new file mode 100644 index 00000000..4a5c13ce --- /dev/null +++ b/notebook/docs/C++/8.map.md @@ -0,0 +1,68 @@ +1. **构造函数**: + - `map()`:创建一个空的映射容器。 + - `map(const map& other)`:拷贝构造函数,用另一个映射容器初始化当前映射容器。 + +2. **赋值和交换**: + - `operator=`:将一个映射容器赋值给另一个映射容器。 + - `assign`:用特定数量的键值对或范围内的键值对替换映射容器的内容。 + - `swap`:交换两个映射容器的内容。 + +3. **迭代器相关**: + - `begin`:返回指向第一个键值对的迭代器。 + - `end`:返回指向最后一个键值对之后的位置的迭代器。 + +4. **容量**: + - `empty`:判断映射容器是否为空。 + - `size`:返回映射容器中键值对的数量。 + - `max_size`:返回映射容器最大可容纳的键值对数量。 + +5. **插入和访问元素**: + - `insert`:插入一个键值对或多个键值对。 + - `erase`:移除指定键或范围内的键值对。 + - `clear`:移除映射容器的所有键值对。 + - `find`:查找指定键的迭代器。 + - `operator[]`:访问映射容器中指定键对应的值。 + +6. **其他操作**: + - `count`:返回指定键在映射容器中出现的次数。 + - `lower_bound`:返回第一个不小于指定键的迭代器。 + - `upper_bound`:返回第一个大于指定键的迭代器。 + +```cpp +#include +#include +using namespace std; + +int main() { + // 创建空映射容器 + map mymap; + + // 插入键值对 + mymap.insert(pair(1, "One")); + mymap.insert(make_pair(2, "Two")); + mymap[3] = "Three"; + + // 访问元素 + cout << "Value at key 2: " << mymap[2] << endl; + + // 查找元素 + map::iterator it = mymap.find(3); + if (it != mymap.end()) { + cout << "Key 3 found, value: " << it->second << endl; + } + + // 移除键值对 + mymap.erase(2); + + // 输出键值对数量 + cout << "Size of map: " << mymap.size() << endl; + + // 遍历输出所有键值对 + for (auto& pair : mymap) { + cout << "Key: " << pair.first << ", Value: " << pair.second << endl; + } + + return 0; +} +``` + diff --git a/notebook/docs/C++/9.set.md b/notebook/docs/C++/9.set.md new file mode 100644 index 00000000..6af3f55a --- /dev/null +++ b/notebook/docs/C++/9.set.md @@ -0,0 +1,71 @@ +1. **构造函数**: + - `set()`:创建一个空集合。 + - `set(const set& other)`:拷贝构造函数,用另一个集合初始化当前集合。 + +2. **赋值和交换**: + - `operator=`:将一个集合赋值给另一个集合。 + - `assign`:用特定数量的元素或范围内的元素替换集合的内容。 + - `swap`:交换两个集合的内容。 + +3. **迭代器相关**: + - `begin`:返回指向第一个元素的迭代器。 + - `end`:返回指向最后一个元素之后的位置的迭代器。 + - `rbegin`:返回指向最后一个元素的反向迭代器。 + - `rend`:返回指向第一个元素之前的位置的反向迭代器。 + +4. **容量**: + - `empty`:判断集合是否为空。 + - `size`:返回集合中元素的数量。 + - `max_size`:返回集合最大可容纳的元素数量。 + +5. **插入和访问元素**: + - `insert`:插入一个元素或多个元素。 + - `erase`:移除指定元素或范围内的元素。 + - `clear`:移除集合的所有元素。 + - `find`:查找指定元素的迭代器。 + - `count`:统计指定元素在集合中出现的次数。 + +6. **其他操作**: + - `lower_bound`:返回第一个不小于指定元素的迭代器。 + - `upper_bound`:返回第一个大于指定元素的迭代器。 + - `equal_range`:返回范围内与指定元素相等的上下界迭代器对。 + +下面是这些函数的示例用法: + +```cpp +#include +#include +using namespace std; + +int main() { + // 创建空集合 + set myset; + + // 插入元素 + myset.insert(5); + myset.insert(10); + myset.insert(3); + + // 查找元素 + auto it = myset.find(10); + if (it != myset.end()) { + cout << "Element found: " << *it << endl; + } + + // 统计元素个数 + int num = myset.count(5); + cout << "Number of 5s: " << num << endl; + + // 移除元素 + myset.erase(3); + + // 输出元素 + for (auto& num : myset) { + cout << num << " "; + } + cout << endl; + + return 0; +} +``` + diff --git a/notebook/docs/C++/总.md b/notebook/docs/C++/总.md new file mode 100644 index 00000000..45d00e25 --- /dev/null +++ b/notebook/docs/C++/总.md @@ -0,0 +1,38 @@ +## 万能头 + +`#include ` 这个头文件实际上是一个非标准的头文件,在一些编译器中使用它可以简化包含标准库头文件的操作,但并不推荐在生产环境中使用,因为它不是标准的 C++ 头文件。通常情况下,应该直接包含需要的具体标准库头文件,而不是依赖于这个非标准的头文件。 + +这个头文件通常包含了 C++ 标准库的所有头文件,但具体的内容可能因编译器和系统环境而异。一般来说,它会包含以下头文件: + +```cpp +#include // 标准输入输出库 +#include // 文件输入输出库 +#include // 字符串处理库 +#include // 时间处理库 +#include // 时间处理库(C++11) + +#include // 向量容器库 +#include // 链表容器库 +#include // 映射容器库 +#include // 集合容器库 +#include // 算法库 + +#include // 随机数库 +#include // 控制输出格式库 +#include // 字符串流库 +#include // 异常处理库 +#include // 函数库 +#include // 迭代器库 +#include // 数值算法库 +#include // 实用工具库 +#include // 元组库 +#include // 位集合库 +#include // 数组库 +#include // 双端队列库 +#include // 队列库 +#include // 栈库 +#include // 无序映射库 +#include // 无序集合库 +``` + +需要注意的是,不同的编译器和环境可能会有不同的实现,因此不能保证所有编译器都支持这种方式,并且不同编译器可能包含的头文件也会有所不同。因此,建议还是根据需要直接包含具体的标准库头文件。 diff --git a/notebook/docs/basic/math/进制转换.md b/notebook/docs/basic/math/进制转换.md index f82f7f20..dfb633fe 100644 --- a/notebook/docs/basic/math/进制转换.md +++ b/notebook/docs/basic/math/进制转换.md @@ -1,89 +1,56 @@ -进制转换是计算机科学中的一个基本概念。不同的进制表示系统使用不同的基数(例如,二进制的基数是2,十进制的基数是10)来表示数字。以下是一些常见的进制及其转换方法: +#### **十进制转换成二进制** -### 常见进制 -- **二进制(Binary)**:基数为2,只使用数字 `0` 和 `1`。 -- **八进制(Octal)**:基数为8,使用数字 `0` 到 `7`。 -- **十进制(Decimal)**:基数为10,使用数字 `0` 到 `9`。 -- **十六进制(Hexadecimal)**:基数为16,使用数字 `0` 到 `9` 和字母 `A` 到 `F`(或 `a` 到 `f`,代表10到15)。 +将一个十进制数转换为二进制数的方法是通过**模运算**(求余数)进行的。具体步骤如下: -### 进制转换方法 +##### **步骤:** +1. 用十进制数除以2,记录余数。 +2. 将商继续除以2,继续记录余数。 +3. 重复此过程,直到商为0为止。 +4. 将所有余数倒序排列,即为该十进制数对应的二进制表示。 -#### 1. 二进制转十进制 -将二进制数按权展开,从右到左依次乘以 2 的幂,然后求和。 -- 例如,二进制 `1011` 转换为十进制: - \[ - 1 \times 2^3 + 0 \times 2^2 + 1 \times 2^1 + 1 \times 2^0 = 8 + 0 + 2 + 1 = 11 - \] - -#### 2. 十进制转二进制 -通过不断将十进制数除以2,记录每次的余数,然后将余数倒序排列得到二进制数。 -- 例如,十进制 `13` 转换为二进制: - - - 13 ÷ 2 = 6,余数 1 - - - 6 ÷ 2 = 3,余数 0 - - - 3 ÷ 2 = 1,余数 1 - - - 1 ÷ 2 = 0,余数 1 - - - 结果:`1101` - -#### 3. 二进制转八进制 -将二进制数每三位分组(从右到左),然后将每组转换为对应的八进制数。 -- 例如,二进制 `101011` 转换为八进制: - - 将二进制数分组为 `101` 和 `011` - - `101` = 5,`011` = 3 - - 结果:`53` - -#### 4. 八进制转二进制 -将每个八进制数转换为三位二进制数,拼接得到最终的二进制数。 -- 例如,八进制 `53` 转换为二进制: - - `5` = `101`,`3` = `011` - - 结果:`101011` - -#### 5. 十进制转十六进制 -通过不断将十进制数除以16,记录每次的余数(如果余数大于9,转换为对应的字母),然后将余数倒序排列得到十六进制数。 -- 例如,十进制 `255` 转换为十六进制: - - 255 ÷ 16 = 15,余数 15(对应 `F`) - - 15 ÷ 16 = 0,余数 15(对应 `F`) - - 结果:`FF` - -#### 6. 十六进制转十进制 -将十六进制数按权展开,从右到左依次乘以16的幂,然后求和。 -- 例如,十六进制 `1A3` 转换为十进制: - \[ - 1 \times 16^2 + 10 \times 16^1 + 3 \times 16^0 = 256 + 160 + 3 = 419 - \] - -### Python 实现进制转换 - -Python 提供了一些内置函数来轻松进行进制转换。 - -- **十进制转其他进制:** - -``` python - # 十进制转二进制 - print(bin(13)) # 输出:0b1101 - - # 十进制转八进制 - print(oct(13)) # 输出:0o15 - - # 十进制转十六进制 - print(hex(255)) # 输出:0xff +##### **示例:** +将十进制数 `153` 转换为二进制: ``` - -- **其他进制转十进制:** - -``` python - # 二进制转十进制 - print(int('1101', 2)) # 输出:13 - - # 八进制转十进制 - print(int('15', 8)) # 输出:13 - - # 十六进制转十进制 - print(int('ff', 16)) # 输出:255 +153 ÷ 2 = 76 余 1 + 76 ÷ 2 = 38 余 0 + 38 ÷ 2 = 19 余 0 + 19 ÷ 2 = 9 余 1 + 9 ÷ 2 = 4 余 1 + 4 ÷ 2 = 2 余 0 + 2 ÷ 2 = 1 余 0 + 1 ÷ 2 = 0 余 1 ``` +将余数倒序排列,得到 `153` 的二进制表示为:`10011001` -通过理解这些转换方法,可以更好地掌握不同进制之间的关系和计算方法。 \ No newline at end of file +--- + +#### **二进制转换成十进制** + +将二进制数转换为十进制数的方法是通过将每一位的数值乘以2的幂次方,然后求和。具体步骤如下: + +##### **步骤:** +1. 从二进制数的最低位开始,每一位数乘以2的对应幂次方(从0开始计数)。 +2. 将所有结果相加,得到的即是对应的十进制数。 + +##### **示例:** +将二进制数 `1001101` 转换为十进制: +``` +1 * 2^6 = 64 +0 * 2^5 = 0 +0 * 2^4 = 0 +1 * 2^3 = 8 +1 * 2^2 = 4 +0 * 2^1 = 0 +1 * 2^0 = 1 +``` +求和得到:`64 + 8 + 4 + 1 = 77` + +因此,二进制数 `1001101` 对应的十进制数为:`77` + +--- + +#### **总结** +- **十进制转二进制**:通过不断除以2并记录余数,最终将余数倒序排列。 +- **二进制转十进制**:通过每一位乘以对应的2的幂次方,并将结果相加。 + +在计算机科学中,理解进制转换是非常重要的,因为不同进制在不同场景下有着广泛的应用。通过这些转换方法,能够轻松在不同进制之间切换,理解数字在不同进制下的表示方式,虽然表示不同,但数学意义是相同的。 \ No newline at end of file diff --git a/notebook/docs/data_structure/霍夫曼编码.md b/notebook/docs/data_structure/霍夫曼编码.md new file mode 100644 index 00000000..55193f41 --- /dev/null +++ b/notebook/docs/data_structure/霍夫曼编码.md @@ -0,0 +1,163 @@ +霍夫曼编码(Huffman Coding)是一种广泛使用的数据压缩算法,特别适用于无损数据压缩。它由David A. Huffman在1952年提出,基于信息论中的熵编码思想。 + +## 霍夫曼编码的基本原理 + +霍夫曼编码是一种**前缀编码**,即没有任何一个编码是其他编码的前缀。它通过构建一个**最优二叉树**,使得频率越高的字符编码越短,从而减少整体编码的长度,实现数据压缩。 + +### 主要步骤 + +1. **统计字符频率**:计算待压缩数据中每个字符出现的频率。 +2. **构建优先队列**:将每个字符和其对应的频率作为一个节点,放入优先队列(最小堆)。 +3. **构建霍夫曼树**: + - 从优先队列中取出两个频率最小的节点,作为左右子节点,构造一个新的父节点,父节点的频率为左右子节点频率之和。 + - 将这个新的父节点插回优先队列中。 + - 重复上述过程,直到队列中只剩下一个节点,这个节点就是霍夫曼树的根节点。 +4. **生成编码**: + - 从霍夫曼树的根节点出发,给左边的分支标记为`0`,右边的分支标记为`1`。 + - 从根节点到每个叶子节点(即字符节点)路径上的`0`和`1`组合,构成该字符的霍夫曼编码。 + +### 示例 + +假设我们有如下字符及其出现频率: + +``` +字符 | 频率 +--------------- + A | 5 + B | 9 + C | 12 + D | 13 + E | 16 + F | 45 +``` + +#### 1. 统计频率 +初始优先队列: + +``` +(A, 5), (B, 9), (C, 12), (D, 13), (E, 16), (F, 45) +``` + +#### 2. 构建霍夫曼树 + +- 取出频率最小的两个节点 `(A, 5)` 和 `(B, 9)`,构造一个新节点 `(AB, 14)`,插回队列。 +- 队列更新为:`(AB, 14), (C, 12), (D, 13), (E, 16), (F, 45)` +- 取出 `(C, 12)` 和 `(D, 13)`,构造 `(CD, 25)`,插回队列。 +- 队列更新为:`(AB, 14), (CD, 25), (E, 16), (F, 45)` +- 取出 `(AB, 14)` 和 `(E, 16)`,构造 `(ABE, 30)`,插回队列。 +- 队列更新为:`(CD, 25), (ABE, 30), (F, 45)` +- 取出 `(CD, 25)` 和 `(ABE, 30)`,构造 `(CDEAB, 55)`,插回队列。 +- 队列更新为:`(CDEAB, 55), (F, 45)` +- 最后将 `(CDEAB, 55)` 和 `(F, 45)` 合并为根节点 `(Root, 100)`。 + +最终霍夫曼树: + +``` + [Root, 100] + / \ + [F, 45] [CDEAB, 55] + / \ + [CD, 25] [ABE, 30] + / \ / \ + [C,12][D,13][A,5] [B,9] [E,16] +``` + +#### 3. 生成编码 + +从根节点到每个字符的路径生成编码: + +``` +F: 0 +C: 100 +D: 101 +A: 1100 +B: 1101 +E: 111 +``` + +### 霍夫曼编码的优点 + +- **无损压缩**:霍夫曼编码不会丢失任何信息,解码后的数据与原始数据完全一致。 +- **高效性**:对于频率分布差异较大的字符集,霍夫曼编码能显著减少编码后的数据量。 +- **简单实现**:算法简单,适合软件实现。 + +### 霍夫曼编码的应用 + +- **文件压缩**:如ZIP和RAR等文件压缩格式。 +- **图像压缩**:如JPEG图像格式的压缩。 +- **数据传输**:在数据传输中减少带宽占用。 + +### 示例代码 (C++) + +以下是一个简单的C++实现霍夫曼编码的示例: + +```cpp +#include +#include +#include +#include + +using namespace std; + +// 定义霍夫曼树节点 +struct HuffmanNode { + char data; + int freq; + HuffmanNode *left, *right; + HuffmanNode(char data, int freq) : data(data), freq(freq), left(NULL), right(NULL) {} +}; + +// 比较器,用于优先队列 +struct compare { + bool operator()(HuffmanNode* l, HuffmanNode* r) { + return l->freq > r->freq; + } +}; + +// 打印霍夫曼编码 +void printCodes(HuffmanNode* root, string str) { + if (!root) return; + if (root->data != '$') cout << root->data << ": " << str << "\n"; + printCodes(root->left, str + "0"); + printCodes(root->right, str + "1"); +} + +// 构建霍夫曼树并打印编码 +void HuffmanCodes(char data[], int freq[], int size) { + HuffmanNode *left, *right, *top; + priority_queue, compare> minHeap; + + for (int i = 0; i < size; ++i) + minHeap.push(new HuffmanNode(data[i], freq[i])); + + while (minHeap.size() != 1) { + left = minHeap.top(); + minHeap.pop(); + + right = minHeap.top(); + minHeap.pop(); + + top = new HuffmanNode('$', left->freq + right->freq); + top->left = left; + top->right = right; + + minHeap.push(top); + } + + printCodes(minHeap.top(), ""); +} + +int main() { + char arr[] = { 'A', 'B', 'C', 'D', 'E', 'F' }; + int freq[] = { 5, 9, 12, 13, 16, 45 }; + int size = sizeof(arr) / sizeof(arr[0]); + + HuffmanCodes(arr, freq, size); + + return 0; +} +``` + +### 总结 + +霍夫曼编码是非常有效的无损压缩算法,特别适用于字符频率分布不均的情况。它的思想简单但非常实用,在许多领域得到了广泛应用。 diff --git a/notebook/mkdocs.yml b/notebook/mkdocs.yml index eea8b668..ddcdec70 100644 --- a/notebook/mkdocs.yml +++ b/notebook/mkdocs.yml @@ -16,8 +16,22 @@ nav: - 数学基础: - 进制转换: basic/math/进制转换.md - 矩阵运算: basic/math/矩阵运算.md + - C++库: + - 总结: C++/总.md + - iostream: C++/1.iostream.md + - fstream: C++/2.fstream.md + - sring: C++/3.string.md + - ctime: C++/4.ctime.md + - chrono: C++/5.chrono.md + - vector: C++/6.vector.md + - list: C++/7.list.md + - map: C++/8.map.md + - set: C++/9.set.md + - algorithm: C++/10.algorithm.md - 数据结构: - - 二叉树: data_structure/二叉树.md + - 二叉树: + - 二叉树: data_structure/二叉树.md + - 霍夫曼编码: data_structure/霍夫曼编码.md - 电子学会考级(机器人): - 历史人物: 电子学会考级/历史事件及人物.md