ARTS(10)

栏目: 编程工具 · 发布时间: 7年前

内容简介:在单元测试一定要充分,现实往往是那些疏忽的单元测试出问题。

1 Algorithm

设计一个 LRU 缓存机制,使它支持 putget 操作,缓存大小是由一定限制的,如果缓存数量超出范围,则删除最近最少使用的 key ,如果 key 不存在,返回 -1 (所有的 value 值大于0),时间复杂度为$O(1)$。

为了保证时间复杂度为$O(1)$,就需要用空间换时间,为了保证更新 Key 和删除 Key 在常数时间内完成,所以采用双向链表完成,查询 Key 在常数时间内完成,则使用 字典 保存每一个 Key ,而且 Value 指向双向链表的每一个元素。依次 Put(1,1), Put(2,2), Put(3,3) 后,示意图如下:

ARTS(10) Front 节点为最近最少使用的 key , Back 节点为最近最多使用的节点。一旦 Get 命中,则将该节点中列表中摘除出来,并且添加到最后。
type Element struct {
    key  int
    value int
    prev  *Element
    next  *Element
}

type List struct {
    head *Element
    tail *Element
}

func NewList() *List {
    l := &List{
        head:∈{},
        tail:∈{},
    }
    l.head.next = l.tail
    l.tail.prev = l.head
    return l
}

func (l *List) Remove(e *Element) {
    pre, next := e.prev, e.next
    pre.next = next
    next.prev = pre
}

func (l *List) Push(e *Element) {
    e.prev = l.tail.prev
    e.prev.next = e
    e.next = l.tail
    l.tail.prev = e
}

func (l *List) Pop() *Element {
    if l.head.next == l.tail {
        return nil
    }
    e := l.head.next
    l.Remove(e)
    return e
}

type LRUCache struct {
    l        *List
    capacity int
    table    map[int]*Element
}

func Constructor(capacity int) LRUCache {
    return LRUCache{
        l:        NewList(),
        capacity: capacity,
        table:    make(map[int]*Element),
    }
}

func (this *LRUCache) Get(key int) int {
    if val, ok := this.table[key]; ok {
        this.l.Remove(val)
        this.l.Push(val)
        return val.value
    }
    return -1
}

func (this *LRUCache) Put(key int, value int) {
    if val, ok := this.table[key]; ok {
        this.l.Remove(val)
        val.value = value
        this.l.Push(val)
    }else{
        e := ∈{key:key, value:value}
        if len(this.table) < this.capacity {
            this.l.Push(e)
            this.table[key] = e
        }else{
            n:=this.l.Pop()
            delete(this.table, n.key)
            n = nil
            this.l.Push(e)
            this.table[key] = e
        }
    }
}

2 Review

Why I love refactoring

为什么我喜欢重构

我喜欢重构,如果不是显然的需求,这也是我软件开发的方法。可以甚至说,我喜欢重构超过喜欢写新需求。我几乎将圣诞假期、新年假期都用在在之前的代码中提取有用的东西。

当在重构的时候,你比当初写下第一行代码的时候更加了解这个领域,所以能够揭开无数之前的错误的假设。你也知道了这些代码在将来会怎么使用,因而更加有有序的组织它们。也知道性能方面问题是否存在,或者事实上性能是否你需要考虑的。

当你编写新的功能的时候, 代码库将会变得更加难以理解。你可能会编写一下很棒的代码,每一行的代码质量也会往上发展,但是这些都不重要的。我们都知道,大的代码库比小的代码库更加难以阅读,大代码库包含更多的文件夹,更多的文件和更多的层次设计,甚至都需要用 grep 工具来查询。但是如果使用重构,你将会往另外一个方向发展,将来的开发者在使用 git blame 的时候,会大大称赞你的名字。

还有更具有洞察力原因是重构有助于你的健康,但是这也不是我为什么喜欢重构的原因。我喜欢编写代码,既喜欢重构,也喜欢编写新的功能。但是没有比写出好的代码更加让人欣慰,没必要担心你的代码是否对别人有用,只要你自己知道就好了。你清楚地知道了使用哪种抽象,将你第一次编写功能的时候担心和优化隔离开来。

对于编写第一个版本的人保持尊重是非常重要的,他们也是聪明的人,是在你不同的限制条件下。或许联合国秘书长应该在将来24小时拍下一个快照,将来和现在都是不同的。没有人知道它的代码在将来会变得非常重要,甚至是在几年后还在运行着。他们的决定是重要的,你应该记住这一点。

不幸的是即使你有一个高品位的代码库,你也不会得到任何赞赏。但是实现它们是重要的而不是得到赞赏,要记住:让一些事变得有用起来。

3 Tips

3.1 github 更新 fork 的仓库

github 上参与开源项目, fork 一份代码仓库后,如果原仓库有更新,那么如果更新自己 fork 出来的一份呢?

  • 添加 remote 源: git remote add upstream https://github.com/whoever/whatever.git ;
  • 拉取源: git fetch upstream ;
  • 切换到 master 分支: git checkout master
  • rebase 分支: git reabse upstream/master

4 Share

单元测试一定要充分,现实往往是那些疏忽的单元测试出问题。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Development Recipes

Web Development Recipes

Brian P. Hogan、Chris Warren、Mike Weber、Chris Johnson、Aaron Godin / Pragmatic Bookshelf / 2012-1-22 / USD 35.00

You'll see a full spectrum of cutting-edge web development techniques, from UI and eye candy recipes to solutions for data analysis, testing, and web hosting. Make buttons and content stand out with s......一起来看看 《Web Development Recipes》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具