织梦 网站地图 样式,网推接单网,网站开发 网页设计北京师范大学出版社,网络舆情监测系统软件#x1f4d9; 作者简介 #xff1a;RO-BERRY #x1f4d7; 学习方向#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 #x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向#xff0c;欢迎各位关注#xff0c;谢谢各位的支持 时间复杂度和空间复杂度 前… 作者简介 RO-BERRY 学习方向致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 日后方向 : 偏向于CPP开发以及大数据方向欢迎各位关注谢谢各位的支持 时间复杂度和空间复杂度 前言1. 什么是数据结构2.什么是算法3.数据结构和算法的重要性4.如何学好数据结构和算法 1.算法效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度 2.时间复杂度2.2 大O的渐进表示法2.3常见时间复杂度计算举例实例1实例2:实例3实例4:实例5 3.空间复杂度实例1实例2实例3 4. 常见复杂度对比 前言
在学习这个知识之前我们先了解几个概念
1. 什么是数据结构
数据结构(Data Structure)是计算机存储、组织数据的方式指相互之间存在一种或多种特定关系的数据元素的集合。
2.什么是算法
算法(Algorithm):就是定义良好的计算过程他取一个或一组的值为输入并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤用来将输入数据转化成输出结果
3.数据结构和算法的重要性
在校园招聘的笔试中 目前校园招聘笔试一般采用Online Judge形式 一般都是20-30道选择题2道编程题或者3-4道编程题 现在公司对学生代码能力的要求是越来越高了大厂笔试中几乎全是算法题而且难度 大中小长的笔试中才会有算法题。算法不仅笔试中考察面试中面试官基本都会让现场写代码。而算法能力短期内无法快速提高了至少需要持续半年以上算法训练积累否则真正校招时笔试会很艰难因此算法要早早准备。
算法的学习是非常重要的那算法学到什么程序才算学通很简单学算法的有个必备的基础功「白板编程」即用笔和纸就可以把一个算法手写出来。举个例子快速排序这个算法你脑子里能第一时间把它理清思路吗随后还能手写的出来吗
算法是一门非常深奥的学科除了一些基础的算法还有非常多更高阶的内容。但要知道所有的编程技术都是为了解决现实生活中某个实际问题。算法也是如此。
很多人学算法学不明白或者觉得很难就是因为这些晦涩难懂的算法在实际的编程中你很难应用到。做编程 90% 的人是没学过算法但不妨碍别人开发做的牛逼。然而不懂算法的人是很难进阶到高阶的岗位也就是我们俗称的码农。
那算法在实际应用中有什么用举个例子布隆过滤器算法(Bloom Filter)非常经典的一个去重算法。它能非常高效的进行各种去重提高你的运行效率。
程序的效率提高它能得到收益再来看个例子 2018 年淘宝双 11开场 21 秒交易额超 10 亿每秒就是 0.47 亿。淘宝的程序多优化一秒就能多带来 0.47 亿交易额。 而在我们现实生活中有无数这样的例子多优化这一秒就能给公司带来巨大的收益。
4.如何学好数据结构和算法
啃书刷题跟着视频学习参加算法比赛
一切都需要我们的不断努力循序渐进慢慢来一切都会好如今种下的果实迟早会开花结果只分早迟 1.算法效率
1.1 如何衡量一个算法的好坏
如何衡量一个算法的好坏呢比如对于以下斐波那契数列
long long Fib(int N)
{if(N 3)return 1;return Fib(N-1) Fib(N-2);
}斐波那契数列的递归实现方式非常简洁但简洁一定好吗那该如何衡量其好与坏呢
1.2 算法的复杂度
算法在编写成可执行程序后运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏一般是从时间和空间两个维度来衡量的即时间复杂度和空间复杂度。 时间复杂度主要衡量一个算法的运行快慢而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。
2.时间复杂度
2.1 时间复杂度的概念 时间复杂度的定义在计算机科学中算法的时间复杂度是一个函数它定量描述了该算法的运行时间。 一个算法执行所耗费的时间从理论上说是不能算出来的只有你把你的程序放在机器上跑起来才能知道。但是我们需要每个算法都上机测试吗 是可以都上机测试但是这很麻烦所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例算法中的基本操作的执行次数为算法的时间复杂度。 即找到某条基本语句与问题规模N之间的数学表达式就是算出了该算法的时间复杂度 // 请计算一下Func1中count语句总共执行了多少次
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 M 10;while (M--){count;}
}第一个for循环里使用了嵌套两个for循环嵌套终止条件均是小于N即内循环一轮是N次外循环是N次总循环NN 第二个for循环终止条件为小于2N即循环2*N次 第三个while循环终止条件为M即M等于0的时候终止M10即循环10次 N 10 F(N) 130N 100 F(N) 10210N 1000 F(N) 1002010
我们会发现当N越来越大的时候对于FN的值2*N和10的影响越来越小而我们的N方是起到决定性因素的。
实际中我们计算时间复杂度时我们其实并不一定要计算精确的执行次数而只需要大概执行次数那么这里我们使用大O的渐进表示法
2.2 大O的渐进表示法
大O符号Big O notation是用于描述函数渐进行为的数学符号。 推导大O阶方法 1、用常数1取代运行时间中的所有加法常数。 2、在修改后的运行次数函数中只保留最高阶项。 3、如果最高阶项存在且不是1则去除与这个项目相乘的常数。得到的结果就是大O阶。 使用大O的渐进表示法以后Func1的时间复杂度为 O(2N) N 10 F(N) 100N 100 F(N) 10000N 1000 F(N) 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项简洁明了的表示出了执行次数。 另外有些算法的时间复杂度存在最好、平均和最坏情况 最坏情况任意输入规模的最大运行次数(上界) 平均情况任意输入规模的期望运行次数 最好情况任意输入规模的最小运行次数(下界) 例如在一个长度为N数组中搜索一个数据x 最好情况1次找到 最坏情况N次找到 平均情况N/2次找到 在实际中一般情况关注的是算法的最坏运行情况所以数组中搜索数据时间复杂度为O(N)
2.3常见时间复杂度计算举例
实例1
// 计算Func2的时间复杂度
void Func2(int N)
{int count 0;for (int k 0; k 2 * N ; k){count;}int M 10;while (M--){count;}printf(%d\n, count);
}实例2:
// 计算Func3的时间复杂度
void Func3(int N, int M)
{int count 0;for (int k 0; k M; k){count;}for (int k 0; k N ; k){count;}printf(%d\n, count);
}实例3
// 计算Func4的时间复杂度
void Func4(int N)
{int count 0;for (int k 0; k 100; k){count;}printf(%d\n, count);
}实例4:
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;}
}实例5
// 计算BinarySearch的时间复杂度
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 mid1;else if (a[mid] x)end mid-1;elsereturn mid;}return -1;
}3.空间复杂度
空间复杂度也是一个数学表达式是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间因为这个也没太大意义所以空间复杂度算的是变量的个数。 空间复杂度计算规则基本跟实践复杂度类似也使用大O渐进表示法。 注意函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。
实例1
// 计算BubbleSort的空间复杂度
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;}
}使用的格外空间也就是exchange常数个额外空间所以空间复杂度为 O(1)
实例2
// 计算Fibonacci的空间复杂度
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{if(n0)return NULL;long long * fibArray (long long *)malloc((n1) * sizeof(long long));fibArray[0] 0;fibArray[1] 1;for (int i 2; i n ; i){fibArray[i] fibArray[i - 1] fibArray [i - 2];}return fibArray;
}动态开辟了N个空间空间复杂度为 O(N)
实例3
// 计算阶乘递归Fac的空间复杂度
long long Fac(size_t N)
{if(N 0)return 1;return Fac(N-1)*N;
}递归调用了N次开辟了N个栈帧每个栈帧使用了常数个空间。空间复杂度为O(N)
4. 常见复杂度对比
一般算法常见的复杂度如下: