问题:
给定一个二维原数组,输出该数组矩阵进行Z字形编排后的内容。
原二维数组示例:
输出示例:
算法描述:
个人思路:
可以利用“走迷宫”算法的思路,先把所有可以移动的方向枚举出来,如下:
enum WAY{
RIGHT,
BOTTOM,
LEFTBOTTOM,
RIGHTTOP,
NONE
} nextWay;
然后利用状态机思想,在循环遍历原数组的内循环中,switch case一下当前应该走的方向,然后在走完之后确定一下下一步应该走哪个方向(注意一定要在确定下一步之前加判断防止越界)。仔细观察该问题可以发现该走法有以下几个特征:
1.第一步在左上角开始走。
2.导致下一步往右走的情况只可能是:
- 走了第一步。
- 从左下到右上移动了之后移动到了首行,并且非右上角(RIGHTTOP方向移动到了右上角便没办法再右移了),那么接下来应该往右。
- 从右上到左下方向移动之后到了左下角或者底边,接下来没办法继续左下移动了,所以只能朝RIGHT方向移动。
3.导致下一步往下走的情况只可能是:
- 当前进行了左下方向的移动,并且移动到了首列,这时候如果当前point非左下角的话,就应该往下移动。
- 当前进行了右上方向的移动,并且移动到了尾列,那么这时候便无法继续右上了,所以下一步只能往下方移动。
4.导致往左下方向移动的可能性只能是:
- 在首行向右移动了之后,下一步应该往坐下移动。
- 如果上一步就是往坐下移动的,且没有触碰到坐下边界,则下一步应该继续往左下移动。
- 当尾列往下方移动一步之后,下一步应该往左下移动。
5.导致往右上方向移动的可能性只能是:
- 在首列往下移动一步之后,应该往右上移动。
- 如果上一步就是右上移动,且下一步并不会达到右上角或者右边及顶边边界,那么还应该继续往右上移动。
- 上一步如果是在底边横向往右移动了一步,那么下一步应该往右上。
个人思路实现的完整代码如下:
#include <iostream>
#include <stdlib.h>
#include <typeinfo>
#include <memory>
#define SIZE 8
using namespace std;
void print (int** p){
//输出
for (int i = 0; i < SIZE; ++i){
for (int j = 0; j < SIZE; ++j){
cout << p[i][j] << '\t';
}
cout << endl;
}
}
void init(int** p){
for (int i = 0; i < SIZE; ++i){
for (int j = 0; j < SIZE; ++j){
p[i][j] = i*SIZE + j;
}
}
}
enum WAY{
RIGHT,
BOTTOM,
LEFTBOTTOM,
RIGHTTOP,
NONE
} nextWay;
struct Point{
int row;
int clum;
};
int main(){
int** p = new int*[8] ;
int** nP = new int*[8];
for (int i = 0; i < SIZE; ++i){
p[i] = new int[8];
memset(p[i], 0, sizeof(int)* 8);
nP[i] = new int[8];
memset(nP[i], 0, sizeof(int)* 8);
}
init(p);
nextWay = NONE;
Point curPos;
cout << "原数组:" << endl;
print(p);
for (int i = 0; i < SIZE; ++i){
for (int j = 0; j < SIZE; ++j){
switch (nextWay){
case RIGHT:
curPos.clum += 1;
if (curPos.row == 0){
//首行右移
nextWay = LEFTBOTTOM;
}
else{
//底行右移
nextWay = RIGHTTOP;
}
break;
case BOTTOM:
curPos.row += 1;
if (curPos.clum == 0){
//首列下移
nextWay = RIGHTTOP;
}
else{
//尾列下移
nextWay = LEFTBOTTOM;
}
break;
case LEFTBOTTOM:
curPos.row += 1;
curPos.clum -= 1;
if (curPos.clum == 0){
//如果已经左下移动到首列
if (curPos.row == SIZE - 1){
//如果移动到左下角
nextWay = RIGHT;
}
else{
//如果移动到左边首列但非左下角
nextWay = BOTTOM;
}
}
else{
if (curPos.row == SIZE - 1){
//如果移动底列
nextWay = RIGHT;
}
else{
//如果移动到非左边首列且非底列
nextWay = LEFTBOTTOM;
}
}
break;
case RIGHTTOP:
curPos.clum += 1;
curPos.row -= 1;
if (curPos.row == 0){
//如果右上角移动已经移到了首行
if (curPos.clum == SIZE - 1){
//如果移动到了右上角
nextWay = BOTTOM;
}
else{
nextWay = RIGHT;
}
}
else{
if (curPos.clum == SIZE - 1){
//如果移动到了最右列
nextWay = BOTTOM;
}
else{
nextWay = RIGHTTOP;
}
}
break;
case NONE:
curPos.clum = 0;
curPos.row = 0;
if (curPos.clum + 1 < SIZE)
nextWay = RIGHT;
break;
}
nP[curPos.row][curPos.clum] = p[i][j];
}
}
cout << endl << endl;
cout << "输出该数组进行Z字形编排后的内容:" << endl;
print(nP);
delete[] p;
delete[] nP;
system("pause");
return 0;
}
注意事项: 主要是在进行下一步走法的确定时,一定要严格检查是否已经达到边界,因为如果达到了边界,则下一步的方向可能发生改变。