题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
例如输入以下矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字 1、2、3、4、8、12、16、15、14、13、9、5、6、7、11、10
分析:画图分析,可以考虑递归,每次打印外面一圈,剩下的继续。同时注意剩下的为一行或者一列时的情况。
(1)自己写的代码,最好想的思路
void PrintMatrixClockwisely2(int** numbers, int columns, int rows)
{
if(numbers == NULL || columns <= 0 || rows <= 0)
return;
for( int i=0; i<columns; ++i )
{
printf( "%d\t",*(*numbers+i) );
}
for( int i=1; i<rows; ++i)
{
printf( "%d\t",*(*(numbers+i)+columns-1) );
}
if( rows>=2 && columns>=2 )
{
for( int i=columns-2; i>=0; --i)
{
printf( "%d\t",*(*(numbers+rows-1)+i) );
}
for( int i=rows-2; i>=1; --i)
{
printf( "%d\t",**(numbers+i) );
}
int newRows = rows-2;
int newColumns = columns-2;
if( newRows == 0 || newColumns==0 )
{
return;
}
int ** newNumber = new int*[newRows];
for( int i=0; i<newRows; ++i)
{
newNumber[i] = new int[newColumns];
}
for( int i=0; i<newRows; ++i)
{
for( int j=0; j<newColumns; ++j)
{
*(*(newNumber+i)+j) = *(*(numbers+i+1)+j+1);
}
}
PrintMatrixClockwisely2(newNumber,newColumns,newRows);
for( int i=0; i<newRows; ++i)
{
delete[] newNumber[i];
}
delete[] newNumber;
}
}
(2)附上《剑指offer》中的方法:
分析:打印第一圈的左上角坐标为(0,0),第二圈的坐标为(1,1),依次类推。左上角的坐标中行标和列标总是相同的,于是可以在矩阵中选取左上角为(start,start)的一圈作为我们分析的目标。每次去掉外面的行和列,每次行和列减少2,因此推断出让循环继续的条件是columns>startX*2并且rows>startY*2。同时注意打印一圈时出现仅剩一行或者一列时打印的处理,以及避免重复打印的问题。
这样避免了(1)中数组的新建和删除,节省了空间,也避免数组new和delete容易出错的问题。
同时访问数组数据时采用下标访问,而不是指针访问的方式。
在《C和指针》一书中指出,当数组作为参数时,可以采用数组形式也可以采用指针形式,采用数组形式必须制定列大小,因此在本题中参数采用了指针的形式,同时传递行和列的大小(在《剑指offer》一书中大部分数组形式参数还是以指针形式传递的)。同时指出,以数组形式访问数组数据不比以指针访问形式更高效,但是对于多维数组这样的形式更加清晰,程序更加易读,所以最好采用下标形式。
void PrintMatrixClockwisely(int** numbers, int columns, int rows)
{
if(numbers == NULL || columns <= 0 || rows <= 0)
return;
int start = 0;
while(columns > start * 2 && rows > start * 2)
{
PrintMatrixInCircle(numbers, columns, rows, start);
++start;
}
}
void PrintMatrixInCircle(int** numbers, int columns, int rows, int start)
{
int endX = columns - 1 - start;
int endY = rows - 1 - start;
// 从左到右打印一行
for(int i = start; i <= endX; ++i)
{
int number = numbers[start][i];
printNumber(number);
}
// 从上到下打印一列
if(start < endY)
{
for(int i = start + 1; i <= endY; ++i)
{
int number = numbers[i][endX];
printNumber(number);
}
}
// 从右到左打印一行
if(start < endX && start < endY)
{
for(int i = endX - 1; i >= start; --i)
{
int number = numbers[endY][i];
printNumber(number);
}
}
// 从下到上打印一行
if(start < endX && start < endY - 1)
{
for(int i = endY - 1; i >= start + 1; --i)
{
int number = numbers[i][start];
printNumber(number);
}
}
}
void printNumber(int number)
{
printf("%d\t", number);
}