程序员面试金典: 9.5位操作 5.8通过位操作进行两点连线
2017-01-04 13:18
295 查看
#include <iostream> #include <stdio.h> #include <vector> #include <string> #include <bitset> using namespace std; /* 问题:有个单色屏幕存储在一个一维字节数组中,使得8个连续像素可以存放在一个字节里。屏幕宽度为w,且w可以被8整除(即一个字节不会分布在 两行上),屏幕宽度可由数组长度及屏幕宽度推算得出。请实现一个函数drawHorizontalLine(byte[] screen, int width, int x1 ,int x2, int y),绘制从点(x1,y)到(x2,y)的水平线。 分析:绘制水平线本质上是找到水平线上的起点和重点,然后连接,起点和重点都已经确认,这个应该没什么难度,由于是一维数组, 首先明确在屏幕中:x代表水平方向,也就是实际意义上的竖轴(列),y代表垂直方向,代表了矩阵中实际意义的横轴(行) 假设给定的像素位置为(x,y),那么它实际在一维数组的位置p=x+w*y 所以起点(x1,y)在是screen[x1+w*y]中的字节,(x2,y)对应screen[x2+w*y]字节, 找到两个字节后,调用drawLine函数即可绘制 书上解法:我没理解绘线的本质实际上将线上的所有像素的颜色都设置为同一个颜色。那么暴力破解解法就是遍历从(x1,y)到(x2,y)上所有 经过的像素,设置颜色,时间复杂度为O(x2-x1) 注意:给定的x是像素的横坐标而不是字节,一个像素占据一个bit 关键: 1 绘线的本质实际上将线上的所有像素的颜色都设置为同一个颜色 2 确定比特x1对应的字节x1Byte = x1 / 8,以及起始比特位x1Bit = x1 % 8 确定比特x2对应的字节x2Byte = x2 / 8, 以及结束比特位x2Bit = x2 % 8 如果x1Bit不为0,说明x1Byte不是完整的字节,令起始字节startByte = x1Byte + 1;否则,令startByte = x1Byte 如果x2Bit不为7,说明x2Byte不是完整的字节,令结束字节endByte = x2Byte - 1;否则,令endByte = x2Byte 将startByte~endByte中字节全部设置为0xff(即白色) 设置左边不完整字节(左边起始字节)掩码,用于后续与运算,必须将不完整字节前面x1Bit位排除,即前面x1Bit位为0,后面8-x1Bit位为1, 所以左边掩码leftMask = 0xff >> x1Bit 设置右边不完整字节(右边最后字节)掩码,必须将x2Bit位包含,即前面x2Biit(包含x2Bit位本身)位为1,后面8-x2Bit位为0, 所以右边掩码rightMask = ~ ( 0xff >> (x2Bit + 1) ) 还需要判断x1与x2对应的字节是否在同一个字节中,因为如果在同一个字节中,需要对左边掩码和右边掩码进行与操作才能得到真实的掩码 mask = leftMask & rightMask 对应字节在screen中位置pos = w * y/8 + x1Byte 对应的字节为 screen[ pos ] |= mask 易错,容易漏掉 如果不在同一个字节,则对左边不完整字节,掩码处理 posLeft = w * y/8 + x1Byte screen[ posLeft ] |= leftMask 右边不完整字节取掩码 posRight = w * y/8 + x2Byte screen[ posRight ] |= leftMask 结束 3 screen.at(pos) |= leftMask;//注意是或运算,通过1来设置颜色,其余保持字节原先的颜色 如果用与,那么掩码中0的部分会使得像素颜色发生变化,而我们真正需要的是掩码中的1, 掩码中的0应该不起作用,所以用或运算 */ //这里的宽度width,对应的是比特 void drawHorizontalLine(vector< bitset<8> >& screen, int width, int x1 ,int x2, int y) { if(screen.empty()) { return; } //判断x1和x2大小,使得x1为较小值 if(x1 > x2) { int temp = x1; x1 = x2; x2 = x1; } //计算起始和结束字节位置 int x1Byte = x1 / 8; int x1Bit = x1 % 8; int startByte = x1Byte; if(x1Bit != 0) { startByte++; } int x2Byte = x2 / 8; int x2Bit = x2 % 8; int endByte = x2Byte; if(x2Bit != 0) { endByte--; } int leftMask = 0xff >> x1Bit; int rightMask = ~ ( 0xff >> (x2Bit + 1) ); //对起始到结束部分完整字节设置为白色 for(int i = startByte ; i <= endByte ; i++) { //宽度是比特,需要转化为字节 int pos = width/8 * y + i; screen.at(pos) = 0xff; } //判断两个x1和x2是否位于同一个字节中,易漏,注意不要 if( x1Byte == x2Byte ) { int mask = leftMask & rightMask; int pos = width/8 * y + x1Byte; screen.at(pos) |= mask; } else { //判断左边起始字节是否是不完整字节,如果是不完整字节,就对左边起始字节进行掩码运算 if(x1Bit != 0) { int pos = width/8 * y + x1Byte; screen.at(pos) |= leftMask;//注意是或运算,通过1来设置颜色,其余保持字节原先的颜色 } //对右边结束字节进行掩码运算 if(x2Bit != 7) { int pos = width/8 * y + x2Byte; screen.at(pos) |= rightMask; } } } int main(int argc, char* argv[]) { getchar(); return 0; }
相关文章推荐
- ASP通过DOM进行XML操作
- 目前比较流行的ASP木马主要通过三种技术来进行对服务器的相关操作
- 使用黑莓8900通过蓝牙连接华为交换机进行现场网络配置与操作(一)
- 第2章_基本数据类型和基本操作_编程练习Exercise2.7通过创建窗口进行大小写的切换
- 第2章_基本数据类型和基本操作_编程练习Exercise2.11通过控制台进行大小写的切换
- 使用Struts的Action来通过Hibernate对数据库进行增、删、改、查四项操作
- 通过Socket进行HttP/HTTPS网页操作
- C#通过一个密码对文件进行加密解密操作
- 通过PBO进行opengl与Cuda的纹理互操作
- 通过sql语句对mysql数据库进行基本的操作
- javascrip通过超链接传递中文时应该进行的操作(中文编码)
- DELPHI通过ACTIVESYNC连接到移动设备,并进行文件的复制,删除等操作!
- VB中通过oo4o进行Oracle数据库操作-Update Delete Insert
- 原创:通过jQuery进行跨域操作
- java中通过调用oracle的function进行数据库操作
- 通过组合条件对DAO进行查询操作
- VB中通过oo4o进行Oracle数据库操作-Select
- Flex中通过doubleClick事件来检测用户是否在TextInput控件中进行了双击(double clicks)操作的例子
- Spring中使用getSession()与通过HibernateTemplate进行数据操作的差别
- 通过Socket进行HttP/HTTPS网页操作