※ 引述《liptonbin (我还存在耶)》之铭言:
: 请教一下
: 我有个
: 输入: 一维arr[240]={0,1,2,3,4,5,.....239}
: (为了方便记忆,写有顺序排列,之后阵列值会变动!)
: 想转成底下5x48阵列,排列如下
: 0, 1, 2, 3,.........47
: 48, 49, 50, 51,........95
: 96, 97, 98, 99,.......143
: 144,145,146,147,......191
: 192,193,194,195,..238,239
: 想做底下阵列运算
: 直列来看,二个一组相减,有点复杂,请问该怎么写c code><
: 示意图如下:
: https://ibb.co/mzM6Mqt
: 想要输出:
: 48-0, 1-1, 50-2, 3-3,............47-47
: 48-48, 97-49, 50-50, 99-51,...........143-95
: 144-96, 97-97, 146-98, 99-99,..........143-143
: 144-144,193-145,146-146, 195-147,..........239-191
: 1-192,193-193, 3-194, 195-195,...47-238,239-239
: 想法是:
: 要把一维阵列转成5x48阵列,在做反转阵列,变成48x5,在转成一维阵列
: 目的是2个为一组,再作减法,比较有序,
: 最后再把一维阵列转回上面的图><
基本上你只要尽可能地把问题描述清楚, 有趣的是: 当你把问题描述完整的同
时, 自然就解掉它了. 让我们来一步步分析它. 假设你现在是一个老板, 需要
雇用一个工读生帮你把图里红线经过的位置依序唸出来 (0, 48, 96, ...),
好让你可以两两去作相减, 你在征才文里会写上哪些需求呢? 我想到的内容会
像下面这样:
1. 给 [工读生] 一组行 (column) 列 (row) 值, 他要有办法将阵列当作
虚拟的矩阵看待.
2. [工读生] 要有办法像图里红线所标示的一样, 依序给出序列 (0, 48,
96, 144, ...) 里的值, 直到行 (column) x 列 (row) - 1 为止.
3. [工读生] 要能知道什么时候该结束, 并且通知你.
有了上面的描述, 我们就可以建立抽象资料型别 (Abstract Data Type) 出来
, 三个项目对应到三个接口. 这个流程在资料结构的书里都会教, 细节不再赘
述. 我们把这里的 [工读生] 改叫作 Iterator:
Abstract Data Type: Iterator
─────────────────────────────
Iterator create(row: size_t, column: size_t) (constructor)
size_t next(it: Iterator)
bool hasNext(it: Iterator)
注意在这个阶段型别并不是最重要的, 重要的是厘清每个接口应该做什么事情.
然后身为雇主的你请了这个 [工读生] 来, 剩下要做的就是每次和他拿两个位
置过来, 得到阵列里对应的值再做相减. 程式码会像这样 (接口实作就当练习
):
struct Iterator it = create(5, 48);
while (hasNext(it)) {
const size_t upper = next(&it);
const size_t lower = next(&it);
printf("%d-%d", arr[lower], arr[upper]);
// other code goes here
}
范例: https://godbolt.org/z/zEsdad
也许眼尖的人已经看出来这是《Design Patterns》里的 Iterator Pattern,
因为原问题的本质是寻访问题, 所以前面提到的抽象资料型别正是根据目前
的问题 (Problem) 以及情境 (Context) (原 PO 对 C 语言的理解) 所揉合
出来的解决方案 (Solution) (= Pattern).
也因为是寻访问题, 如果今天把红线从倒 N 字型改为 Z 字型, 在修改/维护
上将得利于使用了合适的设计样式 (design pattern).