十字链表节点需包含行号、列号、值及right和down两个指针,分别指向同行下一个和同列下一个非零元,以支持高效定位与合并;头指针数组row_head和col_head必须独立初始化为nullptr并同步维护,确保加法时双指针按行列有序遍历、插入时双向链接完整,避免断链或重复释放。

十字链表节点怎么设计才支持加法运算
十字链表的核心是让每个非零元素同时挂到行链和列链上,所以节点必须存行号、列号、值,还得有指向同行下一个、同列下一个的指针。不能只用一个 next 指针——那样只能串一行或一列,加法时没法快速定位“同一位置有没有另一个数”。标准结构体长这样:
struct OLNode {
int row, col;
double value;
OLNode *right; // 同一行下一个非零元
OLNode *down; // 同一列下一个非零元
};
struct CrossList {
OLNode **row_head; // 行头指针数组,row_head[i] 指向第 i 行第一个非零元
OLNode **col_head; // 列头指针数组,col_head[j] 指向第 j 列第一个非零元
int rows, cols, nums;
};
注意:row_head 和 col_head 是两个独立数组,不是共用一套头结点——否则加法过程中插入新节点时容易破坏原有结构。
矩阵加法时怎么避免重复遍历和内存泄漏
加法本质是合并两个稀疏矩阵的非零元:相同位置(row, col)的值相加,结果为 0 就删掉,不为 0 就更新;只在一个矩阵里存在的位置直接复制过去。关键不是“遍历 A 再遍历 B”,而是双指针同步扫行链和列链:
- 对每一行 i,用两个指针分别从
A->row_head[i]和B->row_head[i]出发,按col升序比较 - 遇到相同
col:算和,若为 0 则跳过,否则新建节点或复用原节点(推荐新建,逻辑更干净) - 只在 A 或只在 B 中出现:直接拷贝节点,但要重新连入 C 的行链和列链——别忘了同时更新
C->col_head[col] - 每次插入新节点时,必须同时修改对应行头和列头的链接关系,否则后续按列访问会断链
常见错误:new 节点后只连了 right 没连 down,或者连 down 时没检查 col_head[j] 是否为空,导致空指针解引用。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
初始化和销毁时最容易漏掉什么
十字链表不是普通单链表,头指针数组和节点是分离分配的,销毁必须两步走:
- 先逐行释放所有
OLNode:遍历每行头指针,沿right链释放,但注意不要靠down遍历——那会重复释放同一节点 - 再释放
row_head和col_head数组本身
初始化时也一样:必须显式把 row_head 和 col_head 数组每个元素设为 nullptr,否则未初始化指针可能指向随机地址,加法中一旦尝试 if (col_head[j]->down) 就崩。
另外,输入稀疏矩阵时如果按任意顺序给三元组(行、列、值),必须先排序再建表——否则无法保证每行内 col 递增,后续加法的双指针合并就失效。
为什么不用 std::map<pair>, double></pair> 替代
可以,而且写起来快。但它不满足“十字链表”的结构要求,也没法高效做行列遍历。比如求某行所有非零元之和,map 得遍历全部键;而十字链表只要从 row_head[i] 开始沿 right 走就行,时间复杂度 O(该行非零元个数)。加法本身性能差异不大,但如果你后续还要做转置、乘法或迭代器遍历,十字链表的双向索引能力就不可替代。不过——真只是做一次加法,又不关心内存布局,用 map 或 unordered_map 更省事,也更难写错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










