首页 > 其他分享 >【数据结构】时间、空间复杂度详解

【数据结构】时间、空间复杂度详解

时间:2024-10-16 16:20:00浏览次数:7  
标签:arr int 复杂度 length 详解 时间 数据结构 public

大家有没有遇到过,为什么有些程序跑得飞快,而有些程序却慢得让人抓狂?我们可能都是这样认为的:他写的程序效率高等等,确实如此。但这背后隐藏着两个重要的概念:时间复杂度空间复杂度。它们就像程序的“效率指标”,帮助我们评估程序的性能。

一、时间复杂度:衡量速度的尺子

简单来说,时间复杂度描述的是程序运行时间随输入规模变化的趋势。

假设,你今天要去图书馆看书,这个图书馆超级大,你开始寻找:

  • 情况一: 你知道书名,直接在书架上找到它。无论书架上有多少本书,你只需要花费固定时间。这种情况下,时间复杂度是常数级别,记作 O(1)。例如,以下Java代码展示了访问数组第一个元素的操作,无论数组长度如何,其时间复杂度始终为O(1):

public int getFirstElement(int[] arr) {
  return arr[0]; 
}

对应函数图像:

  • 情况二: 你只知道书的主题,需要逐本翻阅。如果书架上有10本书,你可能需要翻阅10次;如果书架上有100本书,你可能需要翻阅100次。在这种情况下,时间复杂度是线性级别,记作 O(n),其中 n 代表书的数量。例如,以下代码展示了查找数组最大值的例子,需要遍历数组一次,时间复杂度为O(n):

public int findMax(int[] arr) {
  int max = arr[0];
  for (int i = 1; i < arr.length; i++) {
    if (arr[i] > max) {
      max = arr[i];
    }
  }
  return max;
}

对应函数图像:

  • 情况三: 你需要将所有书按照作者排序,然后找到对应作者的书。排序需要比较和移动书,时间会随着书的数量增加而显著增长。这种情况下,时间复杂度可能为平方级别,记作 O(n^2)。例如,经典的冒泡排序算法就展现了 O(n^2) 的时间复杂度:

public void bubbleSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
    for (int j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
}

除了上述例子,还有其他常见的时间复杂度级别:

  • O(log n): 对数级别,时间复杂度随输入规模缓慢增长,例如二分查找算法:

public int binarySearch(int[] arr, int target) {
  int left = 0;
  int right = arr.length - 1;
  while (left <= right) {
    int mid = left + (right - left) / 2;
    if (arr[mid] == target) {
      return mid;
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }
  return -1; 
}

对应函数图像:

  • O(n log n): 线性对数级别,常见于高效的排序算法,例如归并排序算法:

public void mergeSort(int[] arr) {
  if (arr.length <= 1) {
    return;
  }
  int mid = arr.length / 2;
  int[] left = Arrays.copyOfRange(arr, 0, mid);
  int[] right = Arrays.copyOfRange(arr, mid, arr.length);
  mergeSort(left);
  mergeSort(right);
  merge(arr, left, right);
}

private void merge(int[] arr, int[] left, int[] right) {
  int i = 0, j = 0, k = 0;
  while (i < left.length && j < right.length) {
    if (left[i] <= right[j]) {
      arr[k++] = left[i++];
    } else {
      arr[k++] = right[j++];
    }
  }
  while (i < left.length) {
    arr[k++] = left[i++];
  }
  while (j < right.length) {
    arr[k++] = right[j++];
  }
}

对应函数图像:

  • O(2^n): 指数级别,时间复杂度随输入规模指数增长,非常耗时。例如,递归计算斐波那契数列的算法:

public int fibonacci(int n) {
  if (n <= 1) {
    return n;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

对应函数图像:

二、空间复杂度:衡量内存的消耗

空间复杂度描述的是程序运行过程中所需的内存空间随输入规模变化的趋势。

例如:

  • 情况一: 你只需要存储数字的总和,只需要一个变量来存储这个值。这种情况下,空间复杂度是常数级别,记作 O(1)。 例如,以下代码计算两个数的和,只使用了常数个变量,空间复杂度为O(1):

public int sum(int a, int b) {
  return a + b; 
}

  • 情况二: 你需要存储所有数字,需要一个数组来存放它们。如果数字的数量为 n,则空间复杂度是线性级别,记作 O(n)。例如,以下代码复制一个数组,需要创建一个和原数组大小相同的数组,空间复杂度为O(n):

public int[] copyArray(int[] arr) {
  int[] newArr = new int[arr.length];
  for (int i = 0; i < arr.length; i++) {
    newArr[i] = arr[i];
  }
  return newArr;
}

同样,空间复杂度也有对数级别 O(log n),例如以下递归函数,每次递归调用都将问题规模缩小一半,栈空间的消耗呈对数增长:

public void recursiveFunction(int n) {
  if (n <= 1) {
    return;
  }
  recursiveFunction(n / 2); 
}

三、总结

时间复杂度和空间复杂度是评估程序性能的重要指标。

  • 时间复杂度关注程序运行时间,空间复杂度关注程序内存消耗。

  • 选择合适的算法,可以有效降低时间复杂度和空间复杂度,提高程序效率。犹如鱼与熊掌,二者不可兼得。

希望这篇文章能够帮助各位看官更好地理解时间复杂度和空间复杂度,让你在编写代码时更加得心应手!感谢各位看官的观看,下期见,谢谢~

标签:arr,int,复杂度,length,详解,时间,数据结构,public
From: https://blog.csdn.net/weixin_64178283/article/details/142983543

相关文章

  • (接上篇问题回答)OWASP Top 10 漏洞详解:基础知识、面试常问问题与实际应用
    1.SQL注入面试常见问题什么是SQL注入? SQL注入是一种网络安全漏洞,攻击者通过向SQL查询插入恶意代码,来干扰应用程序的数据库查询,导致未授权的数据访问或数据操纵。如何防止SQL注入? 防止SQL注入的方法包括:使用预编译的SQL语句(PreparedStatements)。使用ORM工具。严格验证和......
  • 【数据结构】自己动手写一个C++链表功能
    链表数据结构在操作数据时具有更高的性能,但同时因为其结构的原因会造成时间复杂度为O(N),因此理解链表结构的底层实现能够让我们在开发中对程序的性能进行进一步优化。如果你不知道什么是链表或者时间复杂度,可以参考我另外两篇文章:【数据结构】数组、链表、堆栈、队列到......
  • [整理]C#反射(Reflection)详解
    [整理]C#反射(Reflection)详解本人理解:装配件:Assembly(程序集)晚绑定:后期绑定MSDN:反射(C#编程指南)-----------------原文如下--------1、什么是反射2、命名空间与装配件的关系3、运行期得到类型信息有什么用4、如何使用反射获取类型5、如何根据类型来动态创建对象6、......
  • 前端新手教程:HTML、CSS 和 JavaScript 全面详解及实用案例
    一、引言在当今数字化的时代,前端开发扮演着至关重要的角色,它决定了用户与网页和应用程序交互的体验。HTML、CSS和JavaScript作为前端开发的核心技术,分别负责网页的结构、样式和交互。本教程将为前端新手全面深入地介绍HTML、CSS和JavaScript的知识点,并通过实用案例帮助......
  • Nuxt.js 应用中的 modules:done 事件钩子详解
    title:Nuxt.js应用中的modules:done事件钩子详解date:2024/10/16updated:2024/10/16author:cmdragonexcerpt:modules:done是Nuxt.js中一个重要的生命周期钩子,在Nuxt应用初始化期间触发。该钩子允许开发者在用户定义的模块安装完成后执行特定操作,如初始化后续配......
  • 《纪元1800》遭遇dll丢失问题无法启动:msvcr71.dll丢失详解与定制化解决方案
    《纪元1800》是一款非常受欢迎的城市建设和经济策略游戏,但有时玩家可能会遇到msvcr71.dll丢失的问题,导致游戏无法启动。msvcr71.dll是MicrosoftVisualC++运行库的一部分,负责支持许多应用程序的运行。以下是对msvcr71.dll丢失问题的详细解释及定制化解决方案。问题原......
  • 数据结构--顺序表
    简介:这是顺序表的数据结构以C/C++语言实现,编译器为VS2022,如有不对的地方欢迎大家在评论区里讨论在其中我们要用到如下头文件:#include"stdio.h"#include"stdlib.h"简单宏定义一些类型,宏定义的内容可以根据自身需求进行更换:#defineMaxsize50 //静态顺序表的最大长度#def......
  • Exchange2016服务详解
    Exchange2016服务详解 服务作用问题现象MicrosoftExchangeActiveDirectory拓扑实现AD身份验证用户Outlook邮箱可能需要多次输入密码                                ......
  • G-数据结构-G
    \[\huge近日多做数据结构题,或恐后再读不能醒悟,或记其思路,或骂出题人,或不想刷题,虽有此篇。\]\[\]\[\]\[\]\[\]T1距离首先这题部分分很多,直接$O(n^2)$枚举点对,在树上差分即可获得70分。那么正解几乎和部分分就没什么关系了。首先看到\[ans_u=\sum_{x∈subtree_......
  • 神经网络之卷积篇:详解残差网络为什么有用?(Why ResNets work?)
    详解残差网络为什么有用?为什么ResNets能有如此好的表现,来看个例子,它解释了其中的原因,至少可以说明,如何构建更深层次的ResNets网络的同时还不降低它们在训练集上的效率。通常来讲,网络在训练集上表现好,才能在Hold-Out交叉验证集或dev集和测试集上有好的表现,所以至少在训练集上训练......