【嵌入式】无需死背的硬件寄存器操作

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:不管是驱动,stm32,还是各类的国产芯片(比如匠芯创,杰理,或者是瑞芯微各类平台)都离不开底层硬件的控制,就是寄存器操作

提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是寄存器操作?

在我看来就是:在需要的操作的硬件寄存器管脚置1或者置0,同时不影响其他位

二、置1和置0操作

置1

xxxx|=(1<<yyyy);**//xxxx就是你要操作的寄存器,yyyy就是你要操作的第几位**

置0

xxxx&=~(1
我们来一步一步、**简单易懂地讲清楚**: 为什么链队列在不同指针设置下,入队和出队的时间复杂度不一样? --- # 🎯 题目重述 问题: 链队列中: - 如果**只设头指针**(`front`),则: - 入队:$ O(n) $ - 出队:$ O(1) $ - 如果**只设尾指针**(`rear`),则: - 入队:$ O(1) $ - 出队:$ O(n) $ 口诀记住: > 头指针 → 入队慢 $O(n)$,出队快 $O(1)$; > 尾指针 → 入队快 $O(1)$,出队慢 $O(n)$。 我们要搞明白:**这是什么原理?** --- # 🔧 先理解什么是“链队列” 链队列 = 用**链表实现的队列**,遵守“先进先出”规则。 - **入队**:从**队尾**插入新元素 - **出队**:从**队头**删除并返回元素 👉 所以理想情况是: - 能快速访问**队头**(出队快) - 能快速访问**队尾**(入队快) 但如果只用一个指针,就只能方便一端! --- ## ✅ 情况一:只设头指针 `front`(指向队首) ``` front ↓ [A] → [B] → [C] → nullptr ↑ ↑ ↑ 队头 队尾(没有指针指向它) ``` ### ❓ 如何出队? - 直接取 `front` 指向的节点数据 - 然后让 `front = front->next`,释放原节点 ✅ 时间:$ O(1) $ —— 一步搞定! ### ❓ 如何入队? - 新元素要加在**最后面** - 但你只有 `front`,不知道哪里是结尾 - 所以必须从头开始走链表,一直走到最后一个节点(直到 `next == nullptr`) - 然后把它连上新节点 ⛔️ 问题:这个“走到底”的过程需要遍历整个链表! 👉 如果有 $ n $ 个元素,就要走 $ n $ 步 → 时间复杂度 $ O(n) $ --- ### ✔️ 结论一: > 只有头指针 → 出队快 $O(1)$,入队慢 $O(n)$ --- ## ✅ 情况二:只设尾指针 `rear`(指向队尾) ``` rear ↓ [A] → [B] → [C] ↑ ↑ 队头 队尾 ``` 注意:现在你**只知道队尾在哪**,不知道队头是谁(虽然其实可以从 `rear` 往前推?不行!单向链表不能回头) 但等等——队列还是要能出队啊!怎么办? 假设你想出队(删掉最前面的 A): ### ❓ 如何出队? - 你要删除第一个节点 `[A]` - 但你没有 `front` 指针! - 唯一的办法是从头找起? - 可是你连“头”在哪都不知道! ⚠️ 严重问题:**如果只有尾指针,你根本找不到队头!** 除非……你把链表做成**循环链表**或**双向链表**,但这超纲了。 所以通常设定是: > 使用**尾指针 + 循环单链表**,让 `rear->next` 指向队头! 📌 正确结构如下(重点!): ``` ┌---------------------┐ ↓ | [C] ← [A] → [B] | ↑ ↖ ↓ rear └-- [A] 是队头! ``` 即:`rear->next` 就是队头节点。 这样: - `rear` 自己是队尾 - `rear->next` 是队头 --- ### ❓ 如何入队?(加一个 [D]) 1. 创建新节点 [D] 2. 让 [D] 指向 `rear->next`(也就是队头) 3. 让 `rear->next = D` 4. 更新 `rear = D` ✅ 四步都是常数操作 → $ O(1) $ ### ❓ 如何出队?(删掉 [A]) 1. 找到队头:`front = rear->next` 2. 如果只有一个元素(`front == rear`),删除后置空 3. 否则: - 让 `rear->next = front->next`(跳过第一个) - 删除 `front` ✅ 看起来也是 $ O(1) $? 等等……那为什么说“尾指针出队是 $ O(n) $”? ❌ 错误来源! --- # ⚠️ 关键纠正:常见说法有误导! 你说的知识点: > “若只设尾指针,出队为 $ O(n) $” 这其实是**错误的前提假设**! ✅ 实际上: - 如果使用**带尾指针的循环单链表**,且 `rear->next` 指向队头, - 那么:**出队也可以是 $ O(1) $**! 所以更合理的解释是: | 指针设置 | 入队 | 出队 | |---------|------|------| | 只有头指针 | $ O(n) $(要找尾) | $ O(1) $(直接删头) | | 只有尾指针(非循环) | ❌ 无法高效操作 | | 尾指针 + 循环链表 | $ O(1) $ | $ O(1) $ | --- # 📝 那你说的口诀是怎么回事? 那个口诀其实是一个**教学简化模型**,用来对比两种极端情况: - 设想一种“笨方法”: - 只保存 `rear` 指针,不保存 `front` - 每次要出队时,就得从 `rear` 开始顺着链表走一圈,找到倒数第二个节点,才能把最后一个删掉? - 不对,这不是出队逻辑…… 😱 实际上,这种说法**逻辑混乱**。 --- # ✅ 正确认知(考试 & 实际) 在标准链队列设计中,**我们会同时保存两个指针**: ```cpp struct LinkQueue { Node* front; // 头指针 Node* rear; // 尾指针 }; ``` 这样: - 出队:通过 `front` 操作 → $ O(1) $ - 入队:通过 `rear` 操作 → $ O(1) $ 🎯 **真正的高效链队列 = 既有 front 又有 rear** --- # 所以你的知识点怎么理解? 原来的知识点其实是想表达: | 指针配置 | 入队 | 出队 | |--------|------|------| | 只靠头指针找尾 → 入队慢 | $ O(n) $ | $ O(1) $ | | 只靠尾指针找头 → 出队慢 | $ O(1) $ | $ O(n) $ | 但“只靠尾指针找头”这件事本身就不现实。 --- # 🧠 正确记忆方式(别死背) 👉 记住一句话: > **谁方便谁快,谁不方便谁慢。** - 你能直接访问队尾 → 入队快 $O(1)$ - 不能直接访问队尾 → 入队慢 $O(n)$ - 你能直接访问队头 → 出队快 $O(1)$ - 不能直接访问队头 → 出队慢 $O(n)$ 所以: - 有 `front` → 出队快 - 有 `rear` → 入队快 🔚 结论:**最好两个都有!** --- # 知识点(列出解答该问题需要的知识点) - **$队列操作位置$**:入队在队尾,出队在队头,需快速访问两端。 - **$单链表遍历代价$**:无指针时需遍历找节点,耗时 $O(n)$。 - **$指针决定效率$**:有指针的一端操作为 $O(1)$,否则为 $O(n)$。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值