如何写出高性能代码(一)善用算法和数据结构

简介: 同一份逻辑,不同人的实现的代码性能会出现数量级的差异; 同一份代码,你可能微调几个字符或者某行代码的顺序,就会有数倍的性能提升;同一份代码,也可能在不同处理器上运行也会有几倍的性能差异;十倍程序员不是只存在于传说中,可能在我们的周围也比比皆是。十倍体现在程序员的方法面面,而代码性能却是其中最直观的一面。

  同一份逻辑,不同人的实现的代码性能会出现数量级的差异; 同一份代码,你可能微调几个字符或者某行代码的顺序,就会有数倍的性能提升;同一份代码,也可能在不同处理器上运行也会有几倍的性能差异;十倍程序员不是只存在于传说中,可能在我们的周围也比比皆是。十倍体现在程序员的方法面面,而代码性能却是其中最直观的一面。

  “如何写出高性能代码”系列源自我在组内做的一次分享,本系列将以我个人之前的经验为基础,尝试帮助大家写出更高性能的代码 。原ppt分享的面有宽也比较浅薄,所以这里将原ppt拆分成5个独立的部分,分别成文,也作为对原ppt的扩展和补充,本文是第一篇——善用算法和数据结构。

  荀子-劝学中说道:君子生非异也,善假于物也。其大意是君子的资质跟一般人没什么不同,只是善于借助外物罢了。 对于程序猿而已,我们在日常编码过程中,可能最常用的就是数据结构。现代各语言的开发库里基本上都封装好了各类的数据结构,我们基本不需要自己去实现。但错误地使用数据结构可能导致代码性能出现大幅的下降。

  这里我举三个Java中因未考虑到底层实现导致性能损耗的示例。

  上面这段代码本身功能上没有任何问题,但Java中ArrayList在添加过程中在容量不足时会触发扩容,扩容的过程会额外消耗CPU资源。但我在上述代码中指定了ArrayList的初始化容量为100后,用JMH压测发现有了33%的性能提升。

  在Java中,很多容器都有动态扩容的特性,而扩容的过程涉及到内存的拷贝,很消耗性能。 所以建议如果能预知到数据量大小,在容器初始化的时候给定一个初始容量。这点在现在很多公司的编码规范中也明确提出了,如下图来自阿里巴巴Java开发手册。

再来看一个错误使用LinkedList导致的性能问题。

复制

// jdk LinkedList中的get(int index)
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    Node<E> node(int index) {
        // assert isElementIndex(index);
        if (index < (size >> 1)) {
            Node<E> x = first;
            // 这里会从前到后遍历链表
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

  LinkedList并不受动态扩容的影响,但是它的底层实现是用的链表,而链表最大的问题在于不支持随机遍历,所以LinkedList中get(int index)的底层实现是用了遍历,时间复杂度是O(n),而ArrayList的底层实现是数组,它的get时间复杂度是O(1)。在上述代码中我将LinkedList改成ArrayList后压测确实也得到了十倍以上的性能提升。

  在Java中,Set和List都提供了contains()方法,其作用就是校验某个在是否存在于这个集合中,但其contains实现方法完全不一样。在HashSet中,contains直接是从hash表中查找,其时间复杂度只有O(1)。而在ArrayList和LinkedList中,都是需要遍历一次全量数据才能得出结果,时间复杂度是O(n),代码这里就不再赘述,具体可以自行查阅。

  在我实际测试是,Set和List的contains性能差异确实也非常明显。我用JMH测试发现,当有100个元素时,HashSet.contains的性能是ArrayList的10倍,是LinkedList的20倍,当数据量更大时,这个差异会更明显。

  以上3个错误的示例其实在我们日常代码中经常会遇到,或许你现在去翻阅下项目代码,很容易就能找到List和Set使用不当之处。 也许你会反驳,JDK中这些Api的性能都极高,而且这部分也只是业务逻辑中非常非常小的一部分,错误得使用可能只会导致整体百分之一甚至千分之一的差异,但是不积跬步无以至千里,不积小流无以成江河。

下图是各种常用数据结构各种操作的时间、空间复杂度供大家查阅:

  算法和数据结构是一个程序员的根基,虽然日常我们很少自己去实现某种具体的算法或数据结构,但我们却无时无刻不在使用各种已被封装好的算法或数据结构,我们应当做到对各种算法和数据结构烂熟于心,包括其时间复杂度、空间复杂度、适用范围。

如何写出高性能代码系列文章

目录
相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
68 1
|
2月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
160 4
|
11天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
34 2
|
27天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
57 20
|
2月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
2月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
2月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
131 23
|
1月前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
2月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
61 1
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
80 1

热门文章

最新文章