ARTS训练第四周

164 阅读4分钟

Algorithm

这周的算法部分非常吃力。我开始选择的题目是Median of Two Sorted Arrays。但是做了很久都没能构思出对数级复杂度的算法。后来还是按照线性扫描的思路,依次扫过两个Array,并且决定是否需要:

  1. 继续向前
  2. 跳至另一条array

在循环中,先判断是否已经行进到array的末尾,除了返回或跳转没有别的选择。如果仍然有后继,再比较后继和相邻两者哪个更“小”。全局按照小于等于的顺序排列。这个主循环返回两条array中排序为K的数。因此对于返回中位数的话,需要计算一下 (m+n)/2 的值。而且针对长度奇偶性相同的两个序列,需要额外计算排序为 (m+n)/2-1 的值,然后取均值才是中位数。

因此把返回K位数的函数打包一下,附加了判断m和n奇偶性的分支,以及找单个序列中位数的median函数用于处理序列之一为空的退化情况,就构成了完整的函数。

#define ARRONE 0
#define ARRTWO 1

int findK(int* nums1, int nums1Size, int* nums2, int nums2Size, int order, int* prev) {
    
    
    
    int* end[2]={nums1+nums1Size, nums2+nums2Size};
 
    int* cur_pos = (*nums1 <= *nums2)?nums1:nums2;
    int* adj_pos = (*nums1 <= *nums2)?nums2:nums1;
    int* nex_pos;
    int flag = (*nums1 <= *nums2)?ARRONE:ARRTWO;
    
    if(nums1Size == 0)
    {
        return nums2[order];
    }

    if(nums2Size == 0)
    {
        return nums1[order];
    }
    
    int cursor = 0;
    while(cursor < order)
    {
        *prev = *cur_pos;
        nex_pos = (cur_pos == end[flag]-1)?NULL:cur_pos+1;
        if(nex_pos==NULL && adj_pos != NULL)
        {
            cur_pos = adj_pos;
            adj_pos = NULL;
            flag = 1-flag;
            cursor++;
        }else if(nex_pos != NULL && adj_pos == NULL)
        {
            cur_pos = nex_pos;
            nex_pos = cur_pos+1;
            cursor++;
        }else if(nex_pos == NULL && adj_pos == NULL)
        {
            return *cur_pos;
        }else {
            if(*cur_pos<=*adj_pos && *adj_pos <= *nex_pos){
                cur_pos = adj_pos;
                adj_pos = nex_pos;
                nex_pos = cur_pos+1;
                flag = 1-flag;
                cursor++;
            }
            else {
                cur_pos = nex_pos;
                nex_pos = cur_pos+1;
                cursor++;
            }
        }
    }

    return *cur_pos;
}

double median(int* arr, int len)
{
    if(len%2)
    {
        return (double)(arr[len/2]);
    }else
    {
        return (double)(arr[len/2-1]+arr[len/2])/2.0;
    }
}

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    if(nums1Size == 0)
    {
        return median(nums2, nums2Size);
    }

    if(nums2Size == 0)
    {
        return median(nums1, nums1Size);
    }
    
    int order = (nums1Size + nums2Size)/2;
    int tmp;
    int res = findK(nums1, nums1Size, nums2, nums2Size, order, &tmp);
    if ((nums1Size+nums2Size)%2)
    {
        return (double)res;
    } else
    {
        return (double)(res+tmp)/2.0;
    }
}

Review

本周(其实已经是上周了)还是在啃csapp的第四章。目前看到了处理器怎样处理指令的。有了解了指令的编码和运行过程,包括取指(读取指令码),译码(将指令对应的寄存器和立即数内存地址等装好),执行(数据输入ALU计算),访存(访问存储器读取数据),写回(更新寄存器文件)。书中列举的Y86的简化架构,有详细说明每一步的操作。不过由于这一周还在忙着看别的书,没有看更多了。了解了指令编码的过程,大致对后续的处理器流水线一节有了一点模糊的感觉。

Tips

在运行csapp的Y86的配套编译器程序时,大致能看到程序是借助make命令编译。但是安装失败了几次,而且没能编译出README页面列出的所有指令。发现是首先我的ubuntu缺少了几个必备的包,后来是发现Makefile里面的目标文件all:仅列出了部分程序的名字,导致没有生成完整。修改之后就成功了。

(bash和各种命令行指令还是很厉害的,所以今天看到linux中国推送讨论bash和Python哪个更强,我感觉还是bash啊)

Share

这一周太忙了,考虑到本来share部分本来是计划看computer architecture的,但是我后来找到了一个更相关的资源,是Coursera上的一门计算机体系结构到编程语言的课Build a computer。这个Share模块本来我是计划用来提供英语的,这门课英语授课也能锻炼到,而且火急火燎地完成了第一周的课程,感觉还是很有意思的。我读研的时候有学过automatic reasoning,前一半用Isabelle去证明定理,后一半用描述性语言做formal verification。第一周的HDL(Hardware Description Language 硬件描述语言)就是类似的declarative / functional 语言,静态,需要形式验证才能证明有效性。如果真的要share,也欢迎大家一起加入这门课,不是很难,但是挺好玩的,也有助于我这种半吊子了解计算机底层的很多东西。