算法图解

下面是本人在看算法书籍时做的笔记。因为前面的比较基础,就从第五章才开始做的笔记

第五章:散列表

个人理解:概念类似于hash索引数据结构,通过散列表函数(hash函数) 计算出int值,然后存储数据 - 复杂度 为 O(1),遇到计算出同样int值时,则将该位置 当做链表来处理(冲突的概念)

1,知识点:

(1),散列函数总是将同样的输入映射到相同的索引位置

(2),散列函数将不同的输入映射到不同的索引, 偶然情况也会将不同的输入映射到相同的索引位置,这时将会把该索引位置当做链表来处理

(3),散列函数知道数组有多大,总会返回有效的索引

(4),散列表 是无序的

2,适用场景:防止重复,web缓存,

3,性能:

(1),一般情况下散列表执行各种操作的时间均为O(1), 

O(1) 被称为常量时间,意思指不管散列表多大,查找任意元素的时间都相同

也有最坏情况,即散列表分配不合理,所有元素都存到同一索引位置,故此时操作时间为O(n)

                  平均情况          最糟情况

查找          O(1)                  O(n)

插入          O(1)                  O(n)

删除          O(1)                  O(n)

(2)查找对比

简单查找的运行时间为 线性时间 ,复杂度为O(n)

二分法的运行时间为 对数时间 ,复杂度为O(log n)

散列表中查找的运行时间为 常量时间 ,复杂度为O(1)

(3)散列表,数组,链表 对比

          这里不支持表格,就不列举了

(4),避免冲突,需要 有较低的填装因子和较好的散列函数

填装因子: 散列表包含的元素数 / 位置总数

一般填装因子超过0.7,则需要调整散列表的长度,一般调整散列表的长度时,增大一倍

第六章 广度优先搜索  (breadth first search)  BFS

1,图算法 - 广度优先搜索 - 适用于解决最短路径问题  (是否有A到B的路径,如果有,将找到最短路径)

图由节点和边组成, 一个节点可能与多个节点直接相连,这些节点被称为邻居

A----------------->  B                   

A,B 叫做节点 ,---->  这个叫做边

有向图: A ---> B , A <----- B ,

无向图: A ---- B    意味着两个节点彼此指向对方,即环    A <----> B

2,队列是一种先进先出的数据结构

    栈是一种 后进先出的 数据结构

3,广度优先搜索的PHP代码解释:

查找你朋友中有在腾讯上班的人,如果没有则在朋友的朋友中找,  求最短路径,与你关系相对最近

每个人的朋友 - 可以用散列表结构来解决  即  $arr['zhangsan'] = ['lisi','wangwu'];    $arr['wangwu'] = ['zhaoliu','songqi'];

逻辑:优先查第一层关系的(你的朋友)

其次查第二层关系,(你朋友的朋友)

再次查第三层关系,(你朋友的朋友的朋友)

。。。。。。

知识点:使用到队列,散列表。  每个人的朋友用散列表存储,查找搜索的列表 用 队列。先进先出

代码表示:

首先关系表

$relation['zhangsan'] =  ['lisi','wangwu'];

$relation['wangwu'] = ['zhaoliu','songqi']; 

。。。。。

function breadth_first_search($name){

$searchList = array();  //先弄个 搜索队列  - 该出用php数组做队列

$searchList = array_merge($searchList, $relation[$name]);  // 把该人的朋友加入到队列中

$searchAlready = array();    // 已搜索过的人,防止死循环

while($searchList){

$people = array_shift($searchList); // 弹出查找人 ,顺序

if(! in_array($searchAlready)){ //未查找过

if( check_in_tencent($people) ){

return $people; // 找到了

}else{

array_push($people, $searchAlready);  // 加入已查找列表

$searchList = array_merge($searchList, $relation[$people]);  // 将该的朋友 加入搜索队列中

}

}

}

return "";  //没找到

}

function check_in_tencent($name){

// 随便写个逻辑 判断是不是在腾讯,不是此处讲的重点

}

运行时间:

要找到该人,即意味着将要沿着每条边前行,故运行时间为 O(边数)

还用到了队列,要检查每个人。将一人添加入队列的时间是固定的,为0(1), ---  队列数据类型 插入操作的运行时间为O(1)

要对每个人都进行这样的操作。即为 O(人数)

所以:广度优先搜索的运行时间为 O(人数+边数),  即 O(V+E)    其中 V 为顶点数,E为边数

PS: 还 可以用 Python 脚本写。 先不写了。

第七章 狄克斯特拉算法    Dijkstra

个人理解: 图搜索 分为 有向图,无向图,加权图,负权图 等等      狄克斯特拉算法比广度优先搜索 强在 适用于 计算 加权图

1,知识点

(1),狄克斯特拉算法 对于每条边上的相关数字,称为  权重(weight)

(2),带权重的图称为加权图,不带权重的图称为 非加权图

(3),计算非加权图中的最短路径,可使用 广度优先搜索(BFS),计算加权图中的最短路径可使用狄克斯特拉算法

(4),含有负权边的图,要计算最短路径,不能使用狄克斯特拉算法,应该使用 "贝尔曼-福德算法" 。

2,狄克斯特拉算法 分4个步骤

(1),找到 最便宜的节点,即可在最短时间内到达的节点

(2),更新该节点邻居的开销,即 计算邻居节点的最低开销 然后更新(是否有前往邻居节点的更短路径,如果有则更新)

(3),重复这个过程,直到把所有节点的最低开销都统计过

(4),计算最终路径

3,广度优先搜索(BFS) 跟 狄克斯特拉(Dijkstra) 算法的 概念与区别

BFS 概念逻辑: 一层一层的挨个搜索,定义一个队列,然后 优先搜索第一级别节点,不匹配则将其邻居节点 压入队列,保持好子节点与父节点对应关系,直至循环找到目标节点。然后从子父节点对应关系中  计算出 最短路径

Dijkstra 概念逻辑:从节点列表中找到最便宜的节点,循环计算其邻居节点的开销,如若有比之前更低的开销则更新节点列表,更新子父节点关系,循环处理所有节点。最终从子父节点对应关系中统计出最短路径

3个散列表集合

* 1个存 节点以及开销(不可直接到达的节点,默认开销为无穷大)

* 1个存 节点对应 邻居以及开销

* 1个存 已遍历过的节点

4,JavaScript 代码 实现 狄克斯特拉算法 跟 广度优先算法

/**

* 狄克斯特拉算法

* 最短路径 + 加权重

*

* A 为起点

*

*

* Z 为终点

*

* 3个散列表集合

* 1个存 节点以及开销

* 1个存 节点对应 邻居以及开销

* 1个存 已遍历过的节点

* */

var wuxiongda = 99999;

//节点集合 以及各自开销

var allNode = {

    'B' : 5,

    'C' : wuxiongda,

    'D' : wuxiongda,

    'E' : 6,

    'F' : wuxiongda,

    'G' : wuxiongda,

    'Z' : wuxiongda,

};

//各节点的父节点  eg B的父节点是A,'B':A

var allParentNode = {

    'B' : 'A',

    'E' : 'A',

};

//各节点的 邻居节点以及开销 集合

var graphNodeObj = {

    'A' : {

        'B' : 5,

        'E' : 6,

    },

    'B' : {

        'C' : 16,

        'D' : 9,

    },

    'C' : {

        'B' : 16,

        'G' : 8,

        'Z' : 7,

    },

    'D' : {

        'B' : 9,

        'G' : 3,

        'Z' : 8,

    },

    'D' : {

        'B' : 9,

        'G' : 3,

        'Z' : 8,

    },

    'E' : {

        'F' : 3,

        'G' : 5,

    },

    'F' : {

        'E' : 3,

        'G' : 8,

    },

    'G' : {

        'C' : 1,

        'E' : 5,

        'F' : 8,

        'Z' : 4,

    },

};

//已遍历过的节点

var usedList = {};

//计算最短路径算法: 狄克斯特拉算法

function getShortest(){

    var node = getNewNode();//获取一个未遍历的 最便宜的 节点

    while(node != 'Z'){//非终点

        var cost = allNode[node];//该节点 的开销成本

        var neighbor = graphNodeObj[node];// 该节点的 邻居

        for(var neighNodeKey in neighbor){ //遍历邻居节点

            var new_cost = cost + neighbor[neighNodeKey]; //计算从起点 到 该邻居节点的 开销成本

            if(allNode[neighNodeKey] > new_cost){ //比较 若发现有较低开销出现时,则更新 节点散列表 里的节点开销 以及父节点散列表里的对应关系

                allNode[neighNodeKey] = new_cost; //更新节点散列表

                allParentNode[neighNodeKey] = node;//更新 父节点散列表

            }

        }

        usedList[node] = 1;//加入已遍历过的节点散列表

        node = getNewNode();

    }

}

//获取一个没用过的节点

function getNewNode(){

    var rtn = '';

    var cost = 99999;

    for(var k in allNode){

        if(k in usedList){

            continue;

        }

        if(allNode[k] < cost){

            cost = allNode[k];

            rtn = k;

        }

    }

    return rtn

}

function rtnRoute(list, Node){

    if(Node == 'A'){

        return 'A';

    }

    for(var n in list){

        if(n==Node){

            return n += '-->'+rtnRoute(list,list[n]);

        }

    }

}

//开始计算

getShortest();

//console.log(allNode);

//console.log(allParentNode);

//计算完毕后 整理路线

var finalRoute = '';

var finalNode = 'Z';

//rtnRoute(allParentNode, finalNode);

finalRoute = rtnRoute(allParentNode,finalNode);

console.log('最短路径 = '+finalRoute);

console.log('最短路径开销成本 = '+allNode[finalNode]);

var graphNodeObj_BFS = {

    'A' : {

        'B' : 5,

        'E' : 6,

    },

    'B' : {

        'C' : 16,

        'D' : 9,

    },

    'C' : {

        //'B' : 16,

        'G' : 8,

        'Z' : 7,

    },

    'D' : {

        //'B' : 9,

        'G' : 3,

        'Z' : 8,

    },

    'D' : {

        'B' : 9,

        'G' : 3,

        'Z' : 8,

    },

    'E' : {

        'F' : 3,

        'G' : 5,

    },

    'F' : {

        //'E' : 3,

        'G' : 8,

    },

    'G' : {

        //'C' : 1,

        //'E' : 5,

        //'F' : 8,

        'Z' : 4,

    },

};

//广度优先搜索算法

var allParentNode_BFS = {

    'B' : 'A',

    'E' : 'A',

};

var usedList_BFS = {};

function breadth_first_search(list, start, end){

    var graph = graphNodeObj_BFS[start];

    while(graph){

        var first = '';

        for(var n in graph){

            first = n;

            delete graph[n];

            break;

        }

        if(!(first in usedList_BFS)){

            if(first != end){

                // 该改点的邻居 压入 要搜索的队列  start  -- 相对于php则会很简单 直接合并数组即可 JS 则为对象

                var graphChild = graphNodeObj_BFS[first];

                if(graphChild){

                    for(var nchil in graphChild){

                        graph[nchil] = graphChild[nchil];

                        if(!(nchil in allParentNode_BFS)){ //不必多搜索重复节点-因为逻辑道理相同。 若重复节点搜索时 子节点父节点 散列表会混乱

                            allParentNode_BFS[nchil] = first;

                        }

                    }

                }

                // 该改点的邻居 压入 要搜索的队列  end

            }else{

                graph = {};

                console.log('找到了');

                break;

            }

        }

    }

}

breadth_first_search(graphNodeObj,'A','Z');

//console.log(allParentNode_BFS);

var finalRoute_BFS = '';

finalRoute_BFS = rtnRoute(allParentNode_BFS,'Z');

console.log('广度优先搜索计算出来最短路径 = '+finalRoute_BFS);

//console.log();

第八章 贪婪算法   

1,个人理解:

贪婪算法是一种近似算法。即 接近最终答案,大致解决问题的算法

贪婪算法:每步都采取最优的做法,即 每步都选择局部最优解,最终得到的就是全部最优解

2,集合覆盖问题,近似算法,贪婪算法

eg:覆盖所有州,多个电台,每个电台可能覆盖一个或多个州,计算出最优的选择电台。

方法:选出一个覆盖了最多未覆盖州的 电台,记录进去,然后再重复第一步,直至覆盖完所有的州

贪婪算法的运行时间为 O(n的2次方)      n为电台数

3,NP完全问题,最佳的做法是使用近似算法

/*

* 贪婪算法 - 近似完全算法

*

* 事例:

* 美国N个州,M个电台,每个电台可能覆盖1个或多个州,问:最终选最少的电台覆盖所有州

* **/

//所有的州

var allZhou = {

    a:1, b:1, c:1, d:1, e:1, f:1, g:1, h:1, i:1, j:1, k:1, l:1, m:1, n:1, o:1, p:1, q:1, r:1, s:1,t:1,

    u:1, v:1, w:1, x:1, y:1, z:1,

};

//所有的电台 -- 个电台对应的包含州

var allDj = {

    dj1 : ['q','w','e'],

    dj2 : ['r'],

    dj3 : ['t','y','u','o','p'],

    dj4 : ['a','s','f','a','p','v','o'],

    dj5 : ['d','f','g','h'],

    dj6 : ['j','a','k'],

    dj7 : ['l'],

    dj8 : ['z','x','c'],

    dj9 : ['v','b','n','l'],

    dj10 : ['q','a','z','m','d','p'],

    dj11 : ['r','o','s'],

    dj12 : ['i','d','l'],

    dj13 : ['e','k','v','r'],

    dj14 : ['u','p'],

};

var resultDj = [];//结果电台

var finishStatus = false;

while(Object.keys(allZhou).length > 0){

    var mostPoint = getMostPoint(allDj, allZhou);

    if(!mostPoint || mostPoint==''){

        finishStatus = true;

        break;

    }

    resultDj.push(mostPoint);

    for(var i in allDj[mostPoint]){

        delete allZhou[allDj[mostPoint][i]];

    }

    if(Object.keys(allZhou).length==0){

        finishStatus = true;

    }

}

if(finishStatus){

    console.log('执行结束');

    console.log('执行结果:');

    console.log(resultDj);

}

//查找覆盖最多的 点

function getMostPoint(obj1, obj2){

    var resultP = '';//结果点

    var resultPV = 0;//结果点覆盖的量

    for(var i in obj1){

        if(typeof obj1[i] == 'function'){ continue; }

        var tmpPV = 0;

        for(var i2 in obj1[i]){

            if(obj1[i][i2] in obj2){

                tmpPV += 1;

            }

        }

        if(tmpPV > resultPV){

            resultPV = tmpPV;

            resultP = i;

        }

    }

    return resultP;

}

第九章 动态规划 

1,个人理解

动态规划 是将问题 采用画网格的方式 计算出 最优最终的答案,网格行的排列顺序变化 对计算没有影响

2,最长公共子串

3,小结

在给定约束条件下优化某种指标时,动态规划很有用

问题可分解为离散子问题时,可用动态规划

每种动态规划解决方案都涉及 网格

单元格中的值 通常是要优化的值,每个单元格都是一个子问题

第十章 K最近邻算法  (KNN)

1,计算两点的距离,可使用 毕达哥拉斯 算法

2,回归

回归就是预测结果。

3,可适用于  创建推荐系统。

3.1,OCR -- 光学字符识别

即 计算机可识别照片中的内容,文字

语音识别,人脸识别 等也是基于KNN等简单理念的

一般来说,OCR算法提取线段,点,曲线 等特征

OCR的第一步是查看大量的数字图像并提取特征,这被称为 训练

4,小结:

KNN用于分类和回归,需要考虑最近的邻居

分类就是编组

回归就是预测结果(如数字)

能否挑选合适的特征 事关KNN算法的成败

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 简短点评:爱因斯坦说,“如果你不能把它解释给你外婆听,那么你就没有弄明白。”(You do not really ...
    威玲旺卡阅读 751评论 2 3
  • date: 2017-9-16 11:11:15title: 算法图解读书笔记 算法图解: http://www....
    daydaygo阅读 621评论 0 4
  • 7 狄克斯特拉算法 名字比较绕,其实就是解决带权重图的最快路径问题——或者说是地图中的最快公交路线选择问题。 7....
    废柴社阅读 987评论 0 0
  • 7 狄克斯特拉算法(带权的最短路径,地图路线中的算法)有点没看明白,下期整理。 6 广度优先搜索 广度优先搜索(b...
    废柴社阅读 542评论 0 0
  • 1.大O表示法是一种特殊的表示法,指出了算法的速度有多快。O(n) 小结: 二分查找的速度比简单查找快得多。 O ...
    niffler_阅读 397评论 0 0