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

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", 111111);
    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\": 111111\
        },                      \
    \"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;


在这里插入图片描述

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值