JAVA----数据结构与算法

本文深入探讨了算法的时间复杂度,通过大O表示法分析了斐波纳契数列的递归、循环等实现方式的时间复杂度,指出递归法在大数据规模下效率低下。同时,介绍了动态数组的数据结构,包括接口设计、添加、删除元素的实现,并讨论了扩容策略。文章强调了算法优化的方向——空间与时间的权衡,并提出了根据实际需求调整优化策略的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、算法

1)算法是用于解决特定问题的一系列的执行步骤
2)使用不同算法,解决同一个问题,效率可能相差非常大
3)一般从以下维度来评估算法的优劣

  • 正确性、可读性、健壮性(对不合理输入的反应能力和处理能力)
  • 时间复杂度(time complexity):估算程序指令的执行次数(执行时间)
  • 空间复杂度(space complexity):估算所需占用的存储空间

1.1 时间复杂度

  • 大O表示法:描述复杂度,表示的是数据规模n对应的复杂度;仅仅是一种粗略的分析模型,是一种估算,能简单了解一个算法的执行效率
  • 忽略常数、系数、低阶、对数阶一般省略底数
  • 常数 >> O(1);
  • 2n + 3 >> O(n);
  • n^2 + 2n + 6 >> O(n^2);
  • 4n^3 + 3n^2 + 22n + 100 >> O(n^3)
  • log2(n)、log9(n)>> O(logn)

在这里插入图片描述

  • 常见的时间复杂度
    在这里插入图片描述
    在这里插入图片描述
  • 时间工具类----TimeTool
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeTool {
	private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS");

	public interface Task {
		void execute();
	}

	public static void check(String title, Task task) {
		if (task == null)
			return;
		title = (title == null) ? "" : ("【" + title + "】");
		System.out.println(title);
		System.out.println("开始:" + fmt.format(new Date()));
		long begin = System.currentTimeMillis();
		task.execute();
		long end = System.currentTimeMillis();
		System.out.println("结束:" + fmt.format(new Date()));
		double delta = (end - begin) / 1000.0;
		System.out.println("耗时:" + delta + "秒");
		System.out.println("--------------------------------");
	}
}
  • 求第n个斐波纳契数(fibonacci number)
public class Test {
	/**
	 * 斐波纳契数列: 
	 * 				0 1 1 2 3 5 8 13 ... 
	 * 索引: 
	 * 				0 1 2 3 4 5 6  7 ...
	 */

	// 方法一:递归法
	// 时间复杂度 O(2^n)
	public static int fib1(int n) {
		if (n <= 1)
			return n;
		return fib1(n - 1) + fib1(n - 2);
	}

	// 方法二
	// 时间复杂度 O(n)
	public static int fib2(int n) {
		if (n <= 1)
			return n;

		int first = 0;
		int second = 1;
		for (int i = 0; i < n - 1; i++) {
			int sum = first + second;
			first = second;
			second = sum;
		}
		return second;
	}

	// 方法三
	// 时间复杂度 O(n)
	public static int fib3(int n) {
		if (n <= 1)
			return n;

		int first = 0;
		int second = 1;
		while (n-- > 1) {
			second += first;
			first = second - first;
		}
		return second;
	}

	public static void main(String[] args) {
		// 递归法:存在性能问题,随着n的增大,效率会受影响
		TimeTool.check("fib1", new Task() {

			@Override
			public void execute() {
				System.out.println(fib1(30));
			}

		});

		// 方法二的效率明显比递归法高
		TimeTool.check("fib2", new Task() {

			@Override
			public void execute() {
				System.out.println(fib2(30));
			}

		});

		// 方法三的在变量的使用数量要比方法二少
		TimeTool.check("fib3", new Task() {

			@Override
			public void execute() {
				System.out.println(fib3(30));
			}

		});
	}
}

在这里插入图片描述

  • 斐波纳契数使用递归法的时间复杂度

1)以 fib(5) 为例分析

  • 发现函数有重复调用

在这里插入图片描述
在这里插入图片描述

2)时间复杂度:O(n^2)
在这里插入图片描述

1.2 算法的优化方向

  • 用尽量少的存储空间
  • 用尽量少的执行步骤(执行时间)
  • 根据情况,可以
    1)空间换时间
    2)时间换空间

1.3 多个数据规模的情况

在这里插入图片描述

2. 数据结构

  • 数据结构是计算机存储、组织数据的方式

在这里插入图片描述

2.1 线性表

在这里插入图片描述

2.1.1 数组----Array

在这里插入图片描述

2.1.2 动态数组----Dynamin Array

在这里插入图片描述

2.1.2.1 接口设计

在这里插入图片描述

2.1.2.2 动态数组的设计
2.1.2.2.1 添加元素 ---- add(E element)

在这里插入图片描述

2.1.2.2.2 添加元素 ---- add(int index, E element)

在这里插入图片描述
在这里插入图片描述

2.1.2.2.3 删除元素 ---- remove(int index)

在这里插入图片描述
在这里插入图片描述

2.1.2.2.4 如何扩容
  • 数组扩容,如果用new的方式创建出的数组,地址不可能连续,因此常用做法是申请更大的数组
    在这里插入图片描述
2.1.2.2.5 对象数组

在这里插入图片描述

  • clear()
  • 1)如果基本类型数据,clear()清除元素,只需size=0即可,主要是控制访问和操作数据
  • 2)如果是引用类型,clear()清除元素,①、size=0,对空间中的对象依然存在,这样做会造成内存的浪费,②、elements[i] = null,数组中对象就会被回收。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值