菜鸟程序员:常用编程知识

菜鸟程序员:常用编程知识本文章总结了 c c 技术栈程序员常用的编程知识 该文章会持续更新

大家好,欢迎来到IT知识分享网。

1.有关Linux指令

2.C++容器

类型 描述 特点
1. vector 动态数组,可以通过下表访问,可以快速访问,可以尾部插入删除 支持动态大小调整,适用于需要随机访问 和动态增删元素的场景
list 双向链表,支持快速插入/删除 能够快速插入/删除,但是不支持随机访问元素
map 键值对集合,基于红黑树的实现 存储键值对,按键自动排序,不允许重复键

2.1 vector

动态数组:

​ 动态增加或减少,不用手动管理内存

#include <iostream> #include <vector> int main() { // 创建一个空的 vector 容器 std::vector<int> myVector; // 向 vector 容器尾部添加元素 myVector.push_back(3); myVector.push_back(7); myVector.push_back(12); // 使用迭代器遍历 vector 容器并输出其中的元素 std::cout << "Vector elements: "; for (auto it = myVector.begin(); it != myVector.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // 获取 vector 容器的大小和访问特定位置的元素 std::cout << "Vector size: " << myVector.size() << std::endl; std::cout << "Element at index 1: " << myVector[1] << std::endl; // 修改特定位置的元素 myVector[2] = 20; // 使用范围-based for 循环遍历 vector 并输出元素 std::cout << "Modified Vector elements: "; for (int num : myVector) { std::cout << num << " "; } std::cout << std::endl; // 清空 vector 容器 myVector.clear(); // 检查 vector 是否为空 if (myVector.empty()) { std::cout << "Vector is empty." << std::endl; } else { std::cout << "Vector is not empty." << std::endl; } return 0; } 

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2 list

双向链表:

​ 指向下一个节点和上一个节点。

#include <iostream> #include <list> int main() { // 创建一个存储整数的 list 容器 std::list<int> myList; // 在 list 尾部插入元素 myList.push_back(10); myList.push_back(20); myList.push_back(30); // 在 list 头部插入元素 myList.push_front(5); myList.push_front(15); // 使用迭代器遍历 list 并输出元素 std::cout << "List elements: "; for (auto it = myList.begin(); it != myList.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // 删除 list 中特定的元素值 myList.remove(20); // 使用范围-based for 循环遍历 list 并输出元素 std::cout << "List elements after removal: "; for (int num : myList) { std::cout << num << " "; } std::cout << std::endl; // 检查 list 是否为空 if (myList.empty()) { std::cout << "List is empty." << std::endl; } else { std::cout << "List is not empty." << std::endl; } return 0; } 

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.3 map

自平衡红黑树:

​ 用于储存键值对。

insert() : 向 map 中插入一个键值对。 erase() : 删除 map 中指定键的键值对。 find() : 查找指定键在 map 中的位置。 operator[] : 通过键访问对应的值。 size() : 返回 map 中键值对的数量。 empty() : 检查 map 是否为空。 clear() : 清空 map 中的所有键值对。 
#include <iostream> #include <map> int main() { // 创建一个存储 string 类型键和 int 类型值的 map 容器 std::map<std::string, int> myMap; // 向 map 中插入键值对 myMap["Alice"] = 25; myMap["Bob"] = 30; myMap["Charlie"] = 20; // 使用迭代器遍历 map 并输出键值对 std::cout << "Map elements: " << std::endl; for (auto it = myMap.begin(); it != myMap.end(); ++it) { std::cout << it->first << ": " << it->second << std::endl; } // 查找特定键在 map 中的位置 std::string searchKey = "Bob"; auto found = myMap.find(searchKey); if (found != myMap.end()) { std::cout << "Found " << searchKey << " with value: " << found->second << std::endl; } else { std::cout << searchKey << " not found in the map." << std::endl; } // 删除特定键的键值对 myMap.erase("Charlie"); // 检查 map 是否为空 if (myMap.empty()) { std::cout << "Map is empty." << std::endl; } else { std::cout << "Map is not empty." << std::endl; } return 0; } 

3.红黑树

3.1 节点定义

enum Color{RED, BLACK};//节点颜色 //约定value唯一 template<class T> struct RBTreeNode {//节点定义 RBTreeNode(const T& value = T(), Color color = RED) : _left(nullptr) , _right(nullptr) , _parent(nullptr) , _value(value) , _color(color) RBTreeNode<T>* _left; RBTreeNode<T>* _right; RBTreeNode<T>* _parent; T _value; Color _color; }; //节点一般为红色 

3.2 结构

 为了方便现关联式容器,在红黑树的实现中加入一个头结点。因为根节点必须是黑色,为了与根节点进行区分,将头节点给定为红色。让根节点的_parent指针域指向头节点,并且让头结点的_parent指针域指向红黑树根节点;_left指针域指向红黑树中最左侧节点,_right指针域指向红黑树中最右侧节点。 

在这里插入图片描述

3.3 性质

红黑树保证最长路径不超过最短路径的二倍,因而近似平衡(最短路径就是全黑节点,最长路径就是一个红节点一个黑节点,当从根节点到叶子节点的路径上黑色节点相同时,最长路径刚好是最短路径的两倍)

1、节点是红色或黑色 2、根是黑色 3、叶子节点(外部节点,空节点)都是黑色,这里的叶子节点指的是最底层的空节点(外部节点),下图中的那些null节点才是叶子节点,null节点的父节点在红黑树里不将其看作叶子节点。 4、红色节点的子节点都是黑色 红色节点的父节点都是黑色 从根节点到叶子节点的所有路径上不能有 2 个连续的红色节点 5、从任一节点到叶子节点的所有路径都包含相同数目的黑色节点。 

在这里插入图片描述

3.4 红黑树实现

enum Color{RED, BLACK};//节点颜色 template<class T> struct RBTreeNode {//节点定义 RBTreeNode(const T& value = T(), Color color = RED) : _left(nullptr) , _right(nullptr) , _parent(nullptr) , _value(value) , _color(color) {} RBTreeNode<T>* _left; RBTreeNode<T>* _right; RBTreeNode<T>* _parent; T _value; Color _color; }; //约定value唯一 template<class T> class RBTree { typedef RBTreeNode<T> Node; public: RBTree() { _head = new Node(); _head->_left = _head; _head->_right = _head; } ~RBTree() { Destroy(_head->_parent); delete _head; _head = nullptr; } // //插入 bool Insert(const T& value) { Node*& root = GetRoot(); //1.按照二叉搜索树的方式插入 if (root == nullptr) {//空树 root = new Node(value, BLACK); root->_parent = _head; _head->_left = root; _head->_right = root; return true; } //查找插入位置 Node* cur = root; Node* parent = cur->_parent; while (cur) { parent = cur;//保存其双亲 if (value < cur->_value) { cur = cur->_left; } else if (value > cur->_value) { cur = cur->_right; } else {//已存在 return false; } } //插入新节点 cur = new Node(value);//默认插入节点为红色 if (value < parent->_value) { parent->_left = cur; } else { parent->_right = cur; } cur->_parent = parent; //2.红黑树性质约束 while (parent != _head && parent->_color == RED) {//两个红色相连违法规则 Node* grandFather = parent->_parent; if (parent == grandFather->_left) { Node* uncle = grandFather->_right; //情况一:叔叔节点存在且为红 if (uncle && uncle->_color == RED) { parent->_color = BLACK; uncle->_color = BLACK; grandFather->_color = RED; //改变cur,继续向上调整 cur = grandFather; parent = cur->_parent; } else {//情况二或三:叔叔节点为空,或叔叔节点存在且为黑 //因为情况三可以调整为情况二,所有先处理情况三 if (cur == parent->_right) { //将情况三转换为情况二 RotateLeft(parent); std::swap(parent, cur); } //情况二 parent->_color = BLACK; grandFather->_color = RED; RotateRight(grandFather); } } else {//三种情况的对称情况-->解决方法相同 Node* uncle = grandFather->_left; if (uncle && uncle->_color == RED) {//情况一 parent->_color = BLACK; uncle->_color = BLACK; grandFather->_color = RED; //改变cur,继续向上调整 cur = grandFather; parent = cur->_parent; } else {//情况二或三 if (cur == parent->_left) {//情况三 //调整为情况二 RotateRight(parent); std::swap(cur, parent); } //情况二 parent->_color = BLACK; grandFather->_color = RED; RotateLeft(grandFather); } } } //最后根节点可能被调整为了红色,所以需要被改回黑色 root->_color = BLACK; //3.更新头结点左右指针域--插入元素可能改变树的最值 _head->_left = MostLeft(); _head->_right = MostRight(); return true; } / //查找 Node* Find(const T& value) { Node*& root = GetRoot(); if (root == nullptr) return nullptr; Node* cur = root; while (cur) { if (value < cur->_value) { cur = cur->_left; } else if (value > cur->_value) { cur = cur->_right; } else { return cur; } } return nullptr; } //检测是否是红黑树 bool IsRBTree() { Node* root = GetRoot(); if (root == nullptr) return true; if (root->_color == RED) { //检测性质2 std::cout << "FALSE: 根节点为红色!" << std::endl; return false; } int blackCount = 0; Node* cur = root; while (cur) {//统计一条路径黑色节点个数 if (cur->_color == BLACK) ++blackCount; cur = cur->_left; } return _IsRBTree(root, blackCount, 0); } //中序遍历 void InOrder() { _InOrder(GetRoot()); std::cout << std::endl; } //获取最值 int GetMax() { return MostRight()->_value; } int GetMin() { return MostLeft()->_value; } private: //获取根节点 Node*& GetRoot() { return _head->_parent; } //获取树的最值节点 Node* MostLeft() {//最左侧节点 Node*& root = GetRoot(); if (root == nullptr) return _head; Node* cur = root; while (cur->_left) { cur = cur->_left; } return cur; } Node* MostRight() {//最右侧节点 Node*& root = GetRoot(); if (root == nullptr) return _head; Node* cur = root; while (cur->_right) { cur = cur->_right; } return cur; } //左单旋 void RotateLeft(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; if (subRL) {//注意subrl可能为空 subRL->_parent = parent; } subR->_left = parent; //跟新parent和subR的双亲节点 //先保存好parent原先的双亲节点 Node* pparent = parent->_parent; parent->_parent = subR; subR->_parent = pparent; //处理上层节点 if (pparent == _head) {//已经更新到根节点 _head->_parent = subR; } else { if (parent == pparent->_left) { pparent->_left = subR; } else { pparent->_right = subR; } } } //右单旋 void RotateRight(Node* parent) { //其思想与左单旋相同 Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR) { subLR->_parent = parent; } subL->_right = parent; Node* pparent = parent->_parent; parent->_parent = subL; subL->_parent = pparent; if (pparent == _head) { _head->_parent = subL; } else { if (parent == pparent->_left) { pparent->_left = subL; } else { pparent->_right = subL; } } } //检测是否满足红黑树特性 bool _IsRBTree(Node* root, const int blackNum, int count) { if (root == nullptr) return true; if (root->_color == BLACK) ++count;//统计路径内的黑色节点 //检测是否满足性质3 if (root->_parent != _head && root->_color == RED && root->_parent->_color == RED) { std::cout << "FALSE: 存在两个相连的红色节点!" << std::endl; return false; } if (root->_left == nullptr && root->_right == nullptr) { //是叶子节点,此路径统计结束 return count == blackNum;//检测性质4 } return _IsRBTree(root->_left, blackNum, count) && _IsRBTree(root->_right, blackNum, count); } //中序遍历 void _InOrder(Node*& root) { if (root == nullptr) return; _InOrder(root->_left); std::cout << root->_value << " "; _InOrder(root->_right); } //销毁 void Destroy(Node* root) { if (root == nullptr) return; Destroy(root->_left); Destroy(root->_right); delete root; root = nullptr; } private: Node* _head; }; 

4.libev库定时器

4.1 定时器的初始化

//定时器初始化 struct ev_loop *loop = EV_DEFAULT;//通过 EV_DEFAULT 宏,获取到默认的事件循环。 ev_timer timer; ev_timer_init(&timer, timerCallback, 0.0, 2.0); // 2秒定时器 timer.data = this->Mcfcb; // timer这个结构体中date的初始化 ev_timer_start(loop, &timer);//将定时器 timer 添加到事件循环 loop 中,并开始计时。如果定时器的延迟时间已过(在这个例子中是 0.0),它会立即触发;否则,它会在指定的延迟时间后触发。 ev_run(loop, 0);//启动事件循环。ev_run 函数会阻塞调用线程,直到没有更多活动的事件监听器或调用了 ev_break 函数。参数 0 表示使用默认的行为(即无限循环,直到没有更多事件或调用了 ev_break)。 
ev_run(loop, int flags); /* libev 中常见的 flags 参数包括: 0 或 EVRUN_DEFAULT:这是默认值,表示事件循环将无限期地运行,直到没有活动的事件监听器为止。 EVRUN_ONCE:事件循环将只运行一次,处理当前所有待处理的事件,然后退出。 EVRUN_NOWAIT:事件循环将检查是否有待处理的事件,如果有则处理它们,并立即返回,而不会等待新事件的到来。*/ 

4.2 回调函数

void CUpReportPeriodData::timerCallback(struct ev_loop *loop, ev_timer *w, int revents) { struct C_FCB *self = static_cast<struct C_FCB*>(w->data); std::cout<<"ZHW into CB"<<"FCB:"<<self->FCB<<","<<"flag:"<<self->flag<<","<<revFlag<<std::endl; //如果FCB不为0,FCB--,再次更新控制域,发送报文 if (revFlag == 1) { std::cout<<"zhw:"<<self->FCB<<std::endl; ev_timer_stop(loop, w); } else if(revFlag==0) { if(self->FCB > 0) { self->FCB--; std::cout<<"FCB:"<<self->FCB<<std::endl; } else if(self->FCB==0) { revFlag=1; } ev_timer_stop(loop, w); } } 
void timerCallback(struct ev_loop *loop, ev_timer *w, int revents); /* 一般revents这个函数不会被使用 struct ev_loop *loop: 这是一个指向当前事件循环的指针。libev 允许有多个事件循环实例,但这个函数通常只与触发它的那个事件循环相关。在这个回调函数中,可以使用这个指针来访问和操作该事件循环,比如添加新的watcher、修改定时器等。 ev_timer *w: 指向触发回调函数的定时器watcher的指针。通过这个指针,可以访问定时器watcher的所有属性,包括与定时器相关联的用户数据(通过 w->data 访问)。 revents: 一般这个函数不会被使用。 */ 

5. CJSON

5.1 JSON数据封装

在这里插入图片描述

#include <stdio.h> #include "cJSON.h" int main(void) { 
    cJSON* cjson_test = NULL; cJSON* cjson_address = NULL; cJSON* cjson_skill = NULL; char* str = NULL; /* 创建一个JSON数据对象(链表头结点) */ cjson_test = cJSON_CreateObject(); /* 添加一条字符串类型的JSON数据(添加一个链表节点) */ cJSON_AddStringToObject(cjson_test, "name", "mculover666"); /* 添加一条整数类型的JSON数据(添加一个链表节点) */ cJSON_AddNumberToObject(cjson_test, "age", 22); /* 添加一条浮点类型的JSON数据(添加一个链表节点) */ cJSON_AddNumberToObject(cjson_test, "weight", 55.5); /* 添加一个嵌套的JSON数据(添加一个链表节点) */ cjson_address = cJSON_CreateObject(); cJSON_AddStringToObject(cjson_address, "country", "China"); cJSON_AddNumberToObject(cjson_address, "zip-code", ); cJSON_AddItemToObject(cjson_test, "address", cjson_address); /* 添加一个数组类型的JSON数据(添加一个链表节点) */ cjson_skill = cJSON_CreateArray(); cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" )); cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java" )); cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" )); cJSON_AddItemToObject(cjson_test, "skill", cjson_skill); /* 添加一个值为 False 的布尔类型的JSON数据(添加一个链表节点) */ cJSON_AddFalseToObject(cjson_test, "student"); /* 打印JSON对象(整条链表)的所有数据 */ str = cJSON_Print(cjson_test); printf("%s\n", str); return 0; } 

5.2 JSON数据解析

/* 1.创建链表头指针 */ cJSON* cjson_test = NULL; 
/* 2.数据解析: 数据解析的API只有1个,返回的是链表头节点的地址 (cJSON *) cJSON_Parse(const char *value) */ cjson_test=(cJSON *) cJSON_Parse(str); 
/* 3.根据键值对的名称从链表中去除对应的值,返回的是该键值对的地址 (cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); */ cJSON* cjson_get=(cJSON *) cJSON_GetObjectItem(cjson_test, "zhw"); 
/* 4.提取数组的数据: (int) cJSON_GetArraySize(const cJSON *array); (cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); */ 
char *message = "{ \ \"name\":\"mculover666\", \ \"age\": 22, \ \"weight\": 55.5, \ \"address\": \ { \ \"country\": \"China\",\ \"zip-code\": \ }, \ \"skill\": [\"c\", \"Java\", \"Python\"],\ \"student\": false \ }"; cJSON* cjson_test = NULL; cJSON* cjson_name = NULL; cJSON* cjson_age = NULL; cJSON* cjson_weight = NULL; cJSON* cjson_address = NULL; cJSON* cjson_address_country = NULL; cJSON* cjson_address_zipcode = NULL; cJSON* cjson_skill = NULL; cJSON* cjson_student = NULL; int skill_array_size = 0, i = 0; cJSON* cjson_skill_item = NULL; /* 解析整段JSO数据 */ cjson_test = cJSON_Parse(message); if(cjson_test == NULL) { printf("parse fail.\n"); return -1; } /* 依次根据名称提取JSON数据(键值对) */ cjson_name = cJSON_GetObjectItem(cjson_test, "name"); cjson_age = cJSON_GetObjectItem(cjson_test, "age"); cjson_weight = cJSON_GetObjectItem(cjson_test, "weight"); printf("name: %s\n", cjson_name->valuestring); printf("age:%d\n", cjson_age->valueint); printf("weight:%.1f\n", cjson_weight->valuedouble); /* 解析嵌套json数据 */ cjson_address = cJSON_GetObjectItem(cjson_test, "address"); cjson_address_country = cJSON_GetObjectItem(cjson_address, "country"); cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code"); printf("address-country:%s\naddress-zipcode:%d\n", cjson_address_country->valuestring, cjson_address_zipcode->valueint); /* 解析数组 */ cjson_skill = cJSON_GetObjectItem(cjson_test, "skill"); skill_array_size = cJSON_GetArraySize(cjson_skill); printf("skill:["); for(i = 0; i < skill_array_size; i++) { cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i); printf("%s,", cjson_skill_item->valuestring); } printf("\b]\n"); /* 解析布尔型数据 */ cjson_student = cJSON_GetObjectItem(cjson_test, "student"); if(cjson_student->valueint == 0) { printf("student: false\n"); } else { printf("student:error\n"); } return 0; 

在这里插入图片描述

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/138088.html

(0)
上一篇 2025-06-15 17:26
下一篇 2025-06-15 17:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信