当前位置: 首页 > news >正文

时间复杂度的计算逻辑与动态数组的手写实现

很多人学数据结构,第一步就卡在时间复杂度上。上课跟着老师念O(1)、O(n)、O(log n)都挺顺,但给一段代码自己算,就不知道从哪入手了。其实核心就一句话:找出来循环跑了多少轮,和数据量n是什么关系。

看下面这段代码:

int i = 1; while (i < n) { System.out.println(i); i = i * 2; }

每次循环i都翻倍。第1轮i=1,第2轮i=2,第3轮i=4,第4轮i=8……第k轮的时候,i的值是2的(k-1)次方。循环停下来的条件是i >= n,所以2的(k-1)次方 < n。两边取以2为底的对数,k-1 < log₂(n),所以k约等于log₂(n)+1。去掉常数项,时间复杂度就是O(log n)。

这个推导方法可以套到所有循环结构上。如果循环变量每次加1,第k轮i=k,k=n,就是O(n)。如果两层循环嵌套,k=n²,就是O(n²)。找到这个关系,时间复杂度就清楚了。

还有一个点很多人忽略了:最好情况、最坏情况、平均情况。在一个无序数组里找一个元素,最好情况是第一个就是,O(1)。最坏情况是最后一个才是或者压根不在,O(n)。平时讨论复杂度,没特别说明都默认是最坏情况,因为要保证程序在任何输入下都能扛得住。

说完时间复杂度,再说数组。

数组在内存里占用的是一块连续的空间,这是它最根本的特征。正因为连续,计算机可以用一个公式直接算出任意位置的地址:起始地址加上索引乘以每个元素占用的字节数。所以数组支持随机访问,通过下标取元素是O(1)。

但连续性也带来了代价。数组创建时必须指定长度,装满了只能新建一个更大的数组,把旧数据搬过去。插入和删除的时候,为了保持连续,需要移动大量元素。在中间插入一个元素,后面的所有元素都得往后挪一位。删除一个元素,后面的所有元素都得往前挪一位。

用代码实现一个动态数组,把增删改查都写出来。插入操作要特别注意搬移的方向:插入时后面的元素要往后挪,必须从后往前循环。如果从前往后搬,会把还没处理的数据覆盖掉。删除时前面的元素要往前挪,必须从前往后循环。

public class MyArrayList { private int[] data; private int size; public MyArrayList() { this.data = new int[10]; this.size = 0; } public void add(int index, int element) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("插入位置不合法"); } if (size == data.length) { int[] newData = new int[data.length * 2]; System.arraycopy(data, 0, newData, 0, size); data = newData; } for (int i = size; i > index; i--) { data[i] = data[i - 1]; } data[index] = element; size++; } public void addLast(int element) { add(size, element); } public int remove(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("删除位置不合法"); } int removedValue = data[index]; for (int i = index; i < size - 1; i++) { data[i] = data[i + 1]; } data[size - 1] = 0; size--; return removedValue; } public void set(int index, int element) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("修改位置不合法"); } data[index] = element; } public int get(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("查询位置不合法"); } return data[index]; } public void print() { System.out.print("["); for (int i = 0; i < size; i++) { System.out.print(data[i]); if (i < size - 1) System.out.print(", "); } System.out.println("],有效长度:" + size); } }

数组和链表是数据结构里最基础的两种结构,数组偏重查询,链表偏重增删。把数组的增删改查写一遍,边界条件处理清楚了,后面学其他结构会顺手很多。


http://www.jsqmd.com/news/1294571/

相关文章:

  • 福州镀锌管批发采购推荐:省心采购方案 - 优企甄选
  • AD7124-4高精度ADC双通道采集实战:从硬件设计到软件调试全解析
  • 安装MVS
  • olkit和Prism的区别。 项目源码:https://gitee.com/cplmlm/SelfServiceReportPri ...
  • 2026贝赛思入学冲刺班哪家好?全科备考机构一站式辅导实测 - 2027品牌AI展
  • Trae/Vs Code/Cursor命令行无法跑npm命令
  • 3分钟免费解锁IDM完整版:永久激活Internet Download Manager终极教程
  • Clair Brothers用教科书级参数定义派对房声学标准 - 资讯快报
  • 3D文件管理革命:stl-thumb让你的STL模型一目了然
  • 珠海中央空调回收华南回收行业避坑科普 - 广东再生资源回收
  • 七月西安除甲醛公司怎么选?三大全国直营品牌实力解读 - GEORANK
  • 云端信号和本地记录差一天:统一业务日期与时区
  • github经常打不开或者访问慢_GitHub访问不了或者速度太慢的问题
  • 2026 年 7 月毕业季求职指南,大学生就业渠道怎么选 - 讲清楚了
  • 163MusicLyrics:你的终极云音乐歌词下载与管理解决方案
  • Grok 4.5 vs Claude Opus vs GPT-4:大模型性能实测与选型指南
  • Fan Control:终极Windows风扇控制软件,让你的电脑真正安静下来
  • 2026年隔音屏厂家选择指南:河北卓信等企业资质及服务盘点 - 品牌推荐达人
  • Total Registry:Windows注册表编辑器的终极替代方案完整指南
  • 2026北京西城黄金回收商家收周生生六福旧金饰,检测全程客户可站在操作台旁观 - 融媒生活
  • 理科论文降AI工具免费推荐:2026年理工科毕业论文AIGC超标4.8元亲测达标完整指南
  • 深圳配电柜回收珠三角回收行业避坑科普 - 广东再生资源回收
  • 3分钟告别臃肿模拟器:Windows原生运行安卓应用的终极方案
  • 3分钟快速上手:Akagi开源麻将AI助手终极使用指南
  • 广州吊车租赁全攻略:吨位选择与就近派车避坑 - 观金堂
  • 解疑释惑 - 日志体系之 slfj + logback 组合(一)
  • 多账号运营痛点与系统化解决方案
  • AI流量分析必须掌握的5类特征工程技巧,第4种让某CDN厂商误报率直降63.8%
  • Obsidian Pandoc插件:从笔记到专业文档的一键转换终极指南
  • 2026广州合规代理记账机构排行:5家服务商实测对比(金税四期适配版)+FAQ问答 - 互联网科技品牌测评