软件设计艺术大师基本功--顺时针打印二维数组

Author: Frank

描述:编写一个函数,输入一个矩阵,按照从外向里以顺时针的顺序一次打印出每一个数字。

用状态转换的方法应该也可以,定义参数标致当前的前进方向,右,下,左,上, 定义二维数组标记被访问过的元素, 当向右到尽头时,转向下..)

例如输入的矩阵为:

 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.

分析:(key:二维数组做入参,按照圈数打印)

将矩阵中的数字按照圈输出,1 2 3 4 8 12 16 15 14 13 9 5为第一圈;6 7 11 10为第二圈。

首先,需要确定圈数,设矩阵的行数为row, 列数为column,则圈数取决于两者中的小者。令min = (row >= column) ? column : row; 如果min为偶数,则圈数为min/2;如果min为奇数,则圈数为(min-1)/2, 另外还剩余一行或一列元素需要单独输出。当min==row时,各个圈都输出后,最后需要单独输出剩余的那一行的数据;当min==column时,各个圈都输出后,最后需要单独输出剩余的那一列的数据;

其次,需要设计如何输出一圈的数据。

如上图所示,将一圈的数据分成四个部分,每个部分用一个for循环即可输出,每个部分的起止下标与当前是第几圈有关。假设数组A的行数为row,列数为column:

第0圈: 第一部分 A[0][0~column-2];第二部分 A[0~row-2][column-1];第三部分A[row-1][column-1~1];第四部分A[row-1~1][0]

第1圈: 第一部分 A[1][1~column-3];第二部分 A[1~row-3][column-2];第三部分A[row-2][column-2~2];第四部分A[row-2~2][1]

........

第i圈: 第一部分 A[i][i~column-2-i];第二部分 A[i~row-2-i][column-1-i];第三部分A[row-1-i][column-1-i~i+1];第四部分A[row-1-i~i][i]

代码:

void printUpRow(int* A, int row, int column, int ciecleIdx)
{
	for (int i = ciecleIdx; i<= column-2-ciecleIdx;i++)
		printf("%d	", *((int*)A + column * ciecleIdx + i));//A[ciecleIdx][i]
}
void printRightColumn(int* A, int row, int column, int ciecleIdx)
{
	for (int i = ciecleIdx; i <= row - 2 - ciecleIdx; i++)
		printf("%d	", *((int*)A + column * i + (column - 1 - ciecleIdx)));//A[i][column-1-ciecleIdx]
}
void printBottomRow(int* A, int row, int column, int ciecleIdx)
{
	for (int i = column-1-ciecleIdx; i >= ciecleIdx+1; i--)
		printf("%d	", *((int*)A + column * (row - 1 - ciecleIdx) + i));//A[row - 1 - ciecleIdx][i]
}
void printLeftColumn(int* A, int row, int column, int ciecleIdx)
{
	for (int i = row - 1 - ciecleIdx; i >= ciecleIdx + 1; i--)
		printf("%d	", *((int*)A + column *i + ciecleIdx));//A[i][ciecleIdx]
}

void PrintMatrixClockwise(int* A, int row, int column)
{
	if (row < 1 || column < 1)
		return;
	int circleNum = 0;
	bool extra = false;
	int min = (row >= column) ? column : row;
	if (0 == min % 2)
	{
		circleNum = min / 2;
	}
	else
	{
		circleNum = (min-1) / 2;
		extra = true;//最后需要单独输出剩余的行或列
	}
	for (int circleIdx = 0; circleIdx < circleNum; circleIdx++)
	{
		//print one row
		printUpRow(A, row, column, circleIdx);
		//print one column
		printRightColumn(A, row, column, circleIdx);
		//print one row
		printBottomRow(A, row, column, circleIdx);
		//print one column
		printLeftColumn(A, row, column, circleIdx);
	}
	if ((extra == true))//最后需要单独输出剩余的行或列
	{
		//print the left row or column
		if (row >= column)
		{
			int leftColumIdx = (column - 1) / 2;
			for (int i = circleNum; i <= row - 1 - circleNum; i++)
				printf("%d	", *((int*)A + column *i + leftColumIdx));//A[i][leftColumIdx]
		}
		else
		{
			int leftRowIdx = (row - 1) / 2;
			for (int i = circleNum; i <= column - 1 - circleNum; i++)
				printf("%d	", *((int*)A + column *leftRowIdx + i));//A[leftRowIdx][i]
		}
	}
	printf("\n------------------------------------------\n");
}

测试代码:

int main()
{
	int A[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}};
	PrintMatrixClockwise((int*)A, 3, 5);
	int A1[1][5] = { { 1,2,3,4,5 } };
	PrintMatrixClockwise((int*)A1, 1, 5);
	int A2[5][1] = { 1,2,3,4,5 };
	PrintMatrixClockwise((int*)A1, 5, 1);
	int A3[5][3] = { {1,2,3},{4,5,6},{7,8,9},{10,11,12},{13,14,15} };
	PrintMatrixClockwise((int*)A3, 5, 3);
	int A4[5][5] = { { 1,2,3,4,5 },{ 6,7,8,9,10 },{11,12,13,14,15 },{16,17,18,19,20},{ 21,22,23,24,25 } };
	PrintMatrixClockwise((int*)A4, 5, 5);
	int A5[1][1] = { 1 };
	PrintMatrixClockwise((int*)A1, 1, 1);
	getchar();
    return 0;
}

 


 


用状态转换的方法应该也可以,定义参数标致当前的前进方向,右,下,左,上, 定义二维数组标记被访问过的元素, 当向右到尽头时,转向下..

 

enum class DIR {
	Right = 0,
	Down,
	Left,
	Up
};
bool getNextLocation( vector<vector<char>>& markArr, int rowNum, int colNum, 
	DIR& currDir,
	int lastRowIdx, int lastColuIdx,
	int& nextRowIdx, int& nextColuIdx) {
	if (currDir == DIR::Right) {
		if (lastColuIdx + 1 < colNum && markArr[lastRowIdx][lastColuIdx + 1] == 0) {
			nextRowIdx = lastRowIdx;
			nextColuIdx = nextColuIdx + 1;
			markArr[nextRowIdx][nextColuIdx] = 1;
			return true;
		}
		else  {
			if (markArr[lastRowIdx + 1][lastColuIdx] == 0 && lastRowIdx + 1< rowNum) {
				nextRowIdx = lastRowIdx+1;
				nextColuIdx = lastColuIdx;
				markArr[nextRowIdx][nextColuIdx] = 1;
				currDir = DIR::Down;
				return true;
			}
		}
	}
	else if (currDir == DIR::Down) {
		if (lastRowIdx + 1 < rowNum && markArr[lastRowIdx+1][lastColuIdx] == 0) {
			nextRowIdx = lastRowIdx+1;
			nextColuIdx = nextColuIdx;
			markArr[nextRowIdx][nextColuIdx] = 1;
			return true;
		}
		else {
			if (markArr[lastRowIdx][lastColuIdx-1] == 0 && lastColuIdx -1>= 0) {
				nextRowIdx = lastRowIdx;
				nextColuIdx = lastColuIdx-1;
				markArr[nextRowIdx][nextColuIdx] = 1;
				currDir = DIR::Left;
				return true;
			}
		}
	}
	else if (currDir == DIR::Left) {
		if (lastColuIdx -1 >= 0 && markArr[lastRowIdx][lastColuIdx - 1] == 0) {
			nextRowIdx = lastRowIdx;
			nextColuIdx = lastColuIdx - 1;
			markArr[nextRowIdx][nextColuIdx] = 1;
			return true;
		}
		else {
			if (markArr[lastRowIdx - 1][lastColuIdx] == 0 && lastRowIdx - 1 >= 0) {
				nextRowIdx = lastRowIdx- 1;
				nextColuIdx = lastColuIdx;
				markArr[nextRowIdx][nextColuIdx] = 1;
				currDir = DIR::Up;
				return true;
			}
		}
	}
	else if(currDir == DIR::Up) {
		if (lastRowIdx - 1 >=0 && markArr[lastRowIdx - 1][lastColuIdx] == 0) {
			nextRowIdx = lastRowIdx - 1;
			nextColuIdx = nextColuIdx;
			markArr[nextRowIdx][nextColuIdx] = 1;
			return true;
		}
		else {
			if (markArr[lastRowIdx][lastColuIdx + 1] == 0 && lastColuIdx + 1 < colNum) {
				nextRowIdx = lastRowIdx;
				nextColuIdx = lastColuIdx + 1;
				markArr[nextRowIdx][nextColuIdx] = 1;
				currDir = DIR::Right;
				return true;
			}
		}
	}
	return false;
}
void printArry(vector<vector<int>> arr, int rowNum, int colNum) {
	if (arr.size() < 0) {
		return;
	}

	vector<vector<char>> markArr(rowNum, vector<char>(colNum,0));//标记元素是否已经被访问过
	int lastRowIdx = 0;
	int lastColIdx = 0;
	cout << arr[0][0];//输出第一个元素
	markArr[0][0] = 1;
	int nextRowIdx = 0;
	int nextColuIdx = 0;
	DIR currDir = DIR::Right;
	while (getNextLocation(markArr, rowNum, colNum, currDir, lastRowIdx, lastColIdx, nextRowIdx, nextColuIdx)) {
		cout << arr[nextRowIdx][nextColuIdx];
		lastRowIdx = nextRowIdx;
		lastColIdx = nextColuIdx;
	}
}


int main() {
	vector<vector<int>> arr(3, vector<int>(3, 0));
	arr[0][0] = 1; arr[0][1] = 2; arr[0][2] = 3;
	arr[1][0] = 4; arr[1][1] = 5; arr[1][2] = 6;
	arr[2][0] = 7; arr[2][1] = 8; arr[2][2] = 9;
	
	printArry(arr,3,3);
	return 1;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

First Snowflakes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值