书中的问题描述如下:象棋将帅问题:将帅不能在同一条直线上,各自在3*3的格子里面 ,请写出一个程序,要求用一个字节存储变量。书中给出了三种解法,我都贴在了下面。首先是代码思路:
*假设将为A,帅为B
* 遍历A的所有位置
* 遍历B的所有位置
* 判断A、B是否在同一直线上
* 若不在同一直线,则输出
然后以下是三种方法的详细实现,我都是在DEV C++5.8.2版本编译器中编译通过的,代码中的算法策略注释片段是我的理解。
FirstSolution
#include <stdio.h>
/* *算法策略: *声明一个字节的变量,将它的前四位设置为A的位置代号从0001到0101,即1到9 *将它的后四位设置为B的位置代号也从0001到0101,即1到9 */
#define HALF_BITS_LENGTH 4
//这个值定为一个字节的一半
#define FALLMASK 255
//即FALLMASK为 1111 1111
#define LMASK ( FALLMASK << HALF_BITS_LENGTH)
//即LMASK为 1111 0000
#define RMASK ( FALLMASK >> HALF_BITS_LENGTH)
//即RMASK为 0000 1111
#define LSET(b,n) (b = ((b & RMASK) | ((n) << HALF_BITS_LENGTH)))
//将b左边4位设置为n,首先将b左边4位置为0,再和n做“或”操作
#define RSET(b,n) (b = ((b & LMASK) | (n)))
//同理,将b的右边4位设置为n,首先将b的右边四位置为0,再和n做“或操作
#define LGET(b) ((LMASK & b) >> HALF_BITS_LENGTH)
//获取左边四位的值
#define RGET(b) (RMASK & b)
//获取右边四位的值
#define FRIDW 3
int main()
{
unsigned char b;
for(LSET(b,1); LGET(b) <= FRIDW*FRIDW;LSET(b,(LGET(b)+1)))
{
for(RSET(b,1); RGET(b) <= FRIDW*FRIDW;RSET(b,(RGET(b)+1)))
{
if(LGET(b) % FRIDW != RGET(b) % FRIDW)
printf("A = %d,B = %d\n",LGET(b),RGET(b));
}
}
}
SecondSolution
#include <stdio.h>
#include <windows.h>
/*
*算法策略:
*声明一个BYTE型变量i,赋值为81
*将i除以9的商记做A的位置,模3以后判断是否位置合法
*将i模9的余数记做B的位置 ,模3以后判断是否位置合法
*/
int main()
{
BYTE i=81;
while(i--)
{
if( i/9 % 3 == i%9%3 )
continue;
printf(" A = %d, B = %d \n",i/9 + 1,i % 9 + 1);
}
}
ThirdSolution
#include <stdio.h>
/* *算法策略: *定义一个字节的结构体, *位域中的低四位设置为存储A的位置信息 *位域中的高四位设置为存储B的位置信息 *比较模3以后的值是否相等 */
int main()
{
/* *位域空间:位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为: struct 位域结构名 { 位域列表 }; 其中位域列表的形式为:类型说明符 位域名:位域长度 */
struct {
unsigned char a:4; //结构体变量a只使用其中低4位
unsigned char b:4; //变量b使用高四位
} i;
for(i.a = 1;i.a <= 9;i.a++)
for(i.b = 1;i.b <= 9;i.b++)
if(i.a % 3 != i.b % 3)
printf("A = %d, B = %d\n",i.a,i.b);
}
因为是刚刚才开始研究算法,所以体会也不是很深,写这篇博客有两个目的:一是想记录一下自己的学习过程,另一个是想就书中提出的问题和大家讨论。问题是:有人说第三种算法策略是效率最高的,请读者自己证明。比较第二、三种算法,我的理解是每次循环,第二种算法每次产生的中间变量都要比第三种算法的多,那么内存的读写肯定开销就大,所以第三种算法效率就要高。希望大家看到的话,可以讨论讨论这个理解是否正确,欢迎回复。