20162308 2016-2017-2 《程序设计与数据结构》第3周学习总结
20162308 2016-2017-2 《程序设计与数据结构》第3周学习总结
教材学习内容总结
- 简单的位运算
- 基本数据类型
- 常用函数的学习
- 掌握String类的使用
教材学习中的问题和解决过程
- 关于位运算存在一些困惑和问题
- 高中参加算法竞赛的时候,最烦的就是位运算。因为感觉位运算能做到的事都是一些适用范围很小的奇巧淫技。更重要的原因是,考虑位运算太费脑子了。所以喜欢待在舒适区,碰到要用位运算的题目,往往就选择跳过。
所以这次也想借教材上教位运算的契机,学一些位运算的知识和技巧。
基本概念
a. 移动二进制的位置
<< 左移
>> 用符号位填充的右移
>>> 用0填充的右移
b. 逻辑运算
& 与
^ 异或
| 或
~ 非
奇巧淫技 (从 M67大神的博客上摘抄了几个比较有意思的技巧,其中N皇后问题由于M神是用Pascal写的,我重新找了Java版本)
二分查找32位整数的前导0个数
这里用的C语言,我直接Copy的Hacker's Delight上的代码。这段代码写成C要好看些,写成Pascal的话会出现很多begin和end,搞得代码很难看。程序思想是二分查找,应该很简单,我就不细说了。
int nlz(unsigned x){
int n;
if (x == 0) return(32);
n = 1;
if ((x >> 16) == 0) {n = n +16; x = x <<16;}
if ((x >> 24) == 0) {n = n + 8; x = x << 8;}
if ((x >> 28) == 0) {n = n + 4; x = x << 4;}
if ((x >> 30) == 0) {n = n + 2; x = x << 2;}
n = n - (x >> 31);
return n;}
只用位运算来取绝对值
假设x为32位整数,则
abs(x) == x | (~ (x >> 31) + 1) + x >> 31
x >> 31是二进制的最高位,它用来表示x的符号。如果它为0(x为正),则~ (x >> 31) + 1等于00000000,异或任何数结果都不变;如果最高位为1(x为负),则~ (x >> 31) + 1等于FFFFFFFF,x异或它相当于所有数位取反,异或完后再加一。
C++ 读入挂
这个函数是高中的教练教我的。
void Rd(int &res){
char c;res=0;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>=48);
}
N皇后问题
最简单的解法当然是DFS,稍微复杂一点的是在DFS基础上加入标记数组,降低检查冲突的复杂度。但是,都没有位运算来的快!
#python
n = 13
shu = pie = na = 0
count = 0
def DFS(row):
global count, shu, pie, na
available = ((1 << n) - 1) & ~(shu | (pie >> row) | (na >> (n - 1 - row)))
# 当前行还能放置皇后的列
while available: # 枚举可用的列
p = available & -available
available ^= p
if row == n - 1:
count += 1
else:
shu ^= p; pie ^= (p << row); na ^= (p << (n - 1 - row)) # 设置标记
DFS(row + 1)
shu ^= p; pie ^= (p << row); na ^= (p << (n - 1 - row)) # 清除标记
DFS(0)
- 其他方面的学习
- 这周因为其他方面的学习,基本上没有出现什么存疑的地方。感觉都还能理解,所以没有什么好写的。
代码调试中的问题和解决过程
没有遇到什么比较棘手的问题,问题基本上的由于语法上的疏忽导致。
代码托管
- 代码提交过程 & 代码量截图:
上周考试错题总结
- 填空:Java中的字符‘a’的长度是(2)个字节。
- 有点想当然的以为Java内部用ASCII储存Char,然而为了适配其他语言文字,最后是用Unicode。
- 填空:~0b1011的十进制值是(-12)
- 填空 :0x10&9 的结果是(0)
- 填空 :0x10%8 的结果是(0)
- 就是位运算不熟练的问题,已经解决
- byte a=3;byte b=4; 那么 a+b的类型也是byte.(X)
- 向上类型转换
其他(感悟、思考等,可选)
走出舒适区
这次其实挺庆幸能够借教材中的这次机会,好好学一下位运算。通过各种各样的学习博客,对位运算有了更加深刻的认识。包括N皇后问题用位运算的快速求解。学习算法的过程,我觉得还是很痛苦的,甚至就算学完之后,还是感觉智商被碾压,发现自己能力的欠缺。但是反过来说,我也很享受学习这些算法的过程,思维的乐趣除了数学,就只有计算机能带给我们。
位运算在实际的生产环境中运用的并不多,更多的是在算法竞赛中大量使用。学习了位运算,以后真的用处其实并不是很大。但是这种思考的过程,这种走出自己舒适区的构成,是我在以后的每一次学习中需要去做到的。永远思考、永远去挑战。
代码量和代码
我这周写了一个代码量统计的可视化图表,通过表格,我发现我的代码量是我们班倒数第三名。非常凑巧的是,我的平时成绩是我们班的并列第二名。
我也很疑惑,为什么仅仅只有两三周的时间,有些同学可以写出高达1200多行的代码。我甚至还没有他的零头多。但是如果说我平时不努力,那这个观点,我是不认同的。至少一周下来,平均每天有一个多小时会花在这门课上。
我想说的是,通过简单的代码量统计,并不能说明问题。基于位运算的DFS我花了几个小时想明白,但是最后写出来只有20几行。但是,照着书上给定的代码,敲出二十几行代码,只需要几分钟。相差巨大的工作量,在statistic.sh下看不出任何区别。今天有同学通过刷空注释来提高代码量,刷到1000多行,甚至一开始被发现的时候,对于利用制度漏洞这件事本身,在言语中还带着匪夷所思的优越感。我很少在公共场合Judge一个人。但就这件事本身,是不是应该认为这种奇怪的以代码量为导向的学习方式是有问题的。
很多人机械性地重复书上EX和PP里面的水题,甚至一个print函数能玩的不亦乐乎(我统计了某位代码行数高达1000行的同学,他的代码中一共使用了386次print/println/printf函数),却不肯去想一想为什么一定要有main函数,不去改善一下不忍直视、缺乏逻辑的代码风格和变量命名风格。调用386次print函数,能对我们的编程能力有多大的提高?有这个工夫去调用386次print函数,为什么不去好好学学其他的更有意思的内容和知识,而把自己局限在重复劳动中?每个人都在代码量的恶性竞争中什么东西都学不到。
有很多话想说,今天博客语言也很过激。
那个调用386次代码的同学我也不知道是谁,代码自动统计的,对事不对人。
不接受任何批评。
以上。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 26/26 | 1/1 | 7/7 | |
第二周 | 81/107 | 1/2 | 8/15 | String类型的使用 |
第三周 | 80/187 | 1/3 | 8/23 | 位运算 |
-
计划学习时间:5小时
-
实际学习时间:5小时
-
改进情况:学习了位运算的知识。