20162308 2016-2017-2 《程序设计与数据结构》第3周学习总结

20162308 2016-2017-2 《程序设计与数据结构》第3周学习总结

教材学习内容总结

  1. 简单的位运算
  2. 基本数据类型
  3. 常用函数的学习
  4. 掌握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)
  • 其他方面的学习
  • 这周因为其他方面的学习,基本上没有出现什么存疑的地方。感觉都还能理解,所以没有什么好写的。

代码调试中的问题和解决过程

没有遇到什么比较棘手的问题,问题基本上的由于语法上的疏忽导致。

代码托管

  • 代码提交过程 & 代码量截图:2017-03-14 (1).png

上周考试错题总结

  • 填空: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小时

  • 改进情况:学习了位运算的知识。

参考资料

posted @ 2017-03-16 14:14  20162308马平川  阅读(225)  评论(8编辑  收藏  举报