消息队列LiteQueue

文章目录

  • 一、简介
  • 二、设计
    • 2.1 队列结构设计
    • 2.2 队列接口设计
  • 三、实现
    • 3.1 队列锁的实现
    • 3.2 创建队列
    • 3.3 写入队列
    • 3.4 读出数据
    • 3.5 判断队列是否为空
    • 3.6 判断队列是否为满
    • 3.7 清空队列
    • 3.8 删除队列
  • 四、测试
  • 参考

一、简介

  • 收到消息时先把接收到的消息放到队列中。
  • 在任务中从队列获取数据。
  • 如果解析过程中再来一帧数据,这帧数据会先存放在消息队列中。
  • 当队列中的上一帧数据解析完成后,任务会从队列中的下一条数据开始解析处理,以此循环,直到队列中的消息解析处理完毕。

二、设计

2.1 队列结构设计

有头尾指针分别指向写入的位置和读出的位置
需要配置队列中最多能存储几帧数据即几个列表项,每一项有多大的空间去保存接收到的数据
在这里插入图片描述
LiteQueue相当于是头部,后面紧跟着的是数据,而且每一个数据的存储大小都是确定的。
考虑到多线程不能同时读或者写,要互斥访问,因此还需要加一个读写锁

/*
LiteQueue : Structure describing queue parameters.
item_num_x: Number of items.
item_size : The size of each list item set when creating the queue,
            unit: bytes, used to store data received in the queue.
item_size : The counter of items
*/
typedef struct {    
    volatile uint8_t  queue_write_lock;
    volatile uint8_t  queue_read_lock;
    
    uint8_t   *head;    
    uint8_t   *tail;
    size_t    item_num;    
    size_t    item_size;
    size_t    item_count; 
}LiteQueue,   *pLiteQueue;

2.2 队列接口设计

使用队列前必定先要创建队列,并确定创建队列的大小,其次是读写队列的接口,以及判断队列是否为空/满、清空队列、删除队列

LiteQueue *LiteQueue_Create(size_t item_num, size_t item_size);  
LiteQueue_Status Write_To_LiteQueue(LiteQueue *queue, uint8_t *buff);  
LiteQueue_Status Read_From_LiteQueue(LiteQueue *queue, uint8_t *buff);
LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue);
LiteQueue_Status LiteQueue_Clear(LiteQueue *queue);
LiteQueue_Status LiteQueue_Delete(LiteQueue *queue);
LiteQueue_Status isLiteQueue_Full(LiteQueue *queue); 
LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue); 

队列的状态用一个枚举类型实现

typedef enum{    
    LITE_QUEUE_IDLE = 0,    
    LITE_QUEUE_BUSY,   
    LITE_QUEUE_ERR,    
    LITE_QUEUE_OK,
    LITE_QUEUE_EMPTY,   
    LITE_QUEUE_NONEMPTY,
    LITE_QUEUE_FULL,
    LITE_QUEUE_NONFULL
}LiteQueue_Status;

三、实现

3.1 队列锁的实现

队列锁使用宏定义的方式实现

typedef enum{    
    LITE_QUEUE_UNLOCK = 0, 
    LITE_QUEUE_LOCK,
}LiteQueueLock;

#define  LITE_QUEUE_WRITE_LOCK(__QUEUE__) do{            \
    if((__QUEUE__)->queue_write_lock == LITE_QUEUE_LOCK){\
        return LITE_QUEUE_BUSY;                          \
    } else {                                             \
        (__QUEUE__)->queue_write_lock = LITE_QUEUE_LOCK; \
    }                                                    \
}while(0) 

#define  LITE_QUEUE_WRITE_UNLOCK(__QUEUE__) do{          \
    (__QUEUE__)->queue_write_lock = LITE_QUEUE_UNLOCK;   \
}while(0)                                                  
       
#define  LITE_QUEUE_READ_LOCK(__QUEUE__) do{             \
    if((__QUEUE__)->queue_read_lock == LITE_QUEUE_LOCK){ \
        return LITE_QUEUE_BUSY;                          \
    } else {                                             \
        (__QUEUE__)->queue_read_lock = LITE_QUEUE_LOCK;  \
    }                                                    \
}while(0)       

#define  LITE_QUEUE_READ_UNLOCK(__QUEUE__) do{           \
    (__QUEUE__)->queue_read_lock = LITE_QUEUE_UNLOCK;    \
}while(0)  

3.2 创建队列

/**
* @ brief : Create message queue.
* @ param : {size_t     } item_num : The number of list items in the queue.
            {size_t     } item_size: The size of each list item, unit: bytes.
* @ return: {LiteQueue *} queue    : Message queue handle pointer.
* @ note  : Create a queue and initialize the queue items to 0, with the head and tail pointers pointing to the starting position of the list items.
*/
LiteQueue *LiteQueue_Create(size_t item_num, size_t item_size){
    if((item_num < 1) || (item_size < 1)){
        return NULL;
    }
    
    LiteQueue *queue = (LiteQueue *)malloc(sizeof(LiteQueue) + item_num * item_size);
    
    if( queue == NULL ) {
        printf("LiteQueue malloc failed.\r\n");
        return NULL;
    }
    
    memset((uint8_t *)queue, 0, sizeof(LiteQueue) + item_num * item_size);
    queue->head = (uint8_t *)((uint8_t *)queue + sizeof(LiteQueue));
    queue->tail = queue->head;
    queue->item_num = item_num;
    queue->item_size = item_size;
    queue->item_count = 0;
    queue->queue_read_lock = LITE_QUEUE_UNLOCK;
    queue->queue_write_lock = LITE_QUEUE_UNLOCK;
    
    return queue;
}

3.3 写入队列

/**
* @ brief : Write data to the queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
            {uint8_t        *} buff : Data to be written to the queue.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Writing data when the queue is full will automatically overwrite the first frame of data.
*/
LiteQueue_Status Write_To_LiteQueue(LiteQueue *queue, uint8_t *buff){
    if((queue == NULL) || (buff == NULL)){
        return LITE_QUEUE_ERR;
    }
    
    LITE_QUEUE_WRITE_LOCK(queue);
    
    if(isLiteQueue_Full(queue) == LITE_QUEUE_FULL){
            return LITE_QUEUE_FULL;
        }
    
    memcpy(queue->tail, buff, queue->item_size);
    
    if(queue->tail == (uint8_t *)queue + sizeof(LiteQueue) + (queue->item_num - 1) * queue->item_size){
        queue->tail = (uint8_t *)queue + sizeof(LiteQueue);
    }else{
        queue->tail += queue->item_size;
    }
    queue->item_count += 1;
    
    LITE_QUEUE_WRITE_UNLOCK(queue);
    return LITE_QUEUE_OK;
}

3.4 读出数据

/**
* @ brief : Read data from queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
            {uint8_t        *} buff : Data to be read from the queue.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Read data starting from the position of the head pointer and save it to the buff.
*/
LiteQueue_Status Read_From_LiteQueue(LiteQueue *queue, uint8_t *buff){
    if((queue == NULL) || (buff == NULL) || (isLiteQueue_Empty(queue) == LITE_QUEUE_EMPTY)){
        return LITE_QUEUE_ERR;
    }
    
    LITE_QUEUE_READ_LOCK(queue);
    if(isLiteQueue_Empty(queue) == LITE_QUEUE_EMPTY){
            return LITE_QUEUE_EMPTY;
        }
    memcpy(buff, queue->head, queue->item_size);  
    if(queue->head == (uint8_t *)queue + sizeof(LiteQueue) + (queue->item_num - 1) * queue->item_size){
        queue->head = (uint8_t *)queue + sizeof(LiteQueue);
    }else{
        queue->head += queue->item_size;
    }
    
    queue->item_count -= 1;
    LITE_QUEUE_READ_UNLOCK(queue);
    return LITE_QUEUE_OK;  
}

3.5 判断队列是否为空

/**
* @ brief : Determine whether the queue is empty.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. If they are the same,             
            it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
inline LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue){
    if(queue == NULL){
        return LITE_QUEUE_ERR;
    }
    
    if( queue->item_count == 0 ) {
        return LITE_QUEUE_EMPTY;
    }else{
        return LITE_QUEUE_NONEMPTY;
    } 
}

3.6 判断队列是否为满

/**
* @ brief : Determine whether the queue is full.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. If they are the same,             
            it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
inline LiteQueue_Status isLiteQueue_Full(LiteQueue *queue){
    if(queue == NULL){
        return LITE_QUEUE_ERR;
    }
    
    if( queue->item_count == queue->item_num) {
            return LITE_QUEUE_FULL;
    }else{
            return LITE_QUEUE_NONFULL;
    } 
}

3.7 清空队列

/**
* @ brief : Clear the message queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. 
            If they are the same,it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
LiteQueue_Status LiteQueue_Clear(LiteQueue *queue){
    if(queue == NULL) {
        return LITE_QUEUE_ERR;
    }
    LITE_QUEUE_WRITE_LOCK(queue);
    queue->head = (uint8_t *)((uint8_t *)queue + sizeof(LiteQueue));
    queue->tail = queue->head;
    queue->item_count = 0;
    
    memset(queue->head, 0, queue->item_num * queue->item_size);
    LITE_QUEUE_WRITE_UNLOCK(queue);
    return LITE_QUEUE_OK;
}

3.8 删除队列

/**
* @ brief : Clear the message queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. 
            If they are the same,it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
LiteQueue_Status LiteQueue_Delete(LiteQueue *queue){
    if(queue == NULL) {
        return LITE_QUEUE_ERR;
    }
    //memset((uint8_t *)queue, 0, sizeof(LiteQueue) + queue->item_num * queue->item_size);
    free(queue);
    queue = NULL;
    return LITE_QUEUE_OK;
}

四、测试

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char uint8_t;
typedef unsigned int  uint32_t;

/*
LiteQueue : Structure describing queue parameters.
item_num_x: Number of items.
item_size : The size of each list item set when creating the queue,
            unit: bytes, used to store data received in the queue.
*/
typedef struct {    
    volatile uint8_t  queue_write_lock;
    volatile uint8_t  queue_read_lock;
    
    uint8_t   *head;    
    uint8_t   *tail;
    size_t    item_num;    
    size_t    item_size;
    size_t    item_count; 
}LiteQueue,   *pLiteQueue;

typedef enum{    
    LITE_QUEUE_IDLE = 0,    
    LITE_QUEUE_BUSY,   
    LITE_QUEUE_ERR,    
    LITE_QUEUE_OK,
    LITE_QUEUE_EMPTY,   
    LITE_QUEUE_NONEMPTY,
    LITE_QUEUE_FULL,
    LITE_QUEUE_NONFULL
}LiteQueue_Status;

typedef enum{    
    LITE_QUEUE_UNLOCK = 0, 
    LITE_QUEUE_LOCK,
}LiteQueueLock;

#define  LITE_QUEUE_WRITE_LOCK(__QUEUE__) do{            \
    if((__QUEUE__)->queue_write_lock == LITE_QUEUE_LOCK){\
        return LITE_QUEUE_BUSY;                          \
    } else {                                             \
        (__QUEUE__)->queue_write_lock = LITE_QUEUE_LOCK; \
    }                                                    \
}while(0) 

#define  LITE_QUEUE_WRITE_UNLOCK(__QUEUE__) do{          \
    (__QUEUE__)->queue_write_lock = LITE_QUEUE_UNLOCK;   \
}while(0)                                                  
       
#define  LITE_QUEUE_READ_LOCK(__QUEUE__) do{             \
    if((__QUEUE__)->queue_read_lock == LITE_QUEUE_LOCK){ \
        return LITE_QUEUE_BUSY;                          \
    } else {                                             \
        (__QUEUE__)->queue_read_lock = LITE_QUEUE_LOCK;  \
    }                                                    \
}while(0)       

#define  LITE_QUEUE_READ_UNLOCK(__QUEUE__) do{           \
    (__QUEUE__)->queue_read_lock = LITE_QUEUE_UNLOCK;    \
}while(0)   


LiteQueue *LiteQueue_Create(size_t item_num, size_t item_size);  
LiteQueue_Status Write_To_LiteQueue(LiteQueue *queue, uint8_t *buff);  
LiteQueue_Status Read_From_LiteQueue(LiteQueue *queue, uint8_t *buff);
LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue);
LiteQueue_Status LiteQueue_Clear(LiteQueue *queue);
LiteQueue_Status LiteQueue_Delete(LiteQueue *queue);
LiteQueue_Status isLiteQueue_Full(LiteQueue *queue); 
LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue); 

/**
* @ brief : Create message queue.
* @ param : {size_t     } item_num : The number of list items in the queue.
            {size_t     } item_size: The size of each list item, unit: bytes.
* @ return: {LiteQueue *} queue    : Message queue handle pointer.
* @ note  : Create a queue and initialize the queue items to 0, with the head and tail pointers pointing to the starting position of the list items.
*/
LiteQueue *LiteQueue_Create(size_t item_num, size_t item_size){
    if((item_num < 1) || (item_size < 1)){
        return NULL;
    }
    
    LiteQueue *queue = (LiteQueue *)malloc(sizeof(LiteQueue) + item_num * item_size);
    
    if( queue == NULL ) {
        printf("LiteQueue malloc failed.\r\n");
        return NULL;
    }
    
    memset((uint8_t *)queue, 0, sizeof(LiteQueue) + item_num * item_size);
    queue->head = (uint8_t *)((uint8_t *)queue + sizeof(LiteQueue));
    queue->tail = queue->head;
    queue->item_num = item_num;
    queue->item_size = item_size;
    queue->item_count = 0;
    queue->queue_read_lock = LITE_QUEUE_UNLOCK;
    queue->queue_write_lock = LITE_QUEUE_UNLOCK;
    
    return queue;
}

/**
* @ brief : Write data to the queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
            {uint8_t        *} buff : Data to be written to the queue.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Writing data when the queue is full will automatically overwrite the first frame of data.
*/
LiteQueue_Status Write_To_LiteQueue(LiteQueue *queue, uint8_t *buff){
    if((queue == NULL) || (buff == NULL)){
        return LITE_QUEUE_ERR;
    }
    
    LITE_QUEUE_WRITE_LOCK(queue);
    
    if(isLiteQueue_Full(queue) == LITE_QUEUE_FULL){
            return LITE_QUEUE_FULL;
        }
    
    memcpy(queue->tail, buff, queue->item_size);
    
    if(queue->tail == (uint8_t *)queue + sizeof(LiteQueue) + (queue->item_num - 1) * queue->item_size){
        queue->tail = (uint8_t *)queue + sizeof(LiteQueue);
    }else{
        queue->tail += queue->item_size;
    }
    queue->item_count += 1;
    
    LITE_QUEUE_WRITE_UNLOCK(queue);
    return LITE_QUEUE_OK;
}

/**
* @ brief : Read data from queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
            {uint8_t        *} buff : Data to be read from the queue.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Read data starting from the position of the head pointer and save it to the buff.
*/
LiteQueue_Status Read_From_LiteQueue(LiteQueue *queue, uint8_t *buff){
    if((queue == NULL) || (buff == NULL) || (isLiteQueue_Empty(queue) == LITE_QUEUE_EMPTY)){
        return LITE_QUEUE_ERR;
    }
    
    LITE_QUEUE_READ_LOCK(queue);
    if(isLiteQueue_Empty(queue) == LITE_QUEUE_EMPTY){
            return LITE_QUEUE_EMPTY;
        }
    memcpy(buff, queue->head, queue->item_size);  
    if(queue->head == (uint8_t *)queue + sizeof(LiteQueue) + (queue->item_num - 1) * queue->item_size){
        queue->head = (uint8_t *)queue + sizeof(LiteQueue);
    }else{
        queue->head += queue->item_size;
    }
    
    queue->item_count -= 1;
    LITE_QUEUE_READ_UNLOCK(queue);
    return LITE_QUEUE_OK;  
}

/**
* @ brief : Determine whether the queue is empty.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. If they are the same,             
            it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
inline LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue){
    if(queue == NULL){
        return LITE_QUEUE_ERR;
    }
    
    if( queue->item_count == 0 ) {
            return LITE_QUEUE_EMPTY;
        }else{
                return LITE_QUEUE_NONEMPTY;
        } 
}

/**
* @ brief : Determine whether the queue is full.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. If they are the same,             
            it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
inline LiteQueue_Status isLiteQueue_Full(LiteQueue *queue){
    if(queue == NULL){
        return LITE_QUEUE_ERR;
    }
    
    if( queue->item_count == queue->item_num) {
            return LITE_QUEUE_FULL;
        }else{
                return LITE_QUEUE_NONFULL;
        } 
}

/**
* @ brief : Clear the message queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. 
            If they are the same,it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
LiteQueue_Status LiteQueue_Clear(LiteQueue *queue){
    if(queue == NULL) {
        return LITE_QUEUE_ERR;
    }
    LITE_QUEUE_WRITE_LOCK(queue);
    queue->head = (uint8_t *)((uint8_t *)queue + sizeof(LiteQueue));
    queue->tail = queue->head;
    queue->item_count = 0;
    
    memset(queue->head, 0, queue->item_num * queue->item_size);
    LITE_QUEUE_WRITE_UNLOCK(queue);
    return LITE_QUEUE_OK;
}

/**
* @ brief : Clear the message queue.
* @ param : {LiteQueue      *} queue: Message queue handle pointer.
* @ return: {LiteQueue_Status} Returns the status of the queue.
* @ note  : Determine whether the head and tail pointers are the same. 
            If they are the same,it means there is no data in the queue, otherwise it means there is still data that has not been read out.
*/
LiteQueue_Status LiteQueue_Delete(LiteQueue *queue){
    if(queue == NULL) {
        return LITE_QUEUE_ERR;
    }
    //memset((uint8_t *)queue, 0, sizeof(LiteQueue) + queue->item_num * queue->item_size);
    free(queue);
    queue = NULL;
    return LITE_QUEUE_OK;
}

/**
* @ brief : Print the contents of each list item in the queue.
* @ param : {LiteQueue *} queue: Message queue handle pointer.
* @ return: None.
*/
static void PrintLiteQueue(LiteQueue *queue){
    if(queue == NULL){
        return ;
    }
    
    for(int i = 0; i < queue->item_num; i++){
        printf("[item_num:%d] ", i);
        for(int n = 0; n < queue->item_size; n++){
            printf("%d ", *((uint8_t *)queue + sizeof(LiteQueue) + i * queue->item_size + n));
        }
        printf("\r\n");
    }
}

/**
* @ brief : Print the data in buff.
* @ param : {LiteQueue *} queue: Message queue handle pointer.
* @ return: None.
* @ note  : Used to observe buff data changes and test to verify the correctness of written or read data.
*/
static void PrintBuff(uint8_t *buff, size_t len){
    if((buff == NULL) || (len < 1)){
        return ;
    }
    printf("Read buff<<<:");
    for(size_t i = 0; i < len; i++){
        printf("%d ", buff[i]);
    }
    printf("\r\n\r\n");
}

int main(){
    uint8_t writebuff[10] = {0};
    uint8_t readbuff[10]  = {0};
     /* Create message queue, 4 list items, each list item has 10 bytes of memory space */
    pLiteQueue msgQueue = LiteQueue_Create(4, 10);
    PrintLiteQueue(msgQueue);
    printf("\r\n");
    /* Simulate writing and reading to the queue 6 times, and observe the data in the queue by printing */
    for(int i=0;i<6;i++ ) {
        /* Simulate data, change the writebuff data and write it to the queue */
        for(int n = 0; n < msgQueue->item_size; n++){
            writebuff[n] = (i * msgQueue->item_size + n) % 256;
        }
        
        /* Data is written to the queue */
        Write_To_LiteQueue(msgQueue, writebuff);
        PrintLiteQueue(msgQueue);
        
        /* Read data from queue */
        Read_From_LiteQueue(msgQueue, readbuff);
        PrintBuff(readbuff, sizeof(readbuff));
    }
    return 0;
}

在这里插入图片描述

参考

https://mp.weixin.qq.com/s/vI3g4JmSXMyKrpnIV1vjbg

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[NAND Flash 4.2] Flash 原理 | NOR Flash 和 NAND Flash 闪存详解

依公知及经验整理,原创保护,禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< 前言 智能手机有一个可用的存储空间(如苹果128G),电脑里有一个固态硬盘空间(如联想512G), 这个空间是啥呢? 这个存储空间就是闪存设备,我们都统称为…

计算机网络课程设计-企业网三层架构

&#xff08;单人版&#xff09; 摘 要 本篇报告主要解决了为一家名为西宫的公司网络搭建问题&#xff0c;该网络采用企业网三层架构对完了过进行设计。首先使用以太网中继&#xff0c;主要使用VLAN划分的技术来划定不同部门。使用MSTP对每个组配置生成树&#xff0c;防止交换机…

华为交换机生成树STP配置案例

企业内部网络怎么防止网络出现环路&#xff1f;学会STP生成树技术就可以解决啦。 STP简介 在二层交换网络中&#xff0c;一旦存在环路就会造成报文在环路内不断循环和增生&#xff0c;产生广播风暴&#xff0c;从而占用所有的有效带宽&#xff0c;使网络变得无法正常通信。 在…

【JVM】一文掌握JVM垃圾回收机制

作为Java程序员,除了业务逻辑以外,随着更深入的了解,都无法避免的会接触到JVM以及垃圾回收相关知识。JVM调优是一个听起来很可怕,实际上很简单的事。 感到可怕,是因为垃圾回收相关机制都在JVM的C++层实现,我们在Java开发中看不见摸不着;而实际很简单,是因为它说到底,也…

12.29最小生成数K算法复习(注意输入输出格式),校园最短路径(通过PRE实现路径输出,以及输入输出格式注意)

7-2 最小生成树-kruskal算法 分数 15 const int maxn 1000; struct edge {int u, v, w; }e[maxn]; int n, m, f[30]; bool cmp(edge a, edge b) {return a.w < b.w; } int find(int x) {if (f[x] x) {return x;}else {f[x] find(f[x]);return f[x];} } //int arr[100…

Golang不可不知的7个并发概念

并发性支持是Golang最重要的原生特性之一&#xff0c;本文介绍了Golang中和并发性相关的7个概念。原文: Golang: 7 must-know concurrency related concepts 并发是Go编程语言的基本特性&#xff0c;意味着程序可以同时执行多个任务。Golang的并发独特而强大&#xff0c;其内置…

2 - 表结构 | MySQL键值

表结构 | MySQL键值 表管理1. 库的操作2. 表的操作表的创建与删除表的修改复制表 3. 管理表记录 数据类型数值类型字符类型&#xff08;汉字或者英文字母&#xff09;日期时间类型 表头存储与日期时间格式的数据枚举类型 数据批量处理 表管理 客户端把数据存储到数据库服务器上…

Redis7.2.3(Windows版本)

1、解压 &#xfeff; &#xfeff; 2、设置密码 &#xff08;1&#xff09; 右击编辑redis.conf文件&#xff1a; &#xfeff; &#xff08;2&#xff09; 设置密码。 &#xfeff; 3、测试密码是否添加成功 &#xfeff; 如上图所示&#xff0c;即为成功。 4、设置…

Linux学习第49天:Linux块设备驱动实验(一):Linux三大驱动之一

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本章学习Linux三大驱动之一的块设备驱动&#xff0c;主要应用场景为存储设备。 本章的思维导图如下&#xff1a; 一、什么是块设备 块设备---存储设备 以块为单位…

张量操作与线性回归

一、张量的操作&#xff1a;拼接、切分、索引和变换 &#xff08;1&#xff09;张量拼接与切分 1.1 torch.cat() 功能&#xff1a;将张量按维度dim进行拼接 • tensors: 张量序列 • dim : 要拼接的维度 torch.cat(tensors, dim0, outNone)函数用于沿着指定维度dim将多个张量…

数据结构模拟实现LinkedList双向不循环链表

目录 一、双向不循环链表的概念 二、链表的接口 三、链表的方法实现 &#xff08;1&#xff09;display方法 &#xff08;2&#xff09;size方法 &#xff08;3&#xff09;contains方法 &#xff08;4&#xff09;addFirst方法 &#xff08;5&#xff09;addLast方法 …

Java API 操作Docker浅谈

背景&#xff1a; 使用com.github.docker-java库可以很方便地在Java中操作Docker。下面是一个详细的教程&#xff0c;包括创建镜像、创建容器、启动容器、停止容器和删除容器的步骤以及每一步的说明。 前提&#xff1a; 首先&#xff0c;在你的Java项目中添加com.github.doc…

三、Mysql安全性操作[用户创建、权限分配]

一、用户 1.创建用户 CREATE USER test1localhost identified BY test1;2.删除用户 DROP USER test2localhost;二、权限分配 1.查询用户权限 SHOW GRANTS FOR test1localhost;2.分配权限 # 分配用户所有权限在for_end_test库的test1表 GRANT ALL PRIVILEGES ON for_end_t…

五分钟学完朴素贝叶斯算法

下面再描述一个详细的案例 个人感觉如下链接讲的比较详细 图解机器学习 | 朴素贝叶斯算法详解 - 知乎

2.3物理层下面的传输媒体

目录 2.3物理层下面的传输媒体2.3.1导引型传输媒体1.双绞线2.同轴电缆3.光纤 2.3.2非导引型传输媒体无线电微波通信 2.3物理层下面的传输媒体 传输媒体是数据传输系统中在发送器和接收器之间的物理通路 两大类&#xff1a; 导引型传输媒体&#xff1a;电磁波被导引沿着固体媒体…

新产品推广选品牌外包广州迅腾文化传播多渠道传播能力

在当今激烈的市场竞争中&#xff0c;新产品推广已成为企业发展的关键。选择具备多渠道传播能力的品牌外包服务提供商&#xff0c;有助于快速提升品牌知名度和市场占有率。作为行业领先者&#xff0c;迅腾文化凭借卓越的多渠道传播能力&#xff0c;成为企业新产品推广的理想合作…

国家开放大学形成性考核 统一考试 资料参考

试卷代号&#xff1a;11141 工程经济与管理 参考试题 一、单项选择题&#xff08;每题2分&#xff0c;共20分&#xff09; 1.资金的时间价值&#xff08; &#xff09;。 A.现在拥有的资金在将来投资时所能获得的利益 B.现在拥有的资金在将来消费时所付出的福利损失 C.…

saas 多租户系统数据隔离方案

关注WX公众号&#xff1a; commindtech77&#xff0c; 获得数据资产相关白皮书下载地址 1. 回复关键字&#xff1a;数据资源入表白皮书 下载 《2023数据资源入表白皮书》 2. 回复关键字&#xff1a;光大银行 下载 光大银行-《商业银行数据资产会计核算研究报告》 3. 回复关键字…

FreeRTOS学习第5篇--任务优先级

目录 FreeRTOS学习第5篇--任务优先级任务优先级设计实验任务一StartDefaultTask任务相关代码片段任务二ColorLED_Test任务相关代码片段任务三IRReceiver_Task相关代码片段实验现象本文中使用的测试工程 FreeRTOS学习第5篇–任务优先级 本文目标&#xff1a;学习与使用FreeRTOS…

关键字:throw关键字

在 Java 中&#xff0c;throw关键字用于抛出异常。当程序执行过程中发生意外情况&#xff0c;如错误的输入、资源不足、错误的逻辑等&#xff0c;导致程序无法正常执行下去时&#xff0c;可以使用throw关键字抛出异常。 以下是使用throw关键字的一些示例&#xff1a; 抛出异常…
最新文章