抽象思维:提取共性,应对变化
用于做程序设计维护、应用。。抽象:认识和表达世界
对比算法,发现共性
对比下楼问题和跳马问题
下楼问题与跳马问题 见https://blog.youkuaiyun.com/weixin_43829465/article/details/96004805
两个问题的差异:1、是否达到目标;2、新位置的计算(高度、落点坐标);3、判断是否合法
#include<iostream>
using namespace std;
/// task-dependent
struct position{ int x,y; };
position dxy[] ={{}{}{}{}}
//通用算法框架
void Jump(){
if(IsDone(pos)){
num++;
cout<<
}
}
通过辅助函数将共同点寻找出来,将差异思维隔离开来。
通过修改task-dependent相关的模块,适用于两种问题。
转换视角、提取共性
任务2.2 对比分书问题与八皇后问题
分书问题与八皇后问题见https://blog.youkuaiyun.com/weixin_43829465/article/details/96004805
类似于八皇后。
分书问题中,一本书只能给一个人、一个人只能选一本书。转化为二维矩阵。
均有共同的限定条件:每一行、每一列只能出现一次,不重不漏。不能出现第二个皇后、把书分配出去的标记。
不同点:八皇后对角线不能重;分书问题非全二维矩阵、是矩阵的子集
利用限定的条件去设置矩阵元素。
这两个问题的代码重构
#include<iostream>
using namespace std;
// #define QUEEN
//增加了条件编译选项
bool IsValid(){
}
int main(){
num = 0;
place_state state = CreateInitState();
Try(0,state);
return 0;
}
思考题:下楼、跳马、分书、八皇后四个问题能否合成同一个抽象的算法框架??
代码重构、隔离变化
任务2.3 填充数字旋转方阵
逆时针旋转矩阵(1~NN)填充nn矩阵
函数Fill(number,begin,size)从位置(begin,begin)开始填写。矩阵大小为size*size。
#include<iostream>
#include<iomanip>
using namespace std;
int m[m][n] = {{0}};
void Show()
{
for(int i = 0)
}
任务2.4基于OOP来解决矩阵填充
Object Oriented Programming(OOP)面向对象程序设计
int main() \\main函数测试代码、一般先看先写main代码
{
matrix obj;
cout<<"please input N:";
int size;
cin >> size;
obj.init(size);
obj.fill();
obj.print();
obj.clear();
return 0;
}
#include<iostream>
#include<iomanip>
using namespace std;
class matrix
{
int N;
int** M;//用二维指针代表矩阵
int row,col;
char dir; //'D''R''U''L'
void place(int num);
public:
void init(int size);
void clear();
void fill();
void print();
}
void matrix::init(int size)
{
N = size;
col = 0; raw = -1;
dir = 'D'; //最初方向
M = new int*[N];
for (int r=0; r<N; r++) //r代表每一列
{
M[r] = new int[N];
memset(M[r], 0, sizeof(int)*N ); //矩阵清零、表示无数字
}
}
void matrix::clear()
{
for(int r=0; r<N; r++) delete[] M[r];
delete[] M;
}
void matrix::place(int num)
{
//step1:先根据前一位置、方向,以及摆放规则(DRUL)确定下一个摆放数据的位置
switch(dir)
{
//以下为部分源代码
case 'D':
// 先保证row在合法范围内,再考虑该处是否有数字(为零?)
if (row < N-1 && M[row+1][col] == 0)
row++;
else{
dir = 'R';
col++;
}
break;
}
}
思考题:逆时针填充变为顺时针?若均要支持?若要支持蛇形、Z字形、U字形呢?
很少改动去应对复杂变化->如何用最高的效率去面对变化。(抽象)
任务2.5深入思考:矩阵到底是什么?
M为矩阵的数学运算接口
F为旋转填充的操作接口
矩阵的数学本质:结构化的多维数据
填充操作不是矩阵所固有的、填充操作可以独立于矩阵。

#ifndef MATRIX_H
#define MATRIX_H
#include<iostream>
using namespace std;
class matrix
{
int row,col,**buf; \\数据区域buf--指针的指针
public:
matrix(int,int);
~matrix();
int& operator() (int r,int c); //matrix_obj(r,c) 取一个值出来,返回一个引用 对矩阵的第r行第c列进行赋值。将值附到obj中。
friend ostream& operator << (ostream&, const matrix&); //运算符重载输出结果
} ;
#endif
#include "matrix.h"
#include<iostream> //cout
#include<iomanip> //setw()
using namespace std;
matrix::matrix(int r, int c)
: row(r), col(c)
{
buf = new int*[row];
for (int i = 0; i<row; i++)
buf[i] = new int[col];
}
matrix::~matrix()
{
for(int i=0; i<row; i++)
delete[] buf[i];
delete buf;
}
// 用函数运算符(),实现对矩阵多下标访问支持
int& matrix::operator() (int r, int c)
{
return buf[r][c];
}
ostream& operator << (ostream& o, const matrix& m)
{
for(int i=0; i<m.row; i++)
{
for(int j=0; j<m.col; j++)
o << setw(2) << m.buf[i][j] << ' ';
o << endl;
}
return o;
}
#ifdef TEST_MATRIX //条件编译:ifdef 判断某个宏定义是否被定义,若已定义则执行随后语句 下面是matrix类的测试代码
int main()
{
matrix m(4,5);
for(int i=0; i<4; i++)
for(int j=0; j<5; j++ )
m(i, j) = i*j;
cout << "Matrix 4X5:" << endl;
cout << m << endl;
return 0;
}
#endif
// g++ -DTEST_MATRIX matrix.cpp
任务2.6 深入思考:填充算法是什么?
F:当前位置、当前方向、新位置、规则(下一方向)
输入是他需要、输出是他要得到的——抽象
填充算法的本质-按指定规则,依次生成位置信息。
不同规则的共性如何抽取?如何描述?
用不同的字母表示不同移动方向(大写字母连续前进多步、小写字母前进一步)
Z向右上,z向左下;D down向下 ;R right向右 ;U up向上 ;L left向左
逆时针旋转:DRUL
顺时针旋转:RDLU
U字型:DrUr(竖)、RdLd(横)
Z字型:dZrz…、rzdZ…
设定了字母的集合、每个字母有特定的含义。根据需要选择相应的文字
即根据字符串内容逐个解析字符串、逐个步骤操作。
#ifdef FILLER_H
#define FILLER_H
struct location{ int row, col; };
class filler{
location pos ;
char rule[4];
int idx; //填充方向 dir =rule[idx]
int row_num, col_num;
int r_min, r_max, c_min, c_max; //用于实现旋转方阵
public:
filler(int, int); //range
void reset();
void set_rule(const char*);
location operator *(); //get current location
filler operator ++ (int); // post ++ ,next location
};
#endif
#include "filler.h"
#include "cstring"
using namespace std;
filler :: filler(int rn, int cn)
: row_num(rn), col_num(cn) { reset(); }
void filler::reset(){
pos.row = pos.col = 0;
idx = 0;
r_min = c_min = 0;
r_max = row_num - 1 ;
c_max = col_num - 1 ;
}
void filler::set_rule(const char* r)
{ strncpy(rule,r,4); }
location filler::operator* ()
{ return pos; }
借鉴思考1–标准模板库STL
容器(数据结构)、算法、迭代器(运用算法)。
任务2.7深入思考:规则是什么?
规则在本质上是独立于填充算法而存在的。
class rule 设计思路
(f,r)-> " 字符串 "
指令怎么存的相对于filler对象是封闭的
参照STL将规则给剥离出去
思考题:如果被填充的是迷宫,要求根据制定规则,生成从入口到出口的路径。如何抽象共性?
借鉴思考2–正则表达式
由字符组成的序列、能与之按规则(定义)匹配的字符串的集合。从某种角度看正则表达式也是一种语言.
由字母所组成的字符串,互相进行匹配。
有一些特殊的字符称为元字符
例如 ^ 表示字符串开始 $表示字符串结束
printf()格式化字符串其会按给定的字符串输出数据。
任务2.8 正则表达式工具grep简版
函数grep扫描每一个文件、对每一行采用grep函数