当前位置: 首页 > news >正文

数据结构-LRU缓存(C语言实现)

遇到困难,不必慌张,正是成长的时候,耐心一点!

目录

  • 前言
  • 一、题目介绍
  • 二、实现过程
    • 2.1 实现原理
    • 2.2 实现思路
      • 2.2.1 双向链表
      • 2.2.2 散列表
    • 2.3 代码实现
      • 2.3.1 结构定义
      • 2.3.2 双向链表操作实现
      • 2.3.3 实现散列表的操作
      • 2.3.4 内存释放代码
      • 2.3.5 题目代码实现
  • 总结

前言

本篇文章主要是为了记录实现LRU缓存的方法和思考的过程。

一、题目介绍

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;
如果不存在,则向缓存中插入该组 key-value 。
如果插入操作导致关键字数量超过 capacity ,则应该逐出最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

示例:
输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

提示:
1 <= capacity <= 3000
0 <= key <= 10000
0 <= value <= 105
最多调用 2 * 105 次 get 和 put

下面是本人的一些废话,不感兴趣可直接看实现过程

看完题目,看到函数 get 和 put 必须以 O(1) 的平均时间复杂度运行,第一反应是顺序存储的随机存取才可以实现O(1)的时间复杂度,也就是说一定会有一块连续的存储空间存储数据,且大小为capacity。可以把key对应连续的存储空间的下标,但是看到提示里面的key的范围超出了capacity的范围,那如何在让key在[0,capacity]循环呢?脑子直接想到了循环队列的取余法,因为最近用循环队列比较频繁。
但是,经过取余后,还是会造成出现重复的key,该怎们解决呢?突然想到数据结构里面的散列表的碰撞的处理,立马去看关于散列表的介绍,以前没学的东西,现在又冒出来找我了。
看了以后,觉得很神奇,原来取余法是散列函数的一种,并使用频繁的一种。然后又看了关于碰撞的处理,书上介绍两种,第一种叫开地址法,第二种方法叫拉链法。
解决了碰撞问题,那么如何实现最近最少使用,一想到这是关于链表的题目,慢慢想到了循环单链表,头插法实现最近使用,而尾结点一定是最少使用,也就是当缓存空间达到capacity时,需要删除的。但是写了一半代码,发现当访问结点为尾结点时,需要更改尾结点,也就是需要尾结点的前驱。我知道,在单链表中,寻找某个结点前驱时间复杂度是O(n),不符合题意,立马把代码删除。
经过思考,心情里变得比较烦躁,但又不想看题解,因为想着现在正是考验我的时候,想着这道题一定想要教会我什么。尝试让自己变得冷静,不断地翻开数据结构这本书,看到双向链表,哎,这不就是为了解决以O(1)时间复杂度访问某个结点前驱的问题嘛!为什么没有马上想到,是因为平时做的题目都是单链表,双向链表用的太少了…
以上问题都解决了后,刚开始使用开地址法的线性探查法解决碰撞时,发现最后几个测试用例超时了,但是,说明思路是对的,因为线性探访的最坏情况的时间复杂度就是O(n)。
然后改为使用了拉链法,写代码用的时间不多,调试用了很多时间,最终,在不放弃的情况下,终于找到了代码的某处错误。真是太不容易了,因为常规测试用例通过了,在一些复杂的测试用例没通过,又无法一步一步的调试,只能不断地阅读代码,最后发现是在某个很隐秘且常规测试用例很难覆盖的地方,我当场麻了…
所幸,最后还是一步一步的写出来了,还是非常开心的,感觉时间花的太值了!

二、实现过程

2.1 实现原理

实现原理:散列表+双向链表
散列表解决了key重复问题,并解决函数 get 和 put 必须以 O(1) 的平均时间复杂度运行的问题
双向链表解决了最近使用和最少使用的问题,头插法解决最近使用,尾结点解决了最少使用
结构图如图2.1所示:
在这里插入图片描述

图2.1 LRU原理图

2.2 实现思路

2.2.1 双向链表

为了方便双向链表的插入和删除操作,可以使用两个辅助结点,一个伪头部和一个伪尾部,实现了每个真实结点都有前驱和后继
在这里插入图片描述

图2.2.1 双向链表

2.2.2 散列表

这里主要想介绍解决碰撞问题的拉链法。
设散列表的大小为m,使用拉链法需要建立m条链表,所有散列地址相同的元素放在同一条链表中,如果某个地址中没有存放任何元素,则对应的链表为空链表。设关键码key,根据散列函数h计算出h(key),即可确定第h(key)条链表,然后在该链表进行插入和删除及检索操作。
在本题中,散列函数为取余法,散列表的大小为capacity
h ( k e y ) = k e y % c a p a c i t y h(key) = key \,\%\, capacity h(key)=key%capacity
在本题中, h a s h K e y = h ( k e y ) , h a s h V a l u e = h a s h T a b l e [ h a s h K e y ] hashKey = h(key), hashValue = hashTable[hashKey] hashKey=h(key),hashValue=hashTable[hashKey]
如下图所示
在这里插入图片描述

图2.2.1 散列表

2.3 代码实现

本篇文章的代码使用C语言实现

2.3.1 结构定义

//双向链表结点
struct DoubleNode
{int key;        //真实的keyint value;struct DoubleNode* llink;       //双向链表的前驱struct DoubleNode* rlink;      //双向链表的后继
};//双向链表类型
//为了方便操作,使用两个伪结点
struct DoubleList
{struct DoubleNode* dummyHead;    //双向链表的伪头部struct DoubleNode* dummyRear;    //双向链表的伪尾部  
};//哈希结点的定义
//相同hashKey构成的链表的结点类型
struct HashNode
{struct DoubleNode* address;         //指向双向链表的某个结点struct HashNode*   next;
};//使用双向链表
//保存双向链表的头结点
//散列函数       取余法 
//解决地址碰撞   拉链法   
typedef struct
{struct DoubleList* doubleList;      //双向链表struct HashNode**  hashTable;       //哈希表int capacity;                       //缓存空间大小int curCapacty;                     //已用空间
} LRUCache;

2.3.2 双向链表操作实现

//双向链表的操作
//初始化双向链表
void initDoubleList(struct DoubleList* doubleList)
{doubleList->dummyHead = (struct DoubleNode*)calloc(1, sizeof(struct DoubleNode));  //初始化双向链表的伪头部doubleList->dummyRear = (struct DoubleNode*)calloc(1, sizeof(struct DoubleNode));  //初始化双向链表的伪尾部//头和尾互连doubleList->dummyHead->rlink = doubleList->dummyRear;                              doubleList->dummyRear->llink = doubleList->dummyHead;
}//将某个结点向双向链表中的第一个结点前执行插入操作
void insertNodeToDoubleListFirst(struct DoubleList* doubleList, struct DoubleNode* node)
{node->rlink = doubleList->dummyHead->rlink;node->llink = doubleList->dummyHead;doubleList->dummyHead->rlink->llink = node;doubleList->dummyHead->rlink = node;
}//将node结点移动到双向链表的第一个结点
void moveNodeToHead(struct DoubleList* doubleList, struct DoubleNode* node)
{   //从双向链表中断开node->llink->rlink = node->rlink;node->rlink->llink = node->llink;//将断开的结点重新插入到双向链表的伪头部后insertNodeToDoubleListFirst(doubleList, node);
}

2.3.3 实现散列表的操作

//哈希表的操作
//散列函数
//取余法
int hashFunc(int key, int m)
{return key % m;
}//在hashTable查看对应的hashKey的结点是否指向已存在的key
struct HashNode* getHashNode(struct HashNode** hashTable, int hashKey, int key)
{for (struct HashNode* hashValue = hashTable[hashKey]; hashValue != NULL; hashValue = hashValue->next){if (hashValue->address->key == key){return hashValue;}}return NULL;
}//往哈希表插入一个HashNode(头插法)
void insertHashNodeToHashTable(struct HashNode** hashTable, int hashKey,struct HashNode* hnode)
{   hnode->next = hashTable[hashKey];hashTable[hashKey] = hnode; 
}//从哈希表hashTable[hashKey]->address == dnode的结点断开在之前的链表
struct HashNode* deleteHashNodeFromHashTable(struct HashNode** hashTable, int hashKey, struct DoubleNode* dnode)
{struct HashNode* pre_hashNode = hashTable[hashKey];struct HashNode* freeNode = NULL;if (pre_hashNode->address == dnode)   //如果第一个为删除结点,则将hashTable[hashKey] = pre_hashNode->next{freeNode = pre_hashNode;hashTable[hashKey] = pre_hashNode->next;}else                                //否则需要寻找address为dnode的前驱结点{while (pre_hashNode->next->address != dnode){pre_hashNode = pre_hashNode->next;}freeNode = pre_hashNode->next;pre_hashNode->next = pre_hashNode->next->next;}return freeNode;
}

2.3.4 内存释放代码

//释放hashTable的内存
void hashTableNodeListFree(struct HashNode** hashTable, int capacity)
{  for(int hashKey = 0; hashKey < capacity; hashKey++){//释放相同hashKey的链表结点内存for(struct HashNode* head = hashTable[hashKey]; head != NULL; NULL){struct HashNode* freeNode = head;head = head->next;free(freeNode);}}free(hashTable);
}//释放双向链表的内存
void doubleNodeListFree(struct DoubleList* doubleList)
{   //释放双向链表每一个数据结点空间for(struct DoubleNode* head = doubleList->dummyHead; head != NULL; NULL){struct DoubleNode* freeNode = head;head = head->rlink;free(freeNode);}//释放双向链表的头结点空间free(doubleList);
}

2.3.5 题目代码实现

LRUCache* lRUCacheCreate(int capacity)
{LRUCache* obj = (LRUCache*)calloc(1, sizeof(LRUCache));obj->capacity = capacity;obj->hashTable = (struct HashNode**)calloc(capacity, sizeof(struct HashNode*));obj->doubleList = (struct DoubleList*)calloc(1, sizeof(struct DoubleList));  //初始化双向链表initDoubleList(obj->doubleList);return obj;
}int lRUCacheGet(LRUCache* obj, int key)
{int hashKey = hashFunc(key, obj->capacity);struct HashNode* hashValue = getHashNode(obj->hashTable, hashKey, key);if(hashValue != NULL){moveNodeToHead(obj->doubleList, hashValue->address);return hashValue->address->value;}return -1;
}void lRUCachePut(LRUCache* obj, int key, int value)
{int hashKey = hashFunc(key, obj->capacity);//查看当前的hashKey是否存在//存在则修改valuestruct HashNode* hashValue = getHashNode(obj->hashTable, hashKey, key);if(hashValue != NULL){hashValue->address->value = value;moveNodeToHead(obj->doubleList, hashValue->address);return;}//当前的key对应的hashKey不存在//则将当前的key插入到hashTable中if (obj->curCapacty < obj->capacity)   //缓存空间未满  {   //新建一个双向链表的结点struct DoubleNode* dnode = (struct DoubleNode*)calloc(1, sizeof(struct DoubleNode));dnode->key = key;dnode->value = value;//新建一个HashNodestruct HashNode* hnode = (struct HashNode*)calloc(1, sizeof(struct HashNode));hnode->address = dnode;    //插入到哈希表insertHashNodeToHashTable(obj->hashTable, hashKey, hnode);//将dnode插入到双链表的头insertNodeToDoubleListFirst(obj->doubleList, dnode);obj->curCapacty++;}else    //缓存空间已满  重用旧的结点->需要切断旧结点以前的联系->重新赋值->新生{//逐出最近未使用的关键字,即双向链表的尾结点struct DoubleNode* dnode = obj->doubleList->dummyRear->llink;//重置dnode在hashTable的位置struct HashNode* hnode =  deleteHashNodeFromHashTable(obj->hashTable, hashFunc(dnode->key,obj->capacity), dnode);//将dnode重新赋值dnode->key    = key;dnode->value  = value;//使用原来的哈希结点,则 hnode->address = dnode 可省略insertHashNodeToHashTable(obj->hashTable, hashKey,hnode);moveNodeToHead(obj->doubleList, dnode);}
}void lRUCacheFree(LRUCache* obj)
{//先释放双向链表的内存doubleNodeListFree(obj->doubleList);//释放哈希表的内存hashTableNodeListFree(obj->hashTable, obj->capacity);//释放缓存的头结点内存free(obj);
}

总结

看到题目通过那瞬间,真的非常开心,但我知道,代码还有很多大优化的空间,希望能够持续不断地学习!
仅仅用这篇文章记录本人解题的过程,希望对读者有所帮助吧!

相关文章:

数据结构-LRU缓存(C语言实现)

遇到困难&#xff0c;不必慌张&#xff0c;正是成长的时候&#xff0c;耐心一点&#xff01; 目录 前言一、题目介绍二、实现过程2.1 实现原理2.2 实现思路2.2.1 双向链表2.2.2 散列表 2.3 代码实现2.3.1 结构定义2.3.2 双向链表操作实现2.3.3 实现散列表的操作2.3.4 内存释放代…...

javacv FFmpegFrameGrabber 阻塞重连解决方法汇总

JavaCV中FrameGrabber类可以连接直播流地址, 进行解码, 获取Frame帧信息, 常用方式如下 FrameGrabber grabber new FrameGrabber("rtsp:/192.168.0.0"); while(true) {Frame frame grabber.grabImage();// ... } 在如上代码中, 若连接地址网络不通, 或者连接超时…...

自然语言处理问答系统技术

自然语言处理问答系统技术 随着人工智能的不断发展&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术已成为推动智能问答系统发展的核心技术。问答系统是利用NLP来解析用户提出的问题&#xff0c;并从知识库中找到最相关的答案。在许多应用中&#xff0c;如智能客服、…...

交换机和路由器的区别

交换机和路由器的区别主要体现在以下几个方面&#xff1a; 工作层次不同&#xff1a;交换机通常工作在OSI模型的数据链路层&#xff08;第二层&#xff09;&#xff0c;主要根据MAC地址进行数据包转发。而路由器则工作在OSI模型的网络层&#xff08;第三层&#xff09;&#xf…...

JavaScript Array(数组)

JavaScript Array(数组) JavaScript 中的数组是一种特殊的对象,用于存储一系列有序的值。数组是 JavaScript 中非常强大的数据结构,广泛用于各种编程任务。本文将详细介绍 JavaScript 数组的特性、用法和操作方法。 数组的创建 在 JavaScript 中,创建数组有多种方式: …...

示例说明:elasticsearch实战应用

Elasticsearch 是一个基于 Lucene 的分布式搜索和分析引擎&#xff0c;广泛应用于日志分析、全文搜索、数据可视化等领域。以下是 Elasticsearch 实战应用的一些关键点和步骤&#xff1a; 1. 环境搭建 首先&#xff0c;你需要在你的环境中安装和配置 Elasticsearch。 安装 E…...

暴力匹配算法和 KMP 算法的优缺点分别是什么?

暴力匹配算法和 KMP 算法的优缺点分别是什么? 在字符串匹配领域,暴力匹配算法和 KMP(Knuth-Morris-Pratt)算法是两种常见的方法。它们各有特点,适用于不同的场景。让我们深入探讨这两种算法的优缺点。 一、暴力匹配算法 (一)优点 简单易实现:暴力匹配算法的逻辑非常…...

web笔记

<form method"POST" action"{{ url_for(register) }}"><label for"username">用户名:</label><input type"text" id"username" name"username" required><br><label for"p…...

【网络安全】-访问控制-burp(1~6)

文章目录 前言   1.Lab: Unprotected admin functionality  2.Lab: Unprotected admin functionality with unpredictable URL   3.Lab: User role controlled by request parameter   4.Lab:User role can be modified in user profile  5.Lab: User ID controlled by…...

iOS 项目中的多主题颜色设计与实现

引言 在现代iOS应用中&#xff0c;用户对个性化体验的需求越来越高&#xff0c;除了功能上的满足&#xff0c;多样的视觉风格也是提升用户体验的重要手段之一。提供多主题颜色的切换功能不仅能满足用户的审美偏好&#xff0c;还可以让应用更具活力&#xff0c;适应不同场景下的…...

Android Camera2 与 Camera API技术探究和RAW数据采集

Android Camera2 Android Camera2 是 Android 系统中用于相机操作的一套高级应用程序接口&#xff08;API&#xff09;&#xff0c;它取代了之前的 Camera API。以下是关于 Android Camera2 的一些主要信息&#xff1a; 主要特点&#xff1a; 强大的控制能力&#xff1a;提供…...

[python][pipenv]pipenv的使用

pipenv 是一个 Python 开发工作流程的工具&#xff0c;它旨在将 pip 的包管理和 virtualenv 的虚拟环境管理结合起来。以下是一些基本的 pipenv 使用方法&#xff1a; 安装 pipenv&#xff1a; 如果你还没有安装 pipenv&#xff0c;可以通过 pip 安装它&#xff1a; pip insta…...

SpringSession微服务

一.在linux中确保启动起来redis和nacos 依赖记得别放<dependencyManagement></dependencyManagement>这个标签去了 1.首先查看已经启动的服务 docker ps 查看有没有安装redis和nacos 2.启动redis和nacos 发现没有启动redis和nacos,我们先来启动它。&#xff0c;…...

强化学习:通过试错学习最优策略---示例:使用Q-Learning解决迷宫问题

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是一种让智能体&#xff08;agent&#xff09;在与环境交互的过程中&#xff0c;通过最大化某种累积奖励来学习如何采取行动的学习方法。它适用于那些需要连续决策的问题&#xff0c;比如游戏、自动驾驶和机器人控制…...

OpenGL ES 纹理(7)

OpenGL ES 纹理(7) 简述 通过前面几章的学习&#xff0c;我们已经可以绘制渲染我们想要的逻辑图形了&#xff0c;但是如果我们想要渲染一张本地图片&#xff0c;这就需要纹理了。 纹理其实是一个可以用于采样的数据集&#xff0c;比较典型的就是图片了&#xff0c;我们知道我…...

【C#】CacheManager:高效的 .NET 缓存管理库

在现代应用开发中&#xff0c;缓存是提升性能和降低数据库负载的重要技术手段。无论是 Web 应用、桌面应用还是移动应用&#xff0c;缓存都能够帮助减少重复的数据查询和处理&#xff0c;从而提高系统的响应速度。然而&#xff0c;管理缓存并不简单&#xff0c;尤其是当你需要处…...

【数学分析笔记】第4章第2节 导数的意义和性质(2)

4. 微分 4.2 导数的意义与性质 4.2.3 单侧导数 f ′ ( x ) lim ⁡ Δ x → 0 f ( x Δ x ) − f ( x ) Δ x lim ⁡ x → x 0 f ( x ) − f ( x 0 ) x − x 0 f(x)\lim\limits_{\Delta x\to 0}\frac{f(x\Delta x)-f(x)}{\Delta x}\lim\limits_{x\to x_0}\frac{f(x)-f(x_0)…...

深度学习:迁移学习

目录 一、迁移学习 1.什么是迁移学习 2.迁移学习的步骤 1、选择预训练的模型和适当的层 2、冻结预训练模型的参数 3、在新数据集上训练新增加的层 4、微调预训练模型的层 5、评估和测试 二、迁移学习实例 1.导入模型 2.冻结模型参数 3.修改参数 4.创建类&#xff…...

Footprint Growthly Quest 工具:赋能 Telegram 社区实现 Web3 飞速增长

作者&#xff1a;Stella L (stellafootprint.network) 在 Web3 的快节奏世界里&#xff0c;社区互动是关键。而众多 Web3 社区之所以能够蓬勃发展&#xff0c;很大程度上得益于 Telegram 平台。正因如此&#xff0c;Footprint Analytics 精心打造了 Growthly —— 一款专为 Tel…...

进入xwindows后挂起键盘鼠标没有响应@FreeBSD

问题&#xff1a; 在升级pkg包后&#xff0c;系统无法进入xfce等xwindows&#xff0c;表现为黑屏和看见鼠标&#xff0c;左上角有一个白字符块&#xff0c;键盘鼠标没有反应&#xff0c;整个系统卡住。但是可以ssh登录&#xff0c;内部的服务一切正常。 表现 处理过程&#xf…...

CentOS7.9 snmptrapd更改162端口

端口更改前: 命令: netstat -an |grep 162 [root@kibana snmp]# netstat -an | grep 162 udp 0 0 0.0.0.0:162 0.0.0.0:* unix 3 [ ] STREAM CONNECTED 45162 /run/systemd/journal/stdout u…...

模糊测试SFuzz亮相第32届中国国际信息通信展览会

9月25日&#xff0c;被誉为“中国ICT市场的创新基地和风向标”的第32届中国国际信息通信展在北京盛大开幕&#xff0c;本次展会将在为期三天的时间内&#xff0c;为信息通信领域创新成果、尖端技术和产品提供国家级交流平台。开源网安携模糊测试产品及相关解决方案精彩亮相&…...

CMake学习

向大佬lyf学习&#xff0c;先把其8服务器中所授fine 文章目录 前言一、CMakeList.txt 命令1. 最外层CMakeLists1.1 cmake_minimum_required&#xff08;&#xff09;1.2 project&#xff08;&#xff09;1.3 set&#xff08;&#xff09;1.4 add_subdirectory&#xff08;&…...

书生·浦语大模型全链路开源开放体系

书生浦语大模型全链路开源开放体系 大模型应用生态的发展和繁荣是建立在模型基座强大的通用基础能力之上的。上海AI实验室联合团队研究认为&#xff0c;大模型各项性能提升的基础在于语言建模能力的增强&#xff0c;对于大模型的研究应回归语言建模本质&#xff0c;通过更高质量…...

PHP安装swoole扩展无效,如何将文件上传至Docker容器

目录 过程 操作方式 过程 在没有使用过云服务器以前,Docker这个平台一直都很神秘。在我申请了华为云服务器,并使用WordPress镜像去搭建自己的网站以后,我不得不去把Docker平台弄清楚,原因是我使用的一个主题需要安装swoole扩展,才能够正常启用。而要将swoole.so这个扩展…...

Web3.0 应用项目

Web3.0 是下一代互联网的概念&#xff0c;旨在去中心化、用户拥有数据控制权和通过区块链技术实现信任的网络。Web3.0的应用项目主要集中在区块链、加密货币、去中心化应用 (DApps)、去中心化金融 (DeFi)、NFT&#xff08;非同质化代币&#xff09;等领域。以下是一些典型的 We…...

Linux 学习笔记(十六)—— 重定向与缓冲区

一、文件重定向 矩阵的下标&#xff0c;也就是文件描述符的分配规则&#xff0c;是从0开始空的最小的文件描述符分配给进程新打开的文件&#xff1b;文件输出重定向的原理是&#xff0c;关掉1&#xff08;输出&#xff09;&#xff0c;然后打开文件&#xff0c;这个新打开的文…...

828华为云征文|WordPress部署

目录 前言 一、环境准备 二、远程连接 三、WordPress简介 四、WordPress安装 1. 基础环境安装 ​编辑 2. WordPress下载与解压 3. 创建站点 4. 数据库配置 总结 前言 WordPress 是一个非常流行的开源内容管理系统&#xff08;Content Management System, CMS&#xf…...

华为开源自研AI框架昇思MindSpore应用案例:计算高效的卷积模型ShuffleNet

如果你对MindSpore感兴趣&#xff0c;可以关注昇思MindSpore社区 ShuffleNet ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有限的计算资源来达到…...

《C++ 小游戏:简易飞机大战游戏的实现》

文章目录 《C 游戏代码解析&#xff1a;简易飞机大战游戏的实现》一、游戏整体结构与功能概述二、各个类和函数的功能分析&#xff08;一&#xff09;BK类 - 背景类&#xff08;二&#xff09;hero_plane类 - 玩家飞机类&#xff08;三&#xff09;plane_bullet类 - 玩家飞机发…...

阿里云模板建站怎么样/百度关键词点击排名

题目 <https://leetcode.com/problems/median-of-two-sorted-arrays> 题意 给出两个有序的数组&#xff0c;找出这两个数组所有数的中位数。 Example 1: nums1 [1, 3] nums2 [2]The median is 2.0 Example 2: nums1 [1, 2] nums2 [3, 4]The median is (2 3)/2 2.5 …...

个人网站设计的意义/百度app推广方法

整数中 1 出现的次数(从 1 到 n 整数中 1 出现的次数)(三十一) 题目描述 求出 1~13 的整数中 1 出现的次数,并算出 100~1300 的整数中 1 出现的次数&#xff1f;为此他特别数了一下 1~13 中包含 1 的数字有 1、10、11、12、13 因此共出现 6 次,但是对于后面问题他就没辙了。A…...

关于自行建设门户网站的请示/网络营销的工具有哪些

D:\百度地图\百度地图\资料\百度地图与定位SDK\百度地图v3.5.0\BaiduMap_AndroidSDK_v3.5.0_All\BaiduMap_AndroidSDK_v3.5.0_Docs\doc\index.html public final class MapView extends ViewGroup ViewGroup是一个ViewGroup,是一个容器,学自定义View的时候我们就知道如果是一个…...

在线播放视频网站怎么做/网站运营推广方案

转载于&#xff1a;https://blog.csdn.net/u011700186/article/details/109452658 相关环境 MacOS 10.15.4 SecureCRT 8.7.0 问题描述 当某一个用户登录某一台服务器之后&#xff0c;我们可能会想要执行某些特定的命令或者脚本。比如&#xff0c;连接后我们想要自动切换到某…...

google网站收录入口/今日小说百度搜索风云榜

Python的功能十分强大&#xff0c;有很多令人意想不到的功能&#xff0c;学会python可以大大提高你的工作效率&#xff0c;帮助你解决人工重劳动。本期将继续向大家介绍python中的实用技能&#xff0c;本期的主题是&#xff1a;用Python批量发送带有正文和附件的邮件。让我们一…...

武汉 网站 合作伙伴/爱站网ip反域名查询

日常使用PHP开发较多&#xff0c;但是有些地方PHP的语言的瓶颈就显露出来了&#xff0c;例如&#xff0c;同样是抓取一个网站的内容&#xff0c;使用PHP需要较为复杂的正则匹配&#xff0c;效率较为低下。python具有丰富的类库&#xff0c;拿过来直接可以使用&#xff0c;功能强…...