螺旋矩阵

    这几天在看帖时看到比较多的面试题,其中有一个是螺旋矩阵的编程题,没事就用C++写了一个。所谓螺旋矩阵,就是从矩阵的第一行第一列开始,沿着某个方向用不断增加的数值依次填充矩阵,遇到边界或已填充的值则进行转向,直到将整个矩阵填满。如下是维数为6的螺旋矩阵:

1   2   3   4   5   6
20  21  22  23  24  7
19  32  33  34  25  8
18  31  36  35  26  9
17  30  29  28  27  10
16  15  14  13  12  11
    编写这样的程序时,我觉得最主要的就是一个状态的判断,也就是一个简单的状态机:首先沿着某个方向(如向右),如果下个位置是合法且未被填充,则向着这个方向前进,否则进行转向。由于每个方向都基本上是一样的操作,故抽象出一个方向类Direction作为基类,提供 MoveForward 和 TurnRight 两个虚函数接口。派生出 ToEast 、ToSouth 、ToWest、ToNorth 四个子类,这四个子类实现自己的这两个方法,我只需要一个 Direction 类的指针就可以操作沿这四个方向的增长。这里提供的是顺时针旋转,如果愿意也可以逆时针旋转。

    提供一个ScrewMatrix的类,作为生成螺旋矩阵。由于螺旋矩阵从1开始填充,矩阵为方阵,故设置的退出条件为填充完矩阵维数的平方个数值为止。代码如下(主要实现功能,规范性、安全性等另说):

ScrewMatrix.h:

#ifndef __ScrewMatrix_H_
#define __ScrewMatrix_H_

class ScrewMatrix;

class Direction
{
public:
	virtual void MoveForward(ScrewMatrix* matrix) = 0;
	virtual void TurnRight(ScrewMatrix* matrix) = 0;
};

class ToEast : public Direction
{
public:
	void MoveForward(ScrewMatrix* matrix);
	void TurnRight(ScrewMatrix* matrix);
};

class ToSouth : public Direction
{
public:
	void MoveForward(ScrewMatrix* matrix);
	void TurnRight(ScrewMatrix* matrix);
};

class ToWest : public Direction
{
public:
	void MoveForward(ScrewMatrix* matrix);
	void TurnRight(ScrewMatrix* matrix);
};

class ToNorth : public Direction
{
public:
	void MoveForward(ScrewMatrix* matrix);
	void TurnRight(ScrewMatrix* matrix);
};

class ScrewMatrix
{
public:
	ScrewMatrix(int dir);
	~ScrewMatrix();

public:
	int	GetCurXPos()		{ return m_x; }
	int	GetCurYPos()		{ return m_y; }
	void	SetCurXPos(int x)	{ m_x = x; }
	void	SetCurYPos(int y)	{ m_y = y; }

	void	ChangeDir(Direction* dir);

	bool	IsPosValiable();
	bool	IsFinished();

	void	Generate();
	void	Show();

private:
	int m_Div;
	int m_Num;
	int m_Count;
	int m_x;
	int m_y;
	int* m_Matrix;
	Direction* m_Dir;
};

#endif

ScrewMatrix.cpp:

#include "stdafx.h"
#include "ScrewMatrix.h"
#include <assert.h>
#include <iostream>

using namespace std;

void ToEast::MoveForward(ScrewMatrix *matrix)
{
	matrix->SetCurXPos(matrix->GetCurXPos() + 1);
}

void ToEast::TurnRight(ScrewMatrix* matrix)
{
	matrix->ChangeDir(new ToSouth);
}

void ToSouth::MoveForward(ScrewMatrix *matrix)
{
	matrix->SetCurYPos(matrix->GetCurYPos() + 1);
}

void ToSouth::TurnRight(ScrewMatrix* matrix)
{
	matrix->ChangeDir(new ToWest);
}

void ToWest::MoveForward(ScrewMatrix *matrix)
{
	matrix->SetCurXPos(matrix->GetCurXPos() - 1);
}

void ToWest::TurnRight(ScrewMatrix* matrix)
{
	matrix->ChangeDir(new ToNorth);
}

void ToNorth::MoveForward(ScrewMatrix *matrix)
{
	matrix->SetCurYPos(matrix->GetCurYPos() - 1);
}

void ToNorth::TurnRight(ScrewMatrix* matrix)
{
	matrix->ChangeDir(new ToEast);
}

ScrewMatrix::ScrewMatrix(int dir)
{
	assert(dir >= 1);
	m_Div = dir;
	m_x = 0;
	m_y = 0;
	m_Num = 0;
	m_Count = m_Div * m_Div;
	m_Dir = new ToEast;
	m_Matrix = new int[m_Count];
	assert(m_Dir != NULL);
	assert(m_Matrix != NULL);

	for(int i = 0 ; i < m_Div ; ++i)
		for(int j = 0 ; j < m_Div ; ++j)
			m_Matrix[i * m_Div + j] = 0;
}

ScrewMatrix::~ScrewMatrix()
{
	if(m_Dir)
		delete m_Dir;
	if(m_Matrix)
		delete m_Matrix;
}

void ScrewMatrix::ChangeDir(Direction* dir)
{
	assert(dir != NULL);
	if(m_Dir)
		delete m_Dir;
	m_Dir = dir;
}

bool ScrewMatrix::IsPosValiable()
{
	if(m_x < 0 || m_x >= m_Div || m_y < 0 || m_y >= m_Div)
		return false;
	else
		return true;
}

bool ScrewMatrix::IsFinished()
{
	if(m_Num >= m_Count)
		return true;
	else
		return false;
}

void ScrewMatrix::Generate()
{
	int x,y;
	while(! IsFinished())
	{
		while(IsPosValiable() && m_Matrix[m_y * m_Div + m_x] == 0)
		{
			m_Matrix[m_y * m_Div + m_x] = ++m_Num;
			x = m_x;
			y = m_y;
			m_Dir->MoveForward(this);				//最后会进入一个不可用位置而退出循环
		}
		m_x = x;							//回退到上一个位置
		m_y = y;
		m_Dir->TurnRight(this);						//转向并向前到一个可用位置
		m_Dir->MoveForward(this);
	}
}

void ScrewMatrix::Show()
{
	for(int i = 0 ; i < m_Div ; ++i)
	{
		for(int j = 0 ; j < m_Div ; ++j)
		{
			cout<<m_Matrix[i * m_Div + j]<<"  ";
		}
		cout<<endl;
	}
}

测试:

#include "stdafx.h"
#include "ScrewMatrix.h"

int _tmain(int argc, _TCHAR* argv[])
{
	ScrewMatrix matrix(6);
	matrix.Generate();
	matrix.Show();

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值