面试题整理5 顺时针打印矩阵

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

          例如输入以下矩阵:

           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);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值