由一个简单算法想到的程序员素养问题

简介: 题记:五月从帝都回到武汉,旅游半个月后开始找新工作,六月选择了一家华中地区为数不多的移动互联网公司入职至今,略有感触——比较帝都码农与武汉码农的平均水平,就跟两个城市的经济发展水平差异一样大,不是说武汉这边没有优秀的程序员(我也算半个嘛),而是说平均水平确实不如其他一线城市。

题记:五月从帝都回到武汉,旅游半个月后开始找新工作,六月选择了一家华中地区为数不多的移动互联网公司入职至今,略有感触——比较帝都码农与武汉码农的平均水平,就跟两个城市的经济发展水平差异一样大,不是说武汉这边没有优秀的程序员(我也算半个嘛),而是说平均水平确实不如其他一线城市。想想也正常,巨头公司都扎堆北上广深,以极具竞争力的薪酬福利和巨头光环吸引着广大程序员,反观武汉的互联网发展尚处在初级阶段,无论从公司规模、名气还是最实际的薪酬福利方面均不如一线城市,自然无法吸引广大程序员咯。本人在新公司待了近三个月,慢慢发现代码中的一些问题,而这些问题中除开因为个人能力短时间无法解决的,剩下的就是我想探讨的程序员素养问题。

 
  先说下我所认为的程序员素养吧,我认为应包括以下几个方面呢:1,扎实的功底——扎实掌握操作系统,数据结构等大学基本课程,鼓吹基础无用论的,必定是个三流程序员。2,学习心态——对你所调用的,一定要有好奇心,尽可能花时间去了解API背后的东西,去了解系统框架是如何运作;对新的领域,一定要有好奇心,多尝试多学习,他山之石,可以攻玉。3,善于自学、总结、发问——工作后没有人去手把手教你,只要自己刻苦专研,并总结成博客或者笔记之类的成果,才又提高;在遇到自己能力范围内解决不了的问题,要善于向牛人请求点播,而一针见血的问题往往也会收获一针见血的回答。
 
  举一个简单的例子来讨论素养1,需求如下:已经完成排序的1万条数据,现在需要取前5000条作为最终数据,考虑到数据量较大,如果是新建列表,遍历旧列表的5000条并重新建立引用,有(引用类型所占字节 * 5000)字节的空间上的浪费,而且这种方式显得比较笨拙。
 
  所以,略加思索后写出了以下代码:
 
复制代码
List<Item> rankItems = new ArrayList<Item>();
// 生成数据+排序
...
while (rankItems.size() > 5000) {
    rankItems.remove(rankItems.size() - 1);
}
复制代码
  简单分析,对于ArrayList大家都不陌生,是以数组方式实现的链表,remove(index)方法实质上调用的是System.arraycopy()方法, 源码如下:
 
复制代码
    /**
     * Removes the object at the specified location from this list.
     *
     * @param index
     *            the index of the object to remove.
     * @return the removed object.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || >= size()}
     */
    @Override public E remove(int index) {
        Object[] a = array;
        int s = size;
        if (index >= s) {
            throwIndexOutOfBoundsException(index, s);
        }
        @SuppressWarnings("unchecked") E result = (E) a[index];
        System.arraycopy(a, index + 1, a, index, --s - index);
        a[s] = null;  // Prevent memory leak
        size = s;
        modCount++;
        return result;
    }
复制代码
  System.arraycopy()是native方法,调用的应该是C语言中的memcpy(),虽然copy的source地址和dest地址都是相同的,无需分配新内存,但是要经过5000次的内存IO读写才能删除ArrayList中的数据。究其原因是因为ArrayList的数组实现方式,不利于在指定位置做添加/删除操作,所以思考后有了以下代码:
 
复制代码
List<Item> rankItems = new LinkedList<Item>();
// 生成数据+排序
...
while (rankItems.size() > 5000) {
    rankItems.remove(rankItems.size() - 1);
}
复制代码
  再分析LinkedList的删除效率,是否比ArrayList高了呢?LinkedList的remove(index)方法实现如下:
 
复制代码
/**
     * Removes the object at the specified location from this {@code LinkedList}.
     *
     * @param location
     *            the index of the object to remove
     * @return the removed object
     * @throws IndexOutOfBoundsException
     *             if {@code location < 0 || >= size()}
     */
    @Override
    public E remove(int location) {
        if (0 <= location && location < size) {
            Link<E> link = voidLink;
            if (location < (size / 2)) {
                for (int i = 0; i <= location; i++) {
                    link = link.next;
                }
            } else {
                for (int i = size; i > location; i--) {
                    link = link.previous;
                }
            }
            Link<E> previous = link.previous;
            Link<E> next = link.next;
            previous.next = next;
            next.previous = previous;
            size--;
            modCount++;
            return link.data;
        }
        throw new IndexOutOfBoundsException();
    }
复制代码
  LinkedList的删除操作很简单,只需要修改指定index对象其前后对象的引用即可,但是在指针移动到指定index之前,需要移动1/2个列表长度,效率并非最高,能否将移动的操作也简化掉呢?既然是已排好序的列表,每次删除都删除列表末尾的对象,那我们可以使用LinkedList提供的removeLast()方法,代码如下:
 
复制代码
List<Item> rankItems = new LinkedList<Item>();
// 生成数据+排序
...
while (rankItems.size() > 5000) {
    rankItems.removeLast();
}
复制代码
  分析removeLast()的效率,LinkedList的removeLast()方法实现如下:
 
复制代码
/**
     * Removes the last object from this {@code LinkedList}.
     *
     * @return the removed object.
     * @throws NoSuchElementException
     *             if this {@code LinkedList} is empty.
     */
    public E removeLast() {
        Link<E> last = voidLink.previous;
        if (last != voidLink) {
            Link<E> previous = last.previous;
            voidLink.previous = previous;
            previous.next = voidLink;
            size--;
            modCount++;
            return last.data;
        }
        throw new NoSuchElementException();
    }
复制代码
  LinkedList的removeLast()方法没有移动指针的操作,只需要借助于列表尾的voidLink,即可完成对列表尾部对象的删除,效率上较高。
目录
相关文章
|
机器学习/深度学习 存储 运维
探索编程世界的宝藏:程序员必掌握的20大算法(中)
探索编程世界的宝藏:程序员必掌握的20大算法
160 0
|
搜索推荐 算法 程序员
探索编程世界的宝藏:程序员必掌握的20大算法(上)
探索编程世界的宝藏:程序员必掌握的20大算法
152 0
|
存储 机器学习/深度学习 自然语言处理
探索编程世界的宝藏:程序员必掌握的20大算法(下)
探索编程世界的宝藏:程序员必掌握的20大算法
141 0
|
算法
谈一谈|编程中的数学思维
谈一谈|编程中的数学思维
146 0
|
算法
解决这三个误区,才能真正学好算法
记录一下最近学习算法的一些思考
98 0
|
Java 程序员 iOS开发
非典型程序员的办公桌
非典型程序员的办公桌
324 0
非典型程序员的办公桌
|
设计模式 网络协议 算法
自学编程的八大误区!克服它们,豁然开朗!
说在前面 小伙伴们大家好,又是全新的一天。 关于“自学编程的一些常见误区”这个话题其实很早之前就在视频里聊过了。时间过去了大半年,也还是有很多小伙伴会提及各种自学过程中的常见疑惑,所以还是用文字总结一下这几点想法,和大家共勉。 误区1:忽略基础,盲目莽进 基础知识和基础路线真的非常重要,就以Java领域举例,现在的应用框架实在是太多了,五花八门,层出不穷,迭代的速度太快了。但是假如Java SE的基础不牢、网络协议和操作系统不熟,基本的设计模式不了解,那一味地追求学习新框架反而会让自己陷入迷茫与困顿。 基础牢固,应用框架的学习自然就不用惧怕了,很快就能切入核心,掌握原理。而且越时髦的东西
135 0
|
前端开发 数据可视化 JavaScript
汤尧:走最难的路,看最好的风景
成长一种修炼,借事修人,从项目中探索成长之路,走最难的路,看最好的风景。
汤尧:走最难的路,看最好的风景

相关实验场景

更多