MOOC清华《面向对象程序设计》第5章:OOP版填充数字旋转矩阵

//main.cpp
#include <iostream>
#include "Matrix.h"
using namespace std;

int main() {
	cout << "Please input N: ";
	int size;
	cin >> size;
	
	Matrix obj(size);
	obj.fill();
	cout << obj;
	
	return 0;
}


//Matrix.h
#ifndef Matrix_h
#define Matrix_h

#include <iostream>
using namespace std;

class Matrix{
	int _size;//方阵的规模 
	int *_data;//数据空间
	int row, col;
	char dir;
	int findPosition();//辅助函数 
	
public:
	Matrix(int size);
	~Matrix();
	void fill();
	friend ostream& operator<< (ostream& out, const Matrix& m); 
};

#endif


//Matrix.cpp
#include <iostream>
#include <cstring>
#include "Matrix.h"
using namespace std;

Matrix::Matrix(int size): _size(size), row(-1), col(0), dir('D') {
	_data = new int[size * size];
	memset(_data, 0, sizeof(int) * _size * _size);
}

Matrix::~Matrix(){
	delete _data;
}

ostream& operator<< (ostream& out, const Matrix& m){
	for(int r = 0; r < m._size; r++){ //row
		for(int c = 0; c < m._size; c++) //col
			cout << *(m._data + r * m._size + c) << '\t';
		cout << endl;
	}
}

void Matrix::fill(){
	for(int num = 1; num <= _size * _size; num++){
		int pos = findPosition();
		_data[pos] = num;
	}
}

int Matrix::findPosition(){
	switch(dir){
		case 'D':
			if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)
				row++;
			else{
				dir = 'R'; // next direction
				col++;
			}
			break;
		case 'R':
			if(col < _size - 1 && _data[row * _size + col + 1] == 0)
				col++;
			else{
				dir = 'U'; // next direction
				row--;
			}
			break;
		case 'U':
			if(row > 0 && _data[(row - 1) * _size + col] == 0)
				row--;
			else{
				dir = 'L'; // next direction
				col--;
			}
			break;
		case 'L':
			if(col > 0 && _data[row * _size + col - 1] == 0)
				col--;
			else{
				dir = 'D'; // next direction
				row++;
			}
			break;
	}
	return row * _size + col;
}

测试结果:



若改变构造函数的初始化列表,则可以改变旋转矩阵的“起填位置”(即第一个数填入的位置):

Matrix::Matrix(int size): _size(size), row(size-1), col(-1), dir('R') {
//改变构造函数的初始化列表可以改变第一个数字的位置,注意不要把size-1写成了size 
	_data = new int[size * size];
	memset(_data, 0, sizeof(int) * _size * _size);
}


==================================分割线================================

黄震春老师说:产品经理又来啦,改需求啦!要既能够行优先填充,又能列优先填充(这两条前面已实现);既能逆时针填充(前面已实现),又能顺时针填充,该怎么办?其实除了修改findPosition()这个成员函数以外,还要修改构造函数的初始化列表。分别定义findPosition_clockwise()和findPosition_anticlock()两个私有成员函数,用以实现顺时针填充和逆时针填充的具体细节,以待需要时选用。findPosition_anticlock()其实就是前面的findPosition(),那么只需要定义findPosition_clockwise()就行了。代码如下:

//main.cpp
//同前面一样,略。

//Matrix.h
#ifndef Matrix_h
#define Matrix_h

#include <iostream>
using namespace std;

class Matrix{
	int _size;//方阵的规模 
	int *_data;//数据空间
	int row, col;
	char dir;
	int findPosition_clockwise();//顺时针辅助函数
	int findPosition_anticlock();//逆时针辅助函数 
	
public:
	Matrix(int size);
	~Matrix();
	void fill();
	friend ostream& operator<< (ostream& out, const Matrix& m); 
};

#endif

//Matrix.cpp
#include <iostream>
#include <cstring>
#include "Matrix.h"
using namespace std;

Matrix::Matrix(int size): _size(size), row(0), col(-1), dir('R') {
//改变构造函数的初始化列表可以改变第一个数字的位置,注意不要把size-1写成了size 
	_data = new int[size * size];
	memset(_data, 0, sizeof(int) * _size * _size);
}

Matrix::~Matrix(){
	delete _data;
}

ostream& operator<< (ostream& out, const Matrix& m){
	for(int r = 0; r < m._size; r++){ //row
		for(int c = 0; c < m._size; c++) //col
			cout << *(m._data + r * m._size + c) << '\t';
		cout << endl;
	}
}

void Matrix::fill(){
	for(int num = 1; num <= _size * _size; num++){
		int pos = findPosition_clockwise();
		_data[pos] = num;
	}
}

int Matrix::findPosition_clockwise(){ //clockwise为顺时针的意思 
	switch(dir){
		case 'D':
			if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)
				row++;
			else{
				dir = 'L'; // next direction
				col--;
			}
			break;
		case 'L':
			if(col > 0 && _data[row * _size + col - 1] == 0)
				col--;
			else{
				dir = 'U'; // next direction
				row--;
			}
			break;
		case 'U':
			if(row > 0 && _data[(row - 1) * _size + col] == 0)
				row--;
			else{
				dir = 'R'; // next direction
				col++;
			}
			break;
		case 'R':
			if(col < _size - 1 && _data[row * _size + col + 1] == 0)
				col++;
			else{
				dir = 'D'; // next direction
				row++;
			}
			break;
	}
	return row * _size + col;
}

int Matrix::findPosition_anticlock(){ //anticlock为逆时针的意思 
	switch(dir){
		case 'D':
			if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)
				row++;
			else{
				dir = 'R'; // next direction
				col++;
			}
			break;
		case 'R':
			if(col < _size - 1 && _data[row * _size + col + 1] == 0)
				col++;
			else{
				dir = 'U'; // next direction
				row--;
			}
			break;
		case 'U':
			if(row > 0 && _data[(row - 1) * _size + col] == 0)
				row--;
			else{
				dir = 'L'; // next direction
				col--;
			}
			break;
		case 'L':
			if(col > 0 && _data[row * _size + col - 1] == 0)
				col--;
			else{
				dir = 'D'; // next direction
				row++;
			}
			break;
	}
	return row * _size + col;
}


调试技术要点:一定要仔细推敲构造函数初始化列表中的row、col、dir三个参数,三个参数必须一起调整,错一个都会导致输出矩阵错误。——其实,可以受启发想到:可以把顺时针、逆时针2种情况,“乘以”矩阵的4个顶点作为起点的4种情况,共计8种情况的初始化列表专门写成一个函数,这样只需要确定“顺时针”还是“逆时针”,以及从哪个顶点开始填充这两个条件,就能迅速确定输出的矩阵了。如果这个题目真的是一款产品的需求报告,那么用户所希望得到的是越简单越好,谁会费心思地去推敲row、col、dir三个参数呢?我认为,这也是一层“封装”。用户最终拿到的产品是极简型的。完美!(具体代码实现,见下一篇日志!)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值