要求按如图所示的方式遍历整个二维表,写出程序代码。
这是前些天遇到的一道笔试题,当时头有点大,没想出来怎么精确地控制每条扫描线的行列起始点。
首先分析一下题目。给定一个行数为rows列数为cols的二维数组,同一扫描线上元素A[i][j]的特点是i+j等于一个常数C,C取{0, 1, 2,…, rows-1+cols-1}中共rows+cols-1个不同的值。同一扫描线上元素的访问顺序是行数递减,列数递增,步长都为1。
记不同扫描线数目为scan_lines=rows+cols-1,第i条扫描线个上数组的元素个数(或者称为扫描线的长度)为len[i]。于是我们可以写出一个遍历算法的轮廓:
for (i=0; i
/* 求出当前扫描线的长度len */
for (j=0; j
access(Array[start_row-j][start_col+j]);
}
其中origin_row,origin_col分别是第i条扫描线的起始行号和列号。
剩下的问题是怎么简洁地表示len[i],start_row和start_col?
记二数组两个维度的最小值为min_dim=min(rows, cols)。注意到扫描线长度的变化分三个阶段:第一个阶段按步长1递增,第二个阶段被min_dim限制住最大值,第三个阶段按步长1递减。如图2中圆点所示。很明显,这些点都布在三条直线len=i+1,len=min_dim,len=scan_lines-i(分别如图2中虚线所示)所构成的分段函数min(i+1, min_dim, scan_lines-1)上,所以len可以简洁地表示为len=min(min(i+1, min_dim), scan_lines-1)。
关于start_row,可以看作从0开始一行一行往下移,但最大不超过rows-1。同理start_col可以看作从i-(rows-1)开始一列一列往右移,但最小不能小于0。所以有:
start_row = min(i, rows-1);
start_col = max(0, i-rows+1);
最后,完整的遍历代码为:
for (i=0; i
len = min(min(i+1, min_dim), scan_lines-i);
start_row = min(i, rows-1);
start_col = max(0, i-rows+1);
for (j=0; j
access(Array[start_row-j][start_col+j]);
}