数据结构_时间复杂度

ops/2024/9/24 10:19:19/

✨✨所属专栏:数据结构✨✨

✨✨作者主页:嶔某✨✨

什么是时间复杂度?

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

如何计算时间复杂度?

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。

void func1(int n)
{int count = 0;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){count++;}}for (int k = 0; k < 2*n; k++){count++;}int x = 10;while (x--){count++;}printf("%d\n",count);
}

在func1中count++执行了多少次?

答:F(n)= n^2 + 2*n +10

 在上面的问题中:

NF(N)
10130
10010210
10001002010

我们发现,当n越来越大,对最终结果最具有影响的项为:N^2(最高阶项)

有的同学会问:那如果n等于一个很小的数呢?(比如1,2,3……)

答:随着计算机的发展,由于计算机速度很快,当n很小的时候计算时间还不到1ms,可以忽略不计了。

 我们看下面的结果:(时间单位都为ms)

 所以我们在计算时间复杂读度的时候,只保留对结果影响最大的一项。

具体计算方法看下面的大O渐近表示法。

 大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

使用大O的渐进表示法以后,Func1的时间复杂度为:O(n)

 通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

另外有些算法的时间复杂度存在最好、平均和最坏情况:

最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)

例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到

在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

计算冒泡排序的时间复杂度

void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i-1] > a[i]){Swap(&a[i-1], &a[i]);//两数交换exchange = 1;}}    if (exchange == 0)break;}
}

基本操作执行最好情况N次,最坏执行了(N*(N+1)/2次,通过推导大O阶方法+时间复杂度一般看最
坏,时间复杂度为 O(N^2)

注意:最坏情况展开是:(n^2)/2 + n/2 我们选最高次项(n^2)/2,这里前面的因数1/2直接舍去(对结果影响不大)

计算二分查找的时间复杂度 

int BinarySearch(int* a, int n, int x)
{assert(a);int begin = 0;int end = n-1;// [begin, end]:begin和end是左闭右闭区间,因此有=号while (begin <= end){int mid = begin + ((end-begin)>>1);if (a[mid] < x)begin = mid+1;else if (a[mid] > x)end = mid-1;elsereturn mid;}return -1;
}

基本操作执行最好1次(中间数即为要查找的数),最坏O(logN)次(直到最后一次查找才查找出来),时间复杂度为 O(logN)。(logN在算法分析中表示是底数为2)

为什么最坏是log(n)次?

答:假设最坏查找x次,一共N个数,每次查找都要除去1/2的数,最后仅剩一个数,就有N((1/2)^x )= 1。化简取对数得x = log(N).

计算阶乘递归Fac的时间复杂度

long long Fac(size_t N)
{if(0 == N)return 1;return Fac(N-1)*N;
}

 基本操作递归执行了N次(每一次调用函数都需要前一个函数的基础,直到调用到fac(1)停止),时间复杂度为O(N)

计算斐波那契递归Fib的时间复杂度

long long Fib(size_t N)
{if(N < 3)return 1;return Fib(N-1) + Fib(N-2);
}

基本操作递归执行了N^2次(每一次调用都需要前面两个函数的值为基础,类似于杨辉三角)时间复杂度为O(N^2)

本期博客到这里就结束了,如果有什么错误,欢迎指出,如果对你有帮助,请点个赞,谢谢!


http://www.ppmy.cn/ops/7123.html

相关文章

使用python-can和cantools实现arxml报文解析、发送和接收的完整指南

文章目录 背景一、硬件支持二、环境准备1、python解释器安装2、python库安装 三、 收发案例四、 方法拓展1、canoe硬件调用2、回调函数介绍 结论 背景 在汽车行业中&#xff0c;CAN (Controller Area Network) 总线是用于车辆内部通信的关键技术。arxml文件是一种用于描述CAN消…

掌握ChatGPT写作技巧

ChatGPT无限次数:点击直达 掌握ChatGPT写作技巧 ChatGPT是一种基于大规模预训练模型的自然语言处理工具&#xff0c;能够模拟人类的对话风格&#xff0c;帮助用户生成高质量的文章、对话和文字内容。掌握ChatGPT的写作技巧对于提升文章质量和效率具有重要意义。本文将介绍如何…

Kafka分布式数据处理平台

目录 一.消息队列基本介绍 1.为什么需要消息队列 2.使用消息队列的好处 2.1 解耦 耦合&#xff08;非解耦&#xff09; 解耦 2.2 可恢复性 2.3 缓冲 2.4 灵活性 & 峰值处理能力 2.5 异步通信 3.消息队列的两种模式 3.1 点对点模式 3.2 发布/订阅模式 二.Kafk…

常用node.js命令有哪些呢?

前言 Node.js 是一种在服务器端运行 JavaScript 的开放源代码、跨平台 JavaScript 运行环境。 1、查看当前安装的 Node.js 版本。 node -v 或 node --version 2、查看当前安装的 npm 版本。 npm -v 或 npm --version 3、初始化一个新的 Node.js 项目&#xff0c;会生成一个 pac…

NTLM认证

文章目录 1.概念(1) 本地认证(2) SAM(3) NTLM Hash(4) NTLM 和 NTLM Hash(5) NTLM v2 1.概念 (1) 本地认证 Windows不存储用户的明文密码&#xff0c;它会将用户的明文密码经过加密后存储在 SAM (Security Account Manager Database&#xff0c;安全账号管理数据库)中。 (2)…

MATLAB使用速成 第一章(MATLAB入门)

一、MATLAB的命令窗口 1、窗口概览 2、一些基本使用 &#xff08;1&#xff09;在输入一条命令&#xff08;或者说表达式&#xff09;并按下回车后&#xff0c;窗口往往会输出操作结果&#xff08;这不是必然的&#xff0c;有些命令&#xff0c;比如clc&#xff0c;它并不会输…

用pigeon kotlin swift写一个自己的插件

文章目录 1. 创建一个flutter plugin项目2. 引入依赖3. 创建pigeons文件夹和message.dart4. 执行生成各个平台文件的命令5. base_plugin.dart6. BasePlugin.kt7. BasePlugin.swift8. 遇到的问题9. [源码](https://github.com/githubityu/base_plugin) 1. 创建一个flutter plugi…

常见算法(二分,分块查找,插入,快速排序)

常见算法 1. 顺序查找 package com.mohuanan.exercise;import java.util.ArrayList;public class BasicFind01 {public static void main(String[] args) {int[] arr {1, 2, 3, 1, 2, 3, 4, 5, 6};int number 2;ArrayList<Integer> indexList findIndex(arr, number…