说说你不知道的时间复杂度

简介: 说说你不知道的时间复杂度

一、为什么要学习数据结构和算法



其实,以前我们都会说,学习数据结构有多么多么的重要,长篇大论。这次,我们java程序员来看看数据结构和算法重要性。


例题:判断一个数是否是2的n次方。比如:2,4,8,16是2的n次方;6,10不是。


拿到这道题,用java的思路分析


2:2

4:2*2

8:2 * 2 * 2

16:2 * 2 * 2 * 2

如果一个数除以2,最后余数是0,那么这个数就是2的n次方;如果余数是1,那么就不是。代码实现如下:


public static void main(String[] args) {
        // 随意给一个数,判断这个数是不是2的n次方
        int n = 16;
        int yuShu = n%2;
        int chuShu = n/2;
        while (chuShu > 1) {
            yuShu = chuShu % 2;
            chuShu = chuShu / 2;
        }
        System.out.println( n + " 这个数" + (yuShu == 0?"是":"不是")+"2的n次方");
    }

但是,如果使用数据结构呢?下面来分析一下:将所有的十进制数字都转成2进制


2:10

4:100

8:1000

16:10000

他们的特点是什么呢?第一个数字是1,其余的都是0

而这几个数字之前的一个数字是什么呢?

1:01

3:011

7:0111

15:01111

他们的特点是什么呢?第一个是0,其余的都是1.

利用这两组数字,我们找规律,如果i和i-1按位&与的结果是0,就说明这个i是2的n次方;否则就不是

2 & 1 = 0

4 & 3 = 0

8 & 7 = 0

16 & 15 = 0

但是15 & 14呢,14的二进制数是01110,01111 & 01110 = 00001

所以,通过对数据的分析,我们可以用一句代码判断


if(n & (n=1) == 0) {
  // 这个数就是2的n次方
} else {
  // 否则不是
}

二、数据结构概述


数据结构包括:线性结构和非线性结构


1、线性结构


1)线性结构是最常用的数据结构,其特点是数据元素之间存在一对一的线性关系。

2)线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构。顺序存储的线性表成为顺序表,顺序表中的存储元素是连续的


3)链式存储的线性表成为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息。


4)线性结构常见的有:数组、队列、链表和栈,后面我们会详细讲解


2、非线性结构


非线性结构包括:二维数组、多维数组、广义表、树结构、图结构


三、算法



算法有五个特征:有穷性,确定性,可行性,有输入,有输出

正确性,可读性,健壮性,bug(写出的代码bug少,而且系统稳定)

高效率与低存储:内存+CPU 堆栈内存 OOM


内存占用最小,CPU占用最小,运算速度最快。


评价算法的两个重要指标:时间复杂度 和 空间复杂度

时间复杂度:运行一个程序所花费的时间。

空间复杂度:运行程序所需要的内存。


1、 时间复杂度


1) 计算时间复杂度的意义:分析接口的性能


2) 时间复杂度表示方法:大写的O(n)表示,全称是O(nlogn)

3)常见的时间复杂度


计算时间复杂度,通常是计算比较大的,而且是不确定的的数。如果是已经确定的,那么就不用计算了,常量就是我们说的不用计算的一种。

> 常数:O(1) 1表示的是常数。不是循环的次数


比如下面的这个循环,时间复杂度是O(1)

public class BigO {
    public static void main(String[] args) {
        int n = 0; // 这句话的时间复杂度是O(1)
        for (int i = 0; i < 3; i++) {  // 这句话会执行4次, 它的时间复杂度也是O(1)
            n = n + 1;  // 这句话会执行3次, 他的时间复杂度也是O(1)
        }
    }
}

> 对数:O(logn) 或 O(nlogn)


那么什么情况下会使用时间复杂度是对数的这种情况呢?来看一下下面的代码:

public static void time_log() {
        int a = Integer.MAX_VALUE;
        int i = 1;
        while (i <= a) {
            i = i * 2;  // 这个循环一共要循环多少次呢?
            // 我们来看看i的值2,4,8,16,32,64,128    2^0,2^1,2^2,2^3,2^4,2^5 ====> 2(n) = a ===> n = log2a
        }
    }

这里i = i * 2 这句话需要循环多少次呢?其实我们要求的就是:循环多少次,i<= a 呢?2^n = a ; 求n=log2a, log以2为底a的对数。


以上是O(logn)的情况,那么什么情况下使用O(nlogn)呢?看下面的代码:


public static void time_nlogn() {
        int a = Integer.MAX_VALUE;
        int i = 1;
        for (int j = 0; j < 10; j++) {
            while (i <= a) {
                i = i * 2;  // 这个循环一共要循环多少次呢?
                // 我们来看看i的值2,4,8,16,32,64,128    2(1),2(2),2(3),2(4),2(5)  2(n) = a ===> n = log2a
                // 外面还有个j,所以就是(j * log2a)次
            }
        }  
    }

只有while循环的时候,需要执行log2a次。那么外面多了一层for循环,这次要循环多少次呢?(j * log2a)次


> 线性:O(n)


线性指的就是O(n),也就是运行n次。

public static void time_on() {
        int n = Integer.MAX_VALUE;
        int a = 0;
        for (int i = 0; i < n; i++) {
            a = a + 1; // 这句话的时间复杂度是什么? O(n) n是几就运行几次. n是未知的,不确定的.如果n是确定的,就是常量了. 时间复杂度就是O(1)
        }
    }

这里面a = a + 1;这句话会运行多少次呢?他和n有关系,如果n是10就运行10次,n是100就运行100次。有n决定,所以时间复杂度是O(n);


注意:这里的n是不确定的。如果n是确定的,那么时间复杂度就是O(1)le

> 线性对数:O(nlogn)


这个在上面已经说过了


> 平方:O(n ^ 2)


/**
     * 时间复杂度O(n^2)
     */
    public static void time_Onn() {
        int n = Integer.MAX_VALUE;
        int a = 0;
        for(int i = 0; i < n; i++) {
            for (int j = 0; j< n; j++) {
                a = a + 1; // 这句话执行多少次呢?也就是说它的时间复杂度是多少呢? 外层循环执行n次,内层循环也是n次,所以最终执行n*n次,所以时间复杂度是O(n^2)
            }
        }
    }

这里有两层循环,外层循环执行n次,内存循环也是n次,所以代码a = a + 1;执行O(n*n)次。

常见的O(n^2)还有冒泡排序

public static void time_Onn2() {
        int[] num = {3,6,1,0,8,5};
        int n = num.length;
        int a = 0;
        for(int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                a = a + 1; // 这句话执行多少次呢?也就是说它的时间复杂度是多少呢? 来找找它的规律
                /*
                 * 外层循环i=n, 内层代码执行1次
                 * 外层循环i=n-1,内层代码执行2次
                 * 外层循环i=n-2,内层代码执行3次
                 * 外层循环i=n-3,内层代码执行4次
                 * 外层循环i=1,内层代码执行n次
                 * 
                 * 一共执行多少次呢? 0+1+2+3+......+n = n * (n+1)/2次
                 * 也就是冒泡算法的时间复杂度是O(n*(n+1)/2)次
                 */
            }
        }
    }

冒泡排序的时间复杂度是多少呢?我们来分析一下:


外层循环i=n, 内层代码执行1次

外层循环i=n-1,内层代码执行2次

外层循环i=n-2,内层代码执行3次

外层循环i=n-3,内层代码执行4次

外层循环i=1,内层代码执行n次

一共执行多少次呢? 0+1+2+3+......+n = n * (n+1)/2次

也就是冒泡算法的时间复杂度是O(n*(n+1)/2)次。

在计算时间复杂度的时候去掉常数,所以就是O(n^2)


> N次方:


如果是三层循环,四层循环呢?那就是 n * n * n * n=n^4

上面的冒泡算法会执行n*(n+1)/2 = (n^2 + n)/2 ===>当有加减法的时候,这个时间复杂度怎么计算呢?

取最大的就可以,这个最大是:首先去掉常数后,n2比n的阶层高,所以最后是O(n2)

4) 怎么计算时间复杂度?


第一步:找有循环的地方

第二步:找有网络请求的地方,包括RPC协议请求,数据库请求


网络请求可以通过打印日志来计算时间。


5) 常见时间复杂度的运行效率


O(1) > O(logn) > O(n) > O(nlogn) > O(n^2) > O(n^x)

O(1)的运行效率是最高的。

所以,我们在优化的时候,目标是将所有的时间复杂度往O(1)进行优化。

实际上,O(1) > O(logn) > O(n) > O(nlogn) 效果都是很好的,几乎优化的空间不是很大。我们的最终目标就是将O(n^2) 和 O(n^x)往前优化。

  • 案例1:

再来看看最开始的这个案例:判断一个数是否是2的n次方。比如:2,4,8,16是2的n次方;6,10不是。

如果一个数除以2,最后余数是0,那么这个数就是2的n次方;如果余数是1,那么就不是。代码实现如下:


public static void main(String[] args) {
        // 随意给一个数,判断这个数是不是2的n次方
        int n = 16;
        int yuShu = n%2;
        int chuShu = n/2;
        while (chuShu > 1) {
            yuShu = chuShu % 2;
            chuShu = chuShu / 2;
        }
        System.out.println( n + " 这个数" + (yuShu == 0?"是":"不是")+"2的n次方");
    }

那么这段代码的时间复杂度是多少呢?log2n:log以2位底n的对数。O(logn)

后来通过二进制代码进行优化,优化后的结果是


if(n & (n=1) == 0) {
  // 这个数就是2的n次方
} else {
  // 否则不是
}

这段代码的时间复杂度是O(1)。


我们优化以后,将O(logn)优化为O(1)了,效率大大提高了

  • 案例2


比如,我们在看一段代码的时候,发现有性能瓶颈,然后这段代码使用的排序方式是冒泡排序,如何对这个排序进行优化呢?


找更优秀的替代排序方法,快速排序,归并排序,堆排序等。


2、空间复杂度


1)空间复杂度分析的意义


找出哪些地方花费内存多,哪些数据占用的内存开销大


2)如何找出程序的空间复杂度?


开空间的地方,比如:数组,链表,缓存Map,Set,队列Queue,递归等

数据结构和算法书籍推荐

1187916-20220124112318968-1864447974.png

相关文章
|
6天前
|
人工智能 自然语言处理 Shell
🦞 如何在 Moltbot 配置阿里云百炼 API
本教程指导用户在开源AI助手Clawdbot中集成阿里云百炼API,涵盖安装Clawdbot、获取百炼API Key、配置环境变量与模型参数、验证调用等完整流程,支持Qwen3-max thinking (Qwen3-Max-2026-01-23)/Qwen - Plus等主流模型,助力本地化智能自动化。
🦞 如何在 Moltbot 配置阿里云百炼 API
|
4天前
|
人工智能 JavaScript 应用服务中间件
零门槛部署本地AI助手:Windows系统Moltbot(Clawdbot)保姆级教程
Moltbot(原Clawdbot)是一款功能全面的智能体AI助手,不仅能通过聊天互动响应需求,还具备“动手”和“跑腿”能力——“手”可读写本地文件、执行代码、操控命令行,“脚”能联网搜索、访问网页并分析内容,“大脑”则可接入Qwen、OpenAI等云端API,或利用本地GPU运行模型。本教程专为Windows系统用户打造,从环境搭建到问题排查,详细拆解全流程,即使无技术基础也能顺利部署本地AI助理。
5665 13
|
2天前
|
人工智能 机器人 Linux
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
OpenClaw(原Clawdbot)是一款开源本地AI智能体,支持飞书等多平台对接。本教程手把手教你Linux下部署,实现数据私有、系统控制、网页浏览与代码编写,全程保姆级操作,240字内搞定专属AI助手搭建!
2791 7
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
|
4天前
|
人工智能 JavaScript API
零门槛部署本地 AI 助手:Clawdbot/Meltbot 部署深度保姆级教程
Clawdbot(Moltbot)是一款智能体AI助手,具备“手”(读写文件、执行代码)、“脚”(联网搜索、分析网页)和“脑”(接入Qwen/OpenAI等API或本地GPU模型)。本指南详解Windows下从Node.js环境搭建、一键安装到Token配置的全流程,助你快速部署本地AI助理。(239字)
3530 19
|
10天前
|
人工智能 API 开发者
Claude Code 国内保姆级使用指南:实测 GLM-4.7 与 Claude Opus 4.5 全方案解
Claude Code是Anthropic推出的编程AI代理工具。2026年国内开发者可通过配置`ANTHROPIC_BASE_URL`实现本地化接入:①极速平替——用Qwen Code v0.5.0或GLM-4.7,毫秒响应,适合日常编码;②满血原版——经灵芽API中转调用Claude Opus 4.5,胜任复杂架构与深度推理。
7015 11
|
2天前
|
存储 人工智能 机器人
OpenClaw是什么?阿里云OpenClaw(原Clawdbot/Moltbot)一键部署官方教程参考
OpenClaw是什么?OpenClaw(原Clawdbot/Moltbot)是一款实用的个人AI助理,能够24小时响应指令并执行任务,如处理文件、查询信息、自动化协同等。阿里云推出的OpenClaw一键部署方案,简化了复杂配置流程,用户无需专业技术储备,即可快速在轻量应用服务器上启用该服务,打造专属AI助理。本文将详细拆解部署全流程、进阶功能配置及常见问题解决方案,确保不改变原意且无营销表述。
2643 1
|
2天前
|
存储 安全 数据库
2026年使用Docker部署OpenClaw(原Clawdbot/Moltbot)完整步骤教程
OpenClaw(原Clawdbot/Moltbot)是一款开源的本地运行个人AI助手,支持WhatsApp、Telegram、Slack等十余种通信渠道,兼容macOS、iOS、Android系统,还可渲染实时Canvas界面。本文提供基于Docker Compose的生产级部署指南,涵盖环境准备、源码获取、配置、构建、启动及运维等关键环节,补充生产环境必需的安全配置、数据持久化、备份与监控建议,与官方配置无冲突,适用于希望通过Docker快速部署的用户。需说明的是,OpenClaw暂无官方预构建Docker镜像,需通过源码+Dockerfile本地构建,这也是官方推荐的最稳定部署方式。
1889 0
|
3天前
|
人工智能 JavaScript 安全
Clawdbot 对接飞书详细教程 手把手搭建你的专属 AI 助手
本教程手把手教你将 Moltbot(原 Clawdbot)部署在 Linux 服务器,并对接飞书打造专属 AI 助手:涵盖环境准备、Node.js/NVM 安装、Moltbot 快速安装(支持 Qwen 模型)、Web 管理面板配置及飞书应用创建、权限设置与事件回调对接,全程图文指引,安全可靠。
2227 3
Clawdbot 对接飞书详细教程 手把手搭建你的专属 AI 助手
|
5天前
|
人工智能 安全 Shell
在 Moltbot (Clawdbot) 里配置调用阿里云百炼 API 完整教程
Moltbot(原Clawdbot)是一款开源AI个人助手,支持通过自然语言控制设备、处理自动化任务,兼容Qwen、Claude、GPT等主流大语言模型。若需在Moltbot中调用阿里云百炼提供的模型能力(如通义千问3系列),需完成API配置、环境变量设置、配置文件编辑等步骤。本文将严格遵循原教程逻辑,用通俗易懂的语言拆解完整流程,涵盖前置条件、安装部署、API获取、配置验证等核心环节,确保不改变原意且无营销表述。
2133 6
|
5天前
|
机器人 API 数据安全/隐私保护
只需3步,无影云电脑一键部署Moltbot(Clawdbot)
本指南详解Moltbot(Clawdbot)部署全流程:一、购买无影云电脑Moltbot专属套餐(含2000核时);二、下载客户端并配置百炼API Key、钉钉APP KEY及QQ通道;三、验证钉钉/群聊交互。支持多端,7×24运行可关闭休眠。
3458 7