认=识=时=间=复=杂=度

评估算法优劣的核心指标是什么?

  • 时间复杂度(流程决定)
  • 额外空间复杂度(流程决定)
  • 常数项复杂度(实现细节决定)

时间复杂度

  • 常数时间操作
  • 确定算法流程的总操作数量与样本数量之间的表达式关系
  • 只看表达式最高的阶项的部分

常数时间操作

如果一个操作的具体时间不以一个,不以具体样本量为转移,每次执行时间都是固定时间。称这样的操作为常数时间操作。

  • 常见的算术运算(+、-、*、/、% 等)
  • 常见的位运算(>>、>>>、<<、|、&、^ 等)
    • >>:带符号右移。向右移动的时候,根据原本的正负,补位都用0或1
    • >>>:无符号右移。向右移动的时候,不管正负,只补0
  • 赋值、比较、自增、自减操作等
  • 数组寻址操作

总之,执行时间固定的操作都是常数时间操作。
反之,执行时间不固定的操还,都不是常数时间操作。

如何确定算法流程的总操作数量与样本数量之间的表达式关系?

  1. 想象该算法流程所处理的数据状况,要按照最差的情况来。
  2. 把整个流程彻底拆分为一个个基本动作,保证每个动作都是常数时间的操作。
  3. 如果数据量为N,看看基本动作的数量和N是什么关系。

如何确定算法流程的时间复杂度?

当完成了表达式的建立,只要把最高阶项留下即可,低阶项都去掉,高阶项的系数也都去掉。
记为:O(忽略掉系数的最高阶)

通过3个具体的例子来了解时间复杂度

选择排序

每一轮都去挨个比较,找出最小的那个值,和当前伦的第一个值进行交换。所以排序算法的时间复杂度为O(N^2),并且和数据的初始分布无关。

public static void selectionSort(int[] arr) {
	if (arr == null || arr.length < 2) {
		return;
	}
	for (int i=0; i<arr.length; i++) {
		int minIndex = i;
		for (j=i; j<arr.length; j++) {
			minIndex = arr[j] < arr[minIndex] ? j : minIndex;
		}
		swap(arr, i, minIndex);
	}
}

public static void swap(int[] arr, int i, int j) {
	arr[i] = arr[i]^arr[j];
	arr[j] = arr[i]^arr[j];
	arr[i] = arr[i]^arr[j];
}

冒泡排序

每一轮都进行相邻两个值的比较,如果顺序不对就交换,保证每轮过后的最大值或最小值一定在最后。所以冒泡算法的时间复杂度为O(N^2),并且也和数据的初始分布无关。

public static void bubbleSort(int[] arr) {
	if (arr == null || arr.length < 2) {
		return;
	}
	for (int i=arr.length-1; i>0; i--) {
		for (int j=0; j<i; j++) {
			if (arr[j] > arr[j+1]) {
				swap(arr, j, j+1);
			}
		}
	}
}

public static void swap(int[] arr, int i, int j) {
	arr[i] = arr[i]^arr[j];
	arr[j] = arr[i]^arr[j];
	arr[i] = arr[i]^arr[j];
}

插入排序

每一轮都把最后位置的那个数,依次和它的前一个数对比,如果顺序不对就交换,否则就停止。插入排序和数据的初始分布情况有关,最好的情况下为O(N),最坏的情况下为O(N^2)。但是我们说过时间复杂度只看最坏情况。

public static void insertionSort(int[] arr) {
	if (arr == null || arr.length < 2) {
		return;
	}
	for (int i=1; i<arr.length; i++) {
		for (j=i-1; j>=0; j--) {
			if (arr[j] > arr[j+1]) {
				swap(arr, j, j+1);
			}
		}
	}
}

public static void swap(int[] arr, int i, int j) {
	arr[i] = arr[i]^arr[j];
	arr[j] = arr[i]^arr[j];
	arr[i] = arr[i]^arr[j];
}

常见的时间复杂度

排名由好到差:
O(1)
O(logN)
O(N)
O(N*logN)
O(N^2)…
O(2^N)
O(N!)

额外空间复杂度

你要实现一个算法,在实现算法流程的过程中,你需要开辟一些空间来支持你的算法流程。

作为输入参数的空间,不算额外空间。
作为输出结果的空间,不算额外空间。

因为这些都是必要的、和现实目标无关的。所以都不算。

但除此之外,你的流程如果还需要开辟空间才能让你的流程继续下去。这部分空间就是额外空间。
如果你的流程只需要开辟有限几个变量,额外空间复杂度就是O(1)
如果你的流程需要开辟一个数组、队列等级和,额外空间复杂度就是O(1)

发布了40 篇原创文章 · 获赞 0 · 访问量 388

猜你喜欢

转载自blog.csdn.net/weixin_43780400/article/details/105626294
今日推荐