一. 算法的基本概念
一个问题可以有多个算法,每种算法效率不同
一个算法具有五个特征:有穷性,确切性、输入项、输出项、可行性
-
算法评定
算法分析的目的在于选择合适算法和改进算法
一个算法的评价主要从时间复杂度和空间复杂度来考虑 -
时间复杂度
执行算法所需要时间的计算工作量。一般来说,计算机算法是问题规模n的函数f(n),算法的时间复杂度也因此记做T(n)=O(f(n))
问题的规模n越大,算法执行的时间的增长率与f(n)的增长率正相关,称作渐进时间复杂度 -
时间复杂度计算方式
得出算法的计算次数公式
线性阶 O(n)
O(n) 1+2+3+...+n
常数阶:O(1)
function demo($n){
echo $n;
echo $n;
}
function demo1($n){
echo ($n+1)*$n/2
}
平方阶O(n^2) n^2+n+1
function demo($n)
{
$sum = 0;
for($i=0;$i<$n;$i++){
for($j=0;$j<$n;$j++){
$sum+=$j;
}
$sum+$i;
}
echo $sum;
}
立方阶O(n^3) n^3
如果最高阶存在且不是1,则去除与这个项相乘的常数
-
常见时间复杂度:常数阶、线性阶、平方阶、立方阶、对数阶、nlog2n阶、指数阶
O(1)>O(log2n)>O(n)>O(nlog2n)>O(n2)>O(n3)>O(2n)>O(n!)>O(nn) -
时间复杂度其他概念
最坏情况:最坏情况时的运行时间,一种保证,如果没有特别说明,说的时间复杂度即为最坏情况的时间复杂度
平均情况:期望的运行时间 -
空间复杂度
算法需要消耗的内存空间,记做S(n)= O(f(n))
包括程序代码所占用的空间,输入数据所占用的空间和辅助变量所占用的空间这三个方面
计算和表示方法与时间复杂度类似,一般用复杂度的渐进性来表示 -
空间复杂度计算方式
有时用空间换取时间
冒泡排序的元素交换,空间复杂度0(1) -
排序算法
冒泡排序、直接插入排序、希尔排序、选择排序、快速排序、堆排序、归并排序
冒泡排序:两两相邻的数进行比较,如果反序就交换,否则不交换
时间复杂度:最坏(O(N2),平均(O(N2)))
空间复杂度:O(1)
直接插入排序
每次从无序表中取出第一个元素,把他输入到有序表的合适位置,使有序表依然有序
时间复杂度:最坏(O(N2),平均(O(N2)))
空间复杂度:O(1)
希尔排序
把待排序的数据增量分成几个子序列,对子序列进行插入排序,知道增量为1,直接进行插入排序;增量的排序,一般是数组的长度的一半,再变为原来增量的一半,知道增量为1
时间复杂度:最坏(O(N^2),平均(O(n*log2n)))
空间复杂度:O(1)
选择排序
每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,知道全部待排序的数据元素排完
时间复杂度:最坏(O(N2),平均(O(N2)))
空间复杂度:O(1)
快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按照此方法对这两部分数据分别进行快速排序,整个排序过程可以递归完成
时间复杂度:最坏(O(N^2),平均(O(n*log2n)))
空间复杂度:最坏(O(n),平均(O(log2n)))
堆排序
把待排序的元素按照大小在二叉树位置上排序,排序好的元素要满足:父节点的元素要大于等于子节点;这个过程叫做堆化过程,如果根节点存放的是最大的数,则叫做大根堆,如果是最小,就叫小根堆,可以把根节点拿出来,然后再堆化,循环到最后一个节点
时间复杂度:最坏(O(nlog2n)),平均(O(nlog2n)))
空间复杂度:O(1)
归并排序
将两个或两个以上有序表合并成一个新的有序表,即把待排序序列分成若干个有序的子序列,再把有序的子序列合并为整体有序序列
时间复杂度:最坏(O(nlog2n)),平均(O(nlog2n)))
空间复杂度:O(n)
总结:
快速排序、归并排序的理想时间复杂度都是O(nlog2n),但快速排序的时间复杂度并不稳定,最坏情况下复杂度为O(n^2),所以最理想的算法还是归并排序
二分查找
原理:从数组的中间元素开始,如果中间元素正好是要查找的元素,搜索结束,如果某一个特定元素大于或者小于中间元素,则在数组大于或者小于中间元素的那一半中查找,而且跟开始一样从中间开始比较,如果某一步骤数组为空,代表找不到。
时间复杂度:最坏(O(log2n)),平均(O(log2n)))
空间复杂度:迭代O(1),递归(O(log2n))
顺序查找
原理:按照一定的顺序检查数组中的每一个元素,直到找到所要查找的特定值为止。
时间复杂度:最坏(O(n)),平均(O(n)))
空间复杂度:O(1)
总结:
二分查找算法的时间复杂度最差是O(log2n),顺序查找的时间复杂度最差为O(N),所以二分查找法更快,但是递归情况下,二分查找法更消耗内存,时间复杂度为O(log2n)
二.常见数据结构
-
Array
数组,最简单而且应用最广泛的数据结构之一
特性:使用连续的内存来存储,数组中的所有元素必须是相同的类型或类型的衍生(同质数据结构)、元素可以通过下标直接访问 -
linkedList
链表,线性表的一种,最基本、最简单也是最常用的数据结构
特性:元素之间的关系是一对一的关系(除了第一个还最后一个元素,其他元素都是首尾相接)、顺序存储结构和链式存储结构两种存储方式 -
Stack
栈,和队列相似,一个带有数据存储特性的数据结构
特性:存储数据是先进后出的、栈只有一个出口,只能从栈顶部增加或移除元素 -
Heap
堆,一般情况下,也叫二叉堆,近似完全二叉树的数据结构
特性:子节点的键值或者索引总小于他的父节点,每个节点的左右子树又是一个二叉堆,根节点最大的堆叫最大堆或者大根堆、最小的叫最小堆或者小根堆 -
list
线性表,由零个护着多个数据元素组成的有序序列
特性:线性表是一个序列,0个元素构成的线性表是空表、第一个元素无先驱、最后一个元素无后继、其他元素都只有一个先驱和后继、有长度,长度是元素个数,长度有限 -
doubly-linked-list
双向链表
特性:每个元素都是一个对象,每个对象有一个关键字key和两个指针(next和prev) -
queue
队列
特性:先进先出(FIFO),并发中使用,可以安全将对象从一个任务传给另一个任务 -
set
集合
特性:保存不重复元素 -
map
字典
特性:关联数组,也叫作字典或者键值对 -
graph
图
特性:通常使用邻接矩阵和邻接表表示,前者易实现但对于稀疏矩阵会浪费较多空间、后者使用链表的方式存储信息但对于图搜索时间复杂度较高
三.其他逻辑算法
- 斐波那契数列
- 写一个函数,实现字符串open_door=>OpenDoor
function strHandle($str)
{
$arr = explode('_',$str);
$return = '';
foreach($arr as $val)
{
$return.= ucfirst($val);
}
return $return;
}
四.模拟内置函数
- 不使用PHP内置函数反转字符串
function str_rev($str)
{
for($i=0;true;$i++)
{
if(!isset($str[$i]))
{
break;
}
}
$return = '';
for($j=$i-1;$j>=0;$j--)
{
$return .= $str[$j];
}
return $return;
}
- 不使用array_merge,完成多个数组的合并
function array_mer()
{
//动态获取参数
$arrays = func_get_args();
foreach($arrays as $arr)
{
if(is_array($arr))
{
foreach($arr as $val)
{
$return[] = $val;
}
}
}
return $return;
}
array_mer();