常见的几种算法

来源于《算法图解》

1 二分查找

前提:给定数据都是有序排放的。

思想:从中间猜,每次都排除数据的一半。

比如:1,2,3....,100 数组.  依次猜的数为:50,75,88,94,97,99,100。

根据如下程序,最极端情况才需要猜测7次,那二分查找最大的步数是公式是什么呢?

step = log2n

int binary_search(int search)
{
    int low =0;
    int high = strlen(list) -1;
    int middle = (low + high) / 2;
    int guess = list[middle];
    while(list[middle] != search)
    {
        if(search > list[middle])
            low = middle + 1;
           
        if(search < list[middle])
            high = middle -1;
        
        if(low == high)
            break;

        middle = (low + high) / 2;
    }
    return middle;
}

2 大O 表示法

大O表示法指出了算法有多快,大0表示法计算的是操作数,算法运算时间用大0表示,不是以秒为单位,是从增速的角度度量的。

常见的大O运行时间:

O(log n): 对数时间,比如二分查找法

O(n):线性时间,比如简单查找法(按照顺序依次查找)

O(n*log n):快排

O(n^2): 选择排序,一种较慢的排序方法。

0(n!):旅行商问题,非常慢的算法。

3 数组与链表

链表:每个元素都存储下一个元素的地址,链表的优势在于插入元素方面,不能直接读取某个元素需遍历。
数据:每个元素都存放在一块连续的存储空间,能直接读取某个元素,插入元素很多元素都要平移。

下图为在进行对数组与链表进行查找,插入,删除时其大0 运行时间。

链表数组:facebook 存储用户信息时既不是使用数组,也不时链表而是链表数组。

4 二分查找法

思想:遍历这个链表或数组,选择出最大值放到第一个,接着遍历剩余的元素,将第二大值放入第二个, 依次循环,直到最后一个。

int SelectMaxElement(char *p, int len)
{
    int maxElementIndex = 0;
    for(int i = 0; i < len -1;i++)
    {
        if(p[i] > maxElement)
           MaxElementIndex = i;
    }
    return MaxElementIndex;
    
}

int SelectSort(char *p , int len)
{
    int tempValue = 0 , index = 0;
    for(int i = 0;i < len -1, i++)
    {
        index = SelectMaxElement(p+i,len-i);
        tempValue = p[i];
        p[i] = p[i+index];
        p[i+index] = p[i];
        
    }
}

5 递归

 递归是指自己调用自己的函数,每个递归函数都有两部分:递归条件和基线条件。

递归条件:函数自己调用自己。

基线条件:函数不再自己调用自己,避免形成无限循环。

栈有两种操作,压入和弹出,所有函数调用都进入调用栈,调用栈可能很长,这将占用大量的内存。

6 快速排序

分而治之:当你遇到使用任何算法都无法解决的问题时,或许分而治之是一种通用的解决方法。分而治之算法(D&C)是递归的,使用D&C解决问题必须包含以下两个步骤:1 找出基线条件,2不断将问题分解(或者说缩小规模),直到符合基线条件。

快速排序:它比选择排序快得多,也使用的D&C 。

算法思想:找一基准值,将小于这基准值的放一边, 大于这基准值的放一边,这被称为分区。然后采用D&C ,缩小问题规模重复。

现在你有:一个由所有小于基准值的数字组成的子数组;基准值;一个由所有大于基准值的数组组成的子数组。

快排的大0表示法: 0(nlog n)

7 散列表

散列表:根据散列函数确定元素的存储位置,散列表由键和值组成。适用于:模拟映射关系,防止重复,缓存/记住数据。
散列函数:相同的输入返回的索引值是一样的, 不同的数据返回的索引值不同。


散列冲突:不同的输入被映射到了相同的位置,解决办法:在这个位置存储一个链表。
好的散列表,要避免冲突,需要有:较低的装填因子,良好的散列函数。
装填因子:散列表中多少位置是空的,装填因子适合控制在0.7,大于这个值就应该调整列表的长度。

装填因子计算:已填充的位置/ 列表长度。比如上图列表总长度为8,已填充位置为3,因此装填因子为3/8. 

良好的散列函数:让值呈均匀分布,不要扎堆。

散列表的大0 时间:O(1),根据散列函数能快速定位到键值对,在执行效率上是非常高的。

8 广度优先搜索算法

最短路径问题:使用图来建立问题模型,使用广度优先搜索解决问题。
图:由节点和边组成,用于模拟不同东西是如何相连的。
广度优先搜索算法:假设你要找一个名叫Tom的人,首先你遍历自己的通讯录是否有个叫Tom的人,假设没有,那就必须在朋友的朋友中查找,已此循环,直到找到Tom.
查找最短路径: 首先从你自己通讯录找,这叫一度关系,然后在从朋友的通讯路找,这叫二度关系....。自己的朋友是一度关系,朋友的朋友是二度关系。  一度关系强于二度关系,二度关系强于三度关系,查找顺序为一度关系,到二度,三度。因此需要按顺序添加,有一个可实现这种目的的数据结构,那就是队列。


实现图:通过散列表,来表述你通讯录的关系。构造散列表来描述关系。 

算法步骤:

1.创建一个队列,用于存储要检查的人。
2.从队列中弹出一个人
3.检查这个人是否为自己寻找的人
3.1 是,大功告成
3.2 否,将这个人的所有通讯好友加入队列, 并跳到第二步,递归

 注意检查完之后,需要标记为已检查,不然 像下面这种情况可能会导致无线循环。

9 狄克斯特拉算法

段数最少,用广度优先搜索。路径最短, 用狄克斯特拉算法。

狄克斯特拉算法四个步骤:

1 找出最便宜的节点,既在最短时间内到达的节点。

2 更新该节点的邻居开销

3 重复这个过程,直到对图中的每个节点都这样做了。

4 计算最终路径。

狄克斯特拉算法每条边都有关联数字的图,这些数字称为权重。

算法实现:

 广度优先搜索用于在非加权图中查找最短路径,狄克斯特拉用于加权图中查找最短路径。

10 贪婪算法

       NP完全问题:没有快速算法的问题。

        识别NP 完全问题,面临NP 完全问题时(教室调度,背包问题,集合覆盖问题),最佳的做法是使用近似算法,贪婪算法易于实现,运行速度快,是不错的 近似算法。

        贪婪算法:一种非常简单的问题解决策略,每一步都采用最优解,每步都选择局部最优解的话,得到的就是全局最优解。

11 动态优化问题

动态规划:它将问题分成小问题,先着手解决这些小问题。

算法步骤:在每一行,可偷的商品都为当前行以及之前各行的商品,然后填充网格,最后得到如下网格。

K最近邻算法

K最近邻算法(KNN算法):判断这个水果是柚子还是橙子,看这三个邻居中, 柚子多还是橙子多,如果柚子多,那么就把这个水果归类为柚子, 这就是K最近邻算法。
创建系统推荐:假设Netflix 要给用户priyanka 推荐电影,可以找出喜好与他最接近的五位用户。假设与他喜好接近的五位用户都喜欢这部电影,那么就将其推荐给priyanka.

那么如何确定喜好接近呢? 特征抽取

机器学习:浏览大量的数字图像,将这些特征提取出来(喂养),遇到新图像时,提取该图像的特诊,再找它最近的邻居。

12 其他十种类型算法

二叉查找树:对于其每个节点,左子节点都比它小,而右子节点的值都比它大。二叉查找树大O时间查找和二分法一样。对于有序数组而言,大0 时间查找都一样,但是插入删除要比有序数组快的多。

反向索引:创建一个散列表,将单词映射到包含它的界面。当用户输入某个单词时,查看散列表,哪些页面包含这个单词,在搜索经常用到。

傅里叶变换: 将时域信号转换成频域信号。使用范围极广,比如歌曲调音,JPG 压缩等等。

并行算法:现在台式机或者笔记本采用多核处理器,为提高算法速度,需要让它们在多个内核中并行执行。

分布式算法:在并行算法只需二到四个内核时,完全可以在笔记本运行它,但如果数百个核呢,在这种情况下,可让算法在多台计算机上运行,这就是分布式算法。

布隆过滤器:它是一种概率型数据结构,它提供的答案有可能不对,但很有可能是正确的,相比散列表的绝对准确,布隆过滤器速度要快的多。

SHA:给定一串字符或者文件生成唯一的SHA 值,SHA是一系列算法,SHA-0,SHA-1,SHA-2和SHA-3.

 Simhash:它是局部敏感的散列算法,不同于SHA ,哪怕一个字符不同,得到的值SHA完全不同,Simhash 一个字符不同,得到的字符串只有细微的差异。

Diffie-Hellman:使用两个密钥,公钥和私钥,故名思意,公钥的公开的,加密后的消息只有使用私钥才能打开。

线性规划:用于在给定的约束条件下,最大限度的改善指定的指标。另外所有图的算法都可以使用线性规划来实现,线性规划是一个宽泛得多的框架,图的问题只是其中一个的子集。

        

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值