整屏网站模板,优畅wordpress,上海企业查询,wordpress禁止查看源码#x1f525;博客主页#xff1a;小王又困了
#x1f4da;系列专栏#xff1a;数据结构
#x1f31f;人之为学#xff0c;不日近则日退
❤️感谢大家点赞#x1f44d;收藏⭐评论✍️ 目录
一、什么是数据结构
二、什么是算法
三、算法的效率
四、时间复杂度
4.… 博客主页小王又困了
系列专栏数据结构
人之为学不日近则日退
❤️感谢大家点赞收藏⭐评论✍️ 目录
一、什么是数据结构
二、什么是算法
三、算法的效率
四、时间复杂度
4.1大O渐进表示法
4.2常见时间复杂度计算举例
4.3例题消失的数字
五、空间复杂度
5.1空间复杂度计算
5.2例题轮转数组 ️前言 在前面我们讲完了C语言的内容从本期开始我们将进入数据结构的学习本期介绍了数据结构的概念和算法分析的初步知识。 一、什么是数据结构 数据结构(Data Structure)是计算机存储、组织数据的方式指相互之间存在一种或多种特定关系的数据元素的集合。 二、什么是算法 算法(Algorithm)是定义良好的计算过程它取一个或一组的值为输入并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤用来将输入数据转化成输出结果。 三、算法的效率 我们会通过复杂度去衡量一个算法的好坏。算法在编写成可执行程序后运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏一般是从时间和空间两个维度来衡量的即时间复杂度和空间复杂度。 时间复杂度主要衡量一个算法的运行快慢而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展计 算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。 四、时间复杂度
时间复杂度的概念 时间复杂度的定义在计算机科学中算法的时间复杂度是一个函数它定量描述了该算法的运行时间。一 个算法执行所耗费的时间从理论上说是不能算出来的只有你把你的程序放在机器上跑起来才能知道。但是我们需要每个算法都上机测试吗是可以都上机测试但是这很麻烦所以才有了时间复杂度这个 分析方式。一个算法所花费的时间与其中语句的执行次数成正比例算法中的基本操作的执行次数为算法的时间复杂度。 即找到某条基本语句与问题规模N之间的数学表达式就是算出了该算法的时间复杂度。 4.1大O渐进表示法 实际中我们计算时间复杂度时我们其实并不一定要计算精确的执行次数而只需要大概执行次数所以这里我们使用大O的渐进表示法。 大O符号是用于描述函数渐进行为的数学符号。 推导大O阶方法 1.用常数1取代运行时间中的所有加法常数。 2.在修改后的运行次数函数中只保留最高阶项。 3.如果最高阶项存的系数不为1则去除这个项的系数。 另外有些算法的时间复杂度存在最好、平均和最坏情况
最坏情况 任意输入规模的最大运行次数(上界) 平均情况 任意输入规模的期望运行次数 最好情况 任意输入规模的最小运行次数(下界)
说明在实际中一般情况关注的是算法的最坏运行情况。
4.2常见时间复杂度计算举例
冒泡排序 // 计算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;}
}最好情况O(N) 最好情况就是数组本身有序虽然它有序但是计算机最初并不知道它是有序的仍需要遍历一遍数组才能知道它是有序的所以就好情况就是O(N)。 最坏情况O(N^2) 最坏情况是数组完全逆序则第一趟需要交换N − 1 次第二趟需要交换N − 2次…直到最后一趟只交换一次把所有的交换次数加起来就得到了冒泡排序最坏情况下的时间复杂度其实也就是一个等差数列求和所以最会情况下的时间复杂度是O(N^2) 二分查找 // 计算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 mid 1;else if (a[mid] x)end mid - 1;elsereturn mid;}return -1;
} 最好形况O(1) 最好情况是第一次查找就找到目标值此时时间复杂度就是O(1)。 最坏情况O(log2N) 二分查找每次可以排出一半的数据就坏的情况就是排出到只剩下一个数据。当N/2/2/2/2……/21时就找到了目标值。除去了几个2就是执行的次数所以时间复杂度为O(log2N)。 O(N)和O(log2N)的对比
N1000100W10亿O(N)1000100W10亿O(log2N)102030
由此我们看到O(log2N)相对O(N)在效率上有很大的提升但二分查找有一个限制条件就是数组必须有序所以在实际中二分查找应用并不多。
递归阶乘 // 计算阶乘递归Fac的时间复杂度
long long Fac(size_t N)
{if (0 N)return 1;return Fac(N - 1) * N;
}时间复杂度O(N) Fac一共被递归调用了N1次且每次Fac中执行1次总共执行N1次所以时间复杂度是O(N)。 斐波那契数 // 计算斐波那契递归Fib的时间复杂度
long long Fib(size_t N)
{if (N 3)return 1;return Fib(N - 1) Fib(N - 2);
} 时间复杂度O(2^N) 斐波那契额数列它的时间复杂度是等比数列求和所以时间复杂度为O(2^N)。 4.3例题消失的数字
思路一 我们可以把0~N个数字全部加起来减去数组中的元素结果就是消失的数字。 时间复杂度为O(N) int missingNumber(int* nums, int numsSize)
{int i0int retN*N/2;for(i0;inumsSize;i){ret-nums[i];}return ret;
} 思路二 我们可以使用异或异或的条件是相同为0相异为1。两个相同的数异或为00和任何数异或都为原数所以我们将0~N与数组中的所有异或得到的结果就是消失的数。 int missingNumber(int* nums, int numsSize)
{int m0;int i0;for(i0;inumsSize;i){m^i;}for(i0;inumsSize;i){m^nums[i];}return m;
} 五、空间复杂度
空间复杂度的概念 空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间而算的是变量的个数。 空间复杂度计算规则也使用大O渐进表示法。 注意函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。 一般常见的空间复杂度都是O(1)或者O(N)额外开辟数组。 5.1空间复杂度计算
递归阶乘 // 计算阶乘递归Fac的空间复杂度
long long Fac(size_t N)
{if(N 0)return 1;return Fac(N-1)*N;
}空间复杂度O(N) 函数的每一次调用都会开辟一个栈帧每个栈帧开常数个空间开辟N1个栈帧空间复杂度就为O(N)。 递归程序最大的问题就是深度太深会有栈溢出的风险。 斐波那契数 long long Fib(size_t N)
{if(N 3)return 1;return Fib(N-1) Fib(N-2);
}空间复杂度O(N) 空间是可以重复利用的递归的调用是按一条线递归下去的不会同时递归当递归到最后一层返回时创建的函数栈帧销毁调用另一条仍可以使用这块空间所以空间复杂度是O(N)。 5.2例题轮转数组
思路
逆置前n-k个逆置后k个整体逆置 void reverse(int* nums,int left,int right)
{int tmp0;while(leftj){tmpnums[left];nums[left]nums[right];nums[right]tmp;left;right--; }
}void rotate(int* nums, int numsSize, int k)
{if(k0){return nums;}reverse(nums,0,numsSize-1);reverse(nums,0,k%numsSize-1);reverse(nums,k%numsSize,numsSize-1);
} 本次的内容到这里就结束啦。希望大家阅读完可以有所收获同时也感谢各位读者三连支持。文章有问题可以在评论区留言博主一定认真认真修改以后写出更好的文章。你们的支持就是博主最大的动力。