C++数组实现最大堆:原理、代码与性能优化全解析
1. 项目概述为什么用数组实现最大堆在C的世界里数据结构的选择往往直接决定了程序的效率和优雅程度。今天我们不聊那些复杂的容器库就聚焦一个看似基础但极其核心的结构最大堆。你可能在刷算法题时无数次遇到过“Top K”、“中位数”、“优先队列”这些词它们的背后堆结构往往是那个默默无闻的功臣。而用数组来实现最大堆可以说是最经典、最直观也最考验你对数据结构和内存布局理解的方式。简单来说最大堆是一种特殊的完全二叉树它满足一个核心性质任何一个父节点的值都大于或等于其子节点的值。这意味着堆顶根节点的元素永远是整个集合中的最大值。为什么用数组因为完全二叉树的特性除了最后一层其他层都是满的且最后一层节点靠左排列使得我们可以用一个一维数组完美地模拟它省去了动态指针链接的开销访问和计算都极其高效。对于需要频繁插入、删除最大值比如任务调度、实时排行榜的场景数组实现的堆在时间和空间上都有着显著优势。无论你是正在准备面试还是想在项目中优化性能亲手实现一遍这个结构都能让你对优先级管理有更深的理解。2. 核心原理与数组映射关系2.1 堆的性质与数组的巧妙对应最大堆的逻辑结构是一棵树但它的物理存储却是一个线性数组。这种映射关系是理解整个实现的关键。对于一个存储在数组heap中的最大堆我们约定索引从1开始稍后会解释为什么不是0那么对于数组中任意位置i的节点它的左子节点索引为left 2 * i它的右子节点索引为right 2 * i 1它的父节点索引为parent i / 2整数除法这个简单的算术关系是堆所有操作的基础。它之所以成立完全依赖于完全二叉树的定义。从根节点heap[1]开始按层序遍历的顺序依次放入数组自然就满足了上述索引关系。注意为什么索引从1开始这是一个经典的工程取舍。从1开始上述父子节点索引的计算公式非常直观和整洁。如果从0开始公式会变为左子节点2*i1右子节点2*i2父节点(i-1)/2。虽然也能实现但公式稍显复杂容易在编码时出错。许多经典的算法教材和实现如《算法导论》都采用从1开始的方式以保持逻辑的清晰。在我们的实现中我们会将heap[0]闲置或用作哨兵有效数据从heap[1]开始。2.2 维护堆性质的核心操作上浮与下沉堆的所有操作无论是插入新元素还是移除最大值其核心都在于破坏堆性质后如何通过局部调整快速恢复它。这依赖于两个基石操作上浮Shift Up和下沉Shift Down。上浮Shift Up当一个节点的值变得大于其父节点时为了维护最大堆性质需要将它向上移动。这个过程是沿着节点到根节点的路径进行的。具体操作是比较当前节点与其父节点的值如果当前节点更大则交换它们的位置然后继续以新的位置原父节点位置与它的父节点比较直到当前节点不大于其父节点或者到达了根节点。这个过程就像气泡从水底上浮一样。下沉Shift Down当一个节点的值变得小于其某个子节点时通常发生在移除堆顶后将最后一个元素放到堆顶需要将它向下移动。这个过程是选择当前节点、左子节点、右子节点三者中的最大值。如果最大值是某个子节点则交换当前节点与该子节点并在交换后的新位置上继续与它的子节点比较直到当前节点不小于它的任何子节点或者到达了叶子节点。这个过程就像石头沉入水底。这两个操作的时间复杂度都是O(log n)其中 n 是堆中元素的数量因为它们操作路径的长度最多是树的高度。3. 类设计与成员规划在动手写代码之前好的设计能事半功倍。我们将设计一个MaxHeap类它应该具备清晰的内外接口和健壮的内部状态管理。3.1 成员变量与容量管理首先我们需要决定内部如何存储数据。一个动态数组如std::vector是理想的选择因为它能自动管理内存但我们为了彻底理解底层这里选择使用原生指针和手动管理内存的数组这能让我们更清楚地看到扩容等细节。class MaxHeap { private: int* heap; // 指向堆数组的指针 int capacity; // 数组的总容量 int size; // 当前堆中元素的数量也是下一个可插入位置的索引 // 核心辅助函数 void shiftUp(int index); void shiftDown(int index); void resize(int newCapacity); public: // 构造函数与析构函数 MaxHeap(int initCapacity 10); ~MaxHeap(); // 核心操作接口 void push(int value); // 插入元素 int pop(); // 移除并返回最大值 int top() const; // 获取最大值不删除 bool isEmpty() const; // 判断堆是否为空 int getSize() const; // 获取当前元素数量 };关键设计点解析size的含义size既表示当前堆中的元素个数也指向数组中最后一个元素的下一个位置即新元素插入的位置。这符合C标准库容器的惯例非常方便。容量与扩容初始容量initCapacity避免了一开始就进行多次微小分配。当size capacity时意味着数组已满需要resize扩容。常见的策略是扩容为原来的1.5倍或2倍这里我们采用2倍扩容平衡内存使用和复制开销。索引从1开始heap[0]位置我们将空置。在有些优化中heap[0]可以作为一个极大值的哨兵INT_MAX在某些版本的shiftDown中可以简化边界判断但为了概念清晰我们先保持空置。3.2 构造函数、析构函数与内存管理内存管理是C的基石必须小心处理。MaxHeap::MaxHeap(int initCapacity) : capacity(initCapacity), size(0) { // 分配 capacity 1 的空间因为我们的有效索引从1开始 heap new int[capacity 1]; // heap[0] 我们选择不用保持未初始化或置0均可 } MaxHeap::~MaxHeap() { delete[] heap; // 释放数组内存 }实操心得内存分配加一这里一个非常容易出错的细节是new int[capacity 1]。因为我们的有效数据从索引1开始存到索引size所以实际需要的数组长度是capacity 1。如果分配了capacity的长度那么当插入第capacity个元素时实际上需要访问heap[capacity]这就会发生数组越界。务必在脑子里把索引和物理位置的关系理清。4. 核心操作实现详解4.1 上浮操作实现上浮操作在插入新元素后调用参数是新插入元素的索引初始时为size因为插入后size先增加了。void MaxHeap::shiftUp(int index) { // 当节点不是根节点index 1且其值大于父节点值时需要上浮 while (index 1 heap[index] heap[index / 2]) { std::swap(heap[index], heap[index / 2]); // 交换当前节点与父节点 index index / 2; // 更新索引为父节点位置继续向上比较 } }代码逻辑拆解while循环的两个条件index 1确保不是根节点根节点索引为1没有父节点heap[index] heap[index / 2]判断当前节点是否破坏了堆性质大于父节点。std::swap是C标准库函数高效地交换两个元素的值。循环结束后当前节点就位于满足堆性质的位置了。4.2 下沉操作实现下沉操作比上浮稍复杂因为需要从两个子节点中找出更大的那个。void MaxHeap::shiftDown(int index) { while (2 * index size) { // 确保当前节点至少有左孩子非叶子节点 int leftChild 2 * index; int rightChild leftChild 1; int largerChild leftChild; // 先假设左孩子更大 // 如果右孩子存在且右孩子比左孩子大则更大的孩子是右孩子 if (rightChild size heap[rightChild] heap[leftChild]) { largerChild rightChild; } // 如果当前节点已经大于等于最大的孩子则堆性质已满足停止下沉 if (heap[index] heap[largerChild]) { break; } // 否则交换当前节点与更大的孩子 std::swap(heap[index], heap[largerChild]); index largerChild; // 更新索引到交换后的孩子位置继续向下比较 } }关键点与易错点循环条件2 * index size这个条件判断的是“是否存在左孩子”。在完全二叉树中只要有左孩子该节点就不是叶子节点。size是最后一个元素的索引所以2*index如果大于size说明索引为index的节点没有左孩子必然是叶子节点。右孩子的存在性检查rightChild size这是非常关键的一步。一个节点可能有左孩子但没有右孩子当最后一个节点的父节点只有一个左孩子时。如果不检查rightChild是否在有效范围内 size直接访问heap[rightChild]就会导致数组越界访问到垃圾内存或引发程序崩溃。先比较孩子再比较父亲逻辑是先在左右孩子中找到较大的那个 (largerChild)然后再用当前节点 (heap[index]) 与这个较大的孩子比较。这样能保证交换后新的父节点原较大的孩子仍然大于另一个孩子局部堆性质得以维持。4.3 插入与删除操作有了shiftUp和shiftDown插入 (push) 和删除最大值 (pop) 的实现就水到渠成了。void MaxHeap::push(int value) { // 检查容量不足则扩容 if (size capacity) { resize(capacity * 2); } // 将新元素放到数组末尾索引为 size1 的位置 heap[size] value; // 对新元素进行上浮操作以恢复堆性质 shiftUp(size); } int MaxHeap::pop() { if (isEmpty()) { // 错误处理可以抛出异常或返回一个特定值。这里简单返回最小值。 // 更健壮的做法是使用 std::optionalint 或抛出 std::runtime_error std::cerr Error: Pop from an empty heap! std::endl; return INT_MIN; // 假设INT_MIN表示错误 } // 堆顶的最大值 int maxValue heap[1]; // 将最后一个元素移动到堆顶 heap[1] heap[size]; size--; // 堆大小减一 // 对新的堆顶元素进行下沉操作以恢复堆性质 shiftDown(1); return maxValue; }扩容函数resize的实现void MaxHeap::resize(int newCapacity) { int* newHeap new int[newCapacity 1]; // 分配新数组同样1 // 将旧数据复制到新数组从索引1到size for (int i 1; i size; i) { newHeap[i] heap[i]; } delete[] heap; // 释放旧数组内存 heap newHeap; // 更新指针 capacity newCapacity; // 更新容量 }注意事项插入与删除的边界push中的size这是一个前自增操作它先增加size的值然后使用这个新值作为索引。这正好符合我们的设计size总是指向下一个空闲位置。pop中的越界检查在pop中如果堆为空直接访问heap[1]或heap[size]是危险的。必须在函数开头进行isEmpty()检查。pop的步骤顺序必须先保存heap[1]的值再用最后一个元素覆盖heap[1]然后size--最后进行shiftDown。如果先size--再覆盖就会丢失最后一个元素的信息。4.4 辅助函数实现其他接口函数的实现相对直接int MaxHeap::top() const { if (isEmpty()) { std::cerr Error: Top from an empty heap! std::endl; return INT_MIN; } return heap[1]; } bool MaxHeap::isEmpty() const { return size 0; } int MaxHeap::getSize() const { return size; }5. 完整代码整合与测试将上述所有部分整合并提供一个简单的测试用例。#include iostream #include algorithm // for std::swap #include climits // for INT_MIN class MaxHeap { private: int* heap; int capacity; int size; void shiftUp(int index) { while (index 1 heap[index] heap[index / 2]) { std::swap(heap[index], heap[index / 2]); index / 2; } } void shiftDown(int index) { while (2 * index size) { int leftChild 2 * index; int rightChild leftChild 1; int largerChild leftChild; if (rightChild size heap[rightChild] heap[leftChild]) { largerChild rightChild; } if (heap[index] heap[largerChild]) { break; } std::swap(heap[index], heap[largerChild]); index largerChild; } } void resize(int newCapacity) { int* newHeap new int[newCapacity 1]; for (int i 1; i size; i) { newHeap[i] heap[i]; } delete[] heap; heap newHeap; capacity newCapacity; } public: MaxHeap(int initCapacity 10) : capacity(initCapacity), size(0) { heap new int[capacity 1]; } ~MaxHeap() { delete[] heap; } void push(int value) { if (size capacity) { resize(capacity * 2); } heap[size] value; shiftUp(size); } int pop() { if (isEmpty()) { std::cerr Error: Pop from an empty heap! std::endl; return INT_MIN; } int maxValue heap[1]; heap[1] heap[size]; size--; shiftDown(1); // 可选当堆大小远小于容量时可以缩容以节省内存 // if (size 0 size capacity / 4) { // resize(capacity / 2); // } return maxValue; } int top() const { if (isEmpty()) { std::cerr Error: Top from an empty heap! std::endl; return INT_MIN; } return heap[1]; } bool isEmpty() const { return size 0; } int getSize() const { return size; } }; // 测试函数 int main() { MaxHeap heap; // 测试插入 heap.push(10); heap.push(30); heap.push(20); heap.push(5); heap.push(35); std::cout Current max (top): heap.top() std::endl; // 应输出 35 std::cout Heap size: heap.getSize() std::endl; // 应输出 5 // 测试删除最大值 std::cout \nPopping elements in order:\n; while (!heap.isEmpty()) { std::cout heap.pop() ; // 应输出 35 30 20 10 5 } std::cout std::endl; // 测试空堆操作 std::cout Trying to pop from empty heap: ; int val heap.pop(); // 应输出错误信息并返回INT_MIN std::cout Returned value: val std::endl; return 0; }6. 性能分析与应用场景6.1 时间复杂度分析构建堆如果给定一个无序数组可以通过从最后一个非叶子节点开始自底向上对每个节点执行shiftDown操作来构建堆这个过程的时间复杂度是O(n)而不是直觉上的 O(n log n)。这是一个非常重要的结论。插入 (push)主要开销是shiftUp最多进行树的高度次操作时间复杂度为O(log n)。删除最大值 (pop)主要开销是shiftDown同样最多进行树的高度次操作时间复杂度为O(log n)。获取最大值 (top)直接访问根节点时间复杂度为O(1)。6.2 典型应用场景优先队列这是堆最直接的应用。操作系统中的进程调度按优先级、网络数据包调度等都需要优先队列。C STL中的std::priority_queue底层默认就是用最大堆实现的。Top K 问题在海量数据中找出最大或最小的K个元素。例如维护一个大小为K的最小堆遍历数据比堆顶大的就替换堆顶并下沉最终堆里就是最大的K个元素。时间复杂度是 O(n log K)比全排序 O(n log n) 高效。堆排序不断从最大堆中弹出最大值依次放入数组末尾就可以实现原地的、时间复杂度为 O(n log n) 的排序算法。虽然在实际应用中不如快速排序或归并排序快但其最坏情况下的 O(n log n) 复杂度是稳定的。求中位数/流数据统计可以维护一个最大堆存放较小的一半数和一个最小堆存放较大的一半数动态维护中位数。6.3 与STL的priority_queue对比C标准库提供了std::priority_queue它是一个容器适配器默认使用std::vector作为底层容器并使用std::less来生成最大堆。我们的手动实现与其核心逻辑一致但有以下区别功能std::priority_queue提供了更完整的接口和异常安全保证。定制性手动实现允许你更精细地控制内存如我们的扩容策略、索引方式我们从1开始以及添加自定义的调试或性能监控代码。学习价值手动实现是理解堆数据结构内部运作机制的最佳途径。7. 常见问题与调试技巧7.1 典型错误与排查数组越界这是最常见的错误。务必检查shiftDown中访问rightChild前是否判断了rightChild sizepop操作在堆为空时是否做了检查扩容时新数组大小是否是newCapacity 1所有循环的边界条件如for (int i 1; i size; i)是否正确堆性质破坏插入或删除后堆不再是最大堆。检查shiftUp和shiftDown的比较逻辑确保是“大于”比较对于最大堆。有时不小心写成或会导致错误。检查索引计算parent i / 2,left 2*i,right 2*i1。确保是整数除法。使用小数据量测试并画图插入3-5个元素在纸上画出树形结构和数组手动模拟每一步操作与程序输出对比。内存泄漏确保在析构函数中delete[] heap并且在resize函数中分配新内存后正确释放旧内存。7.2 调试与验证方法编写验证函数在开发过程中可以添加一个bool isMaxHeap() const的成员函数遍历所有非叶子节点检查是否满足heap[i] heap[2*i]且如果右孩子存在heap[i] heap[2*i1]。在每次push或pop后调用它确保堆性质始终维持。bool MaxHeap::isMaxHeap() const { for (int i 1; i size / 2; i) { // 只需检查非叶子节点 int left 2 * i; int right left 1; if (heap[i] heap[left]) return false; if (right size heap[i] heap[right]) return false; } return true; }打印堆内容实现一个printHeap()函数按数组索引或树形格式打印堆内容便于直观观察。单元测试使用不同的测试用例包括空堆、单个元素、已排序序列、逆序序列、随机序列等全面测试边界情况。7.3 扩展与优化方向支持泛型当前堆只支持int类型。可以使用模板template typename T使其支持任意可比较类型。注意类型T需要支持比较运算符。支持自定义比较器像STL一样传入一个比较函数对象或函数指针就可以实现最小堆或基于自定义对象的堆。优化内存实现缩容策略。当size减少到远小于capacity例如size capacity/4时将数组容量减半避免内存浪费。在pop函数末尾可以添加此逻辑见上面代码注释。迭代器支持为其添加迭代器使其能够与STL算法协同工作。异常安全使用std::bad_alloc处理内存分配失败在pop和top为空时抛出std::out_of_range异常使接口更标准。实现一个完整的最大堆就像搭积木一样把基础的shiftUp和shiftDown这两个核心操作理解透彻、写正确整个结构就稳固了。剩下的插入、删除、扩容都是围绕它们进行的组合。我建议你在理解的基础上尝试自己默写一遍代码然后与参考实现对比找出差异点并思考原因这是掌握数据结构最有效的方法。当你能够不假思索地写出一个健壮的堆时你对递归、循环、数组索引和分治思想的理解会上一个台阶再去应对优先队列相关的算法题就会感觉游刃有余。

相关新闻

005、损失函数VFL+DFL+Bbox Loss协同机制——即插即用改进损失函数组合提升检测精度

005、损失函数VFL+DFL+Bbox Loss协同机制——即插即用改进损失函数组合提升检测精度

005、损失函数VFLDFLBbox Loss协同机制——即插即用改进损失函数组合提升检测精度 从一个让我熬夜三天的bug说起 上个月调一个工业缺陷检测项目,YOLOv11 baseline跑出来mAP0.5:0.95只有38.7,小目标召回率惨不忍睹。我翻来覆去调数据增强、调学习率、换ba…

2026/10/3 4:31:17 阅读更多 →
UDS_0x2E_WriteDataByIdentifier_CAPL

UDS_0x2E_WriteDataByIdentifier_CAPL

title: “UDS诊断服务0x2E:用CAPL给ECU"写入"数据,小白也能学会的WriteDataByIdentifier” tags: UDS, 诊断, 0x2E, CAPL, CANoe, 车载测试 category: 车载网络 一、开篇:从"填表格"说起同学们,想象一个场景&…

2026/10/13 9:10:07 阅读更多 →
ADS设计2.4GHz切比雪夫微带带通滤波器:从理论到EM仿真实战

ADS设计2.4GHz切比雪夫微带带通滤波器:从理论到EM仿真实战

1. 项目概述:从需求到方案 最近在做一个射频前端的项目,里面有个模块对带外抑制的要求特别高,普通的巴特沃斯滤波器插损和带外滚降总是差那么点意思,甲方爸爸的指标又卡得死。折腾了好几轮,最后还是决定上切比雪夫&…

2026/10/12 3:42:34 阅读更多 →

最新新闻

PT对称系统在COMSOL中的仿真与应用研究

PT对称系统在COMSOL中的仿真与应用研究

1. 项目背景与核心价值在光学和电磁学领域,PT对称系统(Parity-Time Symmetric Systems)正成为前沿研究热点。这种特殊结构最早由量子力学领域提出,近年来在经典波系统中实现了突破性应用。我们团队使用Comsol Multiphysics对波导、…

2026/10/14 3:42:39 阅读更多 →
AI 智能搜索:Baklib 让回答先有出处

AI 智能搜索:Baklib 让回答先有出处

客服机器人被问到退货规则,把过期 PDF、聊天记录和一篇旧博客拼成一句听起来完整的话。期限张冠李戴,还编出公司从未提供过的办理方式。听起来合理,并不等于可执行。智能体要稳定工作,先要有可验证的知识,而不是更大的…

2026/10/14 3:42:39 阅读更多 →
DBeaver 高阶实战:可脚本化SQL工作流与CI/CD集成指南

DBeaver 高阶实战:可脚本化SQL工作流与CI/CD集成指南

简介:本资源是一份面向数据库开发人员与DBA的DBeaver高效使用指南,聚焦日常高频操作场景,解决工具上手难、查询效率低、SQL编写重复等问题。内容涵盖表结构查看(通过‘打开声明’获取列注释与CREATE语句)、查询性能调优…

2026/10/14 3:42:39 阅读更多 →
拼接屏3D仿真计算器:从原理到实战

拼接屏3D仿真计算器:从原理到实战

1. 引言拼接屏3D仿真计算器是一款面向大屏拼接项目的辅助工具,用于在部署前模拟拼接屏的物理布局、分辨率分配和3D视觉效果。它帮助工程师在方案设计阶段快速验证拼接墙的尺寸、单元数量、缝隙影响以及观看距离,从而降低现场返工成本。本文将从拼接屏的基…

2026/10/14 3:42:39 阅读更多 →
Unity模拟经营游戏时间系统设计:状态机+Timeline+事件总线

Unity模拟经营游戏时间系统设计:状态机+Timeline+事件总线

简介:本资源是一款基于Unity引擎开发的类《星露谷物语》模拟经营游戏《Starland-Time》完整工程包,面向Unity初学者与独立游戏开发者,提供可学习、可调试、可拓展的模拟经营类项目实践范例。压缩包共572个文件,含343个C源码&#…

2026/10/14 3:42:39 阅读更多 →
带同时取送货的车辆路径问题(VRPSDP)建模与模拟退火求解MATLAB实现

带同时取送货的车辆路径问题(VRPSDP)建模与模拟退火求解MATLAB实现

做物流配送优化的人,十有八九遇到过这种场景:同一个客户点,既要给你送一箱新货,又要让你从他那儿拉走一箱退货或者回收品。如果你把这个问题当成普通的车辆路径问题(VRP)去处理,八成会翻车&…

2026/10/14 3:41:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →