原文出处,未经作者许可

2019-09-11 作者:小鱼儿主页高手论坛   |   浏览(130)

别人家的面试题:统计“1”的个数

2016/05/27 · JavaScript · 5 评论 · Javascript, 算法

本文作者: 伯乐在线 - 十年踪迹 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

小胡子哥 @Barret李靖 给我推荐了一个写算法刷题的地方 leetcode.com,没有 ACM 那么难,但题目很有趣。而且据说这些题目都来源于一些公司的面试题。好吧,解解别人公司的面试题其实很好玩,既能整理思路锻炼能力,又不用担心漏题 ╮(╯▽╰)╭。

长话短说,让我们来看一道题:

HTTPS 到底加密了什么?

2018/07/03 · 基础技术 · HTTPS

原文出处: 云叔_又拍云   

关于 HTTP 和 HTTPS 这个老生常谈的话题,我们之前已经写过很多文章了,比如这篇《从HTTP到HTTPS再到HSTS》,详细讲解了 HTTP 和 HTTPS 的进化之路,对的没错,就是 HTTP 兽进化 HTTPS 兽。

图片 1

那么今天我们主要聊一聊 HTTPS 到底加密了些什么内容。

先跟大家讲个故事,我初恋是在初中时谈的,我的后桌。那个时候没有手机这类的沟通工具,上课交流有三宝,脚踢屁股、笔戳后背以及传纸条,当然我只能是那个屁股和后背。

说实话传纸条真的很危险,尤其是这种早恋的纸条,被抓到就是一首《凉凉》。

于是我和我的小女朋友就商量一下加密这个小纸条上面的数据,这样就算被班主任抓到她也奈何不了我们!

我们用将英文字母和数字一一对应,组成一个密码本,然后在小纸条上写上数字,要将他翻译成对应的字母,在拼成拼音才能知道这串数字意思。

上面就是最初我坎坷的感情史。

后来等我长大了,才知道这是回不去的美好。如果给我一个机会,我愿意……啊呸,跑偏了,等长大了才知道,这个就是现在网站数据传输中的 HTTPS。

十大经典排序算法

2016/09/19 · 基础技术 · 7 评论 · 排序算法, 算法

本文作者: 伯乐在线 - Damonare 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

主流浏览器图片反防盗链方法总结

2018/04/24 · HTML5 · 防盗链

原文出处: Myths   

统计“1”的个数

给定一个非负整数 num,对于任意 i,0 ≤ i ≤ num,计算 i 的值对应的二进制数中 “1” 的个数,将这些结果返回为一个数组。

例如:

当 num = 5 时,返回值为 [0,1,1,2,1,2]。

/** * @param {number} num * @return {number[]} */ var countBits = function(num) { //在此处实现代码 };

1
2
3
4
5
6
7
/**
* @param {number} num
* @return {number[]}
*/
var countBits = function(num) {
    //在此处实现代码
};

多了 SSL 层的 HTTP 协议

简而言之,HTTPS 就是在 HTTP 下加入了 SSL 层,从而保护了交换数据隐私和完整性,提供对网站服务器身份认证的功能,简单来说它就是安全版的 HTTP。

现在随着技术的发展,TLS 得到了广泛的应用,关于 SSL 与 TLS 的差别,我们不用在意,只要知道 TLS 是 SSL 的升级版本就好。
图片 2
一般来说,HTTPS 主要用途有三个:一是通过证书等信息确认网站的真实性;二是建立加密的信息通道;三是数据内容的完整性。
图片 3

上文为又拍云官网,我们可以通过点击浏览器地址栏锁标志来查看网站认证之后的真实信息,SSL证书保证了网站的唯一性与真实性。

那么加密的信息通道又加密了哪些信息呢?

签发证书的 CA 中心会发布一种权威性的电子文档——数字证书,它可以通过加密技术(对称加密与非对称加密)对我们在网上传输的信息进行加密,比如我在 Pornhub 上输入:

账号:cbssfaw

密码:123djaosid

可是这个数据被黑客拦截盗窃了,那么加密后,黑客得到的数据可能就是这样的:

账号:çµø…≤¥ƒ∂ø†®∂˙∆¬

密码:∆ø¥§®†ƒ©®†©˚¬

图片 4

最后一个就是验证数据的完整性,当数据包经过无数次路由器转发后会发生数据劫持,黑客将数据劫持后进行篡改,比如植入羞羞的小广告。开启HTTPS后黑客就无法对数据进行篡改,就算真的被篡改了,我们也可以检测出问题。

前言

读者自行尝试可以想看源码戳这,博主在github建了个库,读者可以Clone下来本地尝试。此博文配合源码体验更棒哦

  • 这世界上总存在着那么一些看似相似但有完全不同的东西,比如雷锋和雷峰塔,小平和小平头,玛丽和马里奥,Java和javascript….当年javascript为了抱Java大腿恬不知耻的让自己变成了Java的干儿子,哦,不是应该是跪舔,毕竟都跟了Java的姓了。可如今,javascript来了个咸鱼翻身,几乎要统治web领域,Nodejs,React Native的出现使得javascript在后端和移动端都开始占有了一席之地。可以这么说,在Web的江湖,JavaScript可谓风头无两,已经坐上了头把交椅。
  • 在传统的计算机算法和数据结构领域,大多数专业教材和书籍的默认语言都是Java或者C/C ,O’REILLY家倒是出了一本叫做《数据结构与算法javascript描述》的书,但不得不说,不知道是作者吃了shit还是译者根本就没校对,满书的小错误,这就像那种无穷无尽的小bug一样,简直就是让人有种嘴里塞满了shit的感觉,吐也不是咽下去也不是。对于一个前端来说,尤其是笔试面试的时候,算法方面考的其实不难(十大排序算法或是和十大排序算法同等难度的),但就是之前没用javascript实现过或是没仔细看过相关算法的原理,导致写起来浪费很多时间。所以撸一撸袖子决定自己查资料自己总结一篇博客等用到了直接看自己的博客就OK了,正所谓靠天靠地靠大牛不如靠自己(ˉ(∞)ˉ)。
  • 算法的由来:9世纪波斯数学家提出的:“al-Khowarizmi”就是下图这货(感觉重要数学元素提出者貌似都戴了顶白帽子),开个玩笑,阿拉伯人对于数学史的贡献还是值得人敬佩的。
    图片 5

前言

还记得之前写的那个无聊的插件,前一段时间由于豆瓣读书增加了防盗链策略使得我们无法直接引用他们的图片,使得我这个小插件无法工作。本以为是一个很简单的问题,但是没想到这个小问题硬是让我改了五六遍才改好,可以说是非常的蠢了。总结一下自己犯傻的原因,还是由于自己懒得去深入研究,谷歌百度了问题就直接把方案拿来用了,浅尝辄止人云亦云,解决了表面的问题而没有深入的总结。当然,从另外一个方面讲,我也是初步领会到了前端程序员面对要兼容各种浏览器的需求时头有多大了。

解题思路

这道题咋一看还挺简单的,无非是:

  • 实现一个方法 countBit,对任意非负整数 n,计算它的二进制数中“1”的个数
  • 循环 i 从 0 到 num,求 countBit(i),将值放在数组中返回。

JavaScript中,计算 countBit 可以取巧:

function countBit(n){ return n.toString(2).replace(/0/g,"").length; }

1
2
3
function countBit(n){
    return n.toString(2).replace(/0/g,"").length;
}

上面的代码里,我们直接对 n 用 toString(2) 转成二进制表示的字符串,然后去掉其中的0,剩下的就是“1”的个数。

然后,我们写一下完整的程序:

版本1

function countBit(n){ return n.toString(2).replace(/0/g,'').length; } function countBits(nums){ var ret = []; for(var i = 0; i <= nums; i ){ ret.push(countBit(i)); } return ret; }

1
2
3
4
5
6
7
8
9
10
11
function countBit(n){
   return n.toString(2).replace(/0/g,'').length;
}
 
function countBits(nums){
   var ret = [];
   for(var i = 0; i <= nums; i ){
       ret.push(countBit(i));
   }
   return ret;
}

上面这种写法十分讨巧,好处是 countBit 利用 JavaScript 语言特性实现得十分简洁,坏处是如果将来要将它改写成其他语言的版本,就有可能懵B了,它不是很通用,而且它的性能还取决于 Number.prototype.toString(2) 和 String.prototype.replace 的实现。

所以为了追求更好的写法,我们有必要考虑一下 countBit 的通用实现法。

我们说,求一个整数的二进制表示中 “1” 的个数,最普通的当然是一个 O(logN) 的方法:

function countBit(n){ var ret = 0; while(n > 0){ ret = n & 1; n >>= 1; } return ret; }

1
2
3
4
5
6
7
8
function countBit(n){
    var ret = 0;
    while(n > 0){
        ret = n & 1;
        n >>= 1;
    }
    return ret;
}

所以我们有了版本2

这么实现也很简洁不是吗?但是这么实现是否最优?建议此处思考10秒钟再往下看。


对称加密与非对称加密

对称加密

对称加密是指加密与解密的使用同一个密钥的加密算法。小编初中的时候传纸条使用了同一套加密密码,所以我用的加密算法就是对称加密算法。

目前常见的加密算法有:DES、AES、IDEA 等

非对称加密

非对称加密使用的是两个密钥,公钥与私钥,我们会使用公钥对网站账号密码等数据进行加密,再用私钥对数据进行解密。这个公钥会发给查看网站的所有人,而私钥是只有网站服务器自己拥有的。

目前常见非对称加密算法:RSA,DSA,DH等。

正文

问题

问题很简单,就是我希望在自己的页面里用`来引用其他网站的一张图片,但是他的网站设置了防盗链的策略,会在后台判断请求的Referrer属性是不是来自于一个非本域名的网站,如果来源不是本域名就返回403 forbidden`。我的目的就是用最方便的方法使得我的页面能够不受他的防盗链策略的影响。

更快的 countBit

上一个版本的 countBit 的时间复杂度已经是 O(logN) 了,难道还可以更快吗?当然是可以的,我们不需要去判断每一位是不是“1”,也能知道 n 的二进制中有几个“1”。

有一个诀窍,是基于以下一个定律:

  • 对于任意 n, n ≥ 1,有如下等式成立:

countBit(n & (n - 1)) === countBit(n) - 1

1
countBit(n & (n - 1)) === countBit(n) - 1

这个很容易理解,大家只要想一下,对于任意 n,n – 1 的二进制数表示正好是 n 的二进制数的最末一个“1”退位,因此 n & n – 1 正好将 n 的最末一位“1”消去,例如:

  • 6 的二进制数是 110, 5 = 6 – 1 的二进制数是 101,6 & 5 的二进制数是 110 & 101 == 100
  • 88 的二进制数是 1011000,87 = 88 – 1 的二进制数是 1010111,88 & 87 的二进制数是 1011000 & 1010111 == 1010000

于是,我们有了一个更快的算法:

版本3

function countBit(n){ var ret = 0; while(n > 0){ ret ; n &= n - 1; } return ret; } function countBits(nums){ var ret = []; for(var i = 0; i <= nums; i ){ ret.push(countBit(i)); } return ret; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function countBit(n){
    var ret = 0;
    while(n > 0){
        ret ;
        n &= n - 1;
    }
    return ret;
}
 
function countBits(nums){
   var ret = [];
   for(var i = 0; i <= nums; i ){
       ret.push(countBit(i));
   }
   return ret;
}

上面的 countBit(88) 只循环 3 次,而“版本2”的 countBit(88) 却需要循环 7 次。

优化到了这个程度,是不是一切都结束了呢?从算法上来说似乎已经是极致了?真的吗?再给大家 30 秒时间思考一下,然后再往下看。


HTTPS=数据加密 网站认证 完整性验证 HTTP

通过上文,我们已经知道,HTTPS 就是在 HTTP 传输协议的基础上对网站进行认证,给予它独一无二的身份证明,再对网站数据进行加密,并对传输的数据进行完整性验证。

HTTPS 作为一种加密手段不仅加密了数据,还给了网站一张身份证。

如果让我回到十年前,那么我一定会这样跟我的女朋友传纸条:

先准备一张独一无二的纸条,并在上面签上我的大名,然后用只有我女朋友可以解密的方式进行数据加密,最后写完后,用胶水封起来,防止隔壁桌的小王偷看修改小纸条内容。

 

1 赞 收藏 评论

图片 6

排序算法说明

(1)排序的定义:对一序列对象根据某个关键字进行排序;

输入:n个数:a1,a2,a3,…,an
输出:n个数的排列:a1’,a2’,a3’,…,an’,使得a1’

再讲的形象点就是排排坐,调座位,高的站在后面,矮的站在前面咯。

(3)对于评述算法优劣术语的说明

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;

内排序:所有排序操作都在内存中完成;
外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;

时间复杂度: 一个算法执行所耗费的时间。
空间复杂度: 运行完一个程序所需内存的大小。

关于时间空间复杂度的更多了解请戳这里,或是看书程杰大大编写的《大话数据结构》还是很赞的,通俗易懂。

(4)排序算法图片总结(图片来源于网络):

排序对比:

图片 7

图片名词解释:
n: 数据规模
k:“桶”的个数
In-place: 占用常数内存,不占用额外内存
Out-place: 占用额外内存

排序分类:

图片 8

解决方案

countBits 的时间复杂度

考虑 countBits, 上面的算法:

  • “版本1” 的时间复杂度是 O(N*M),M 取决于 Number.prototype.toString 和 String.prototype.replace 的复杂度。
  • “版本2” 的时间复杂度是 O(N*logN)
  • “版本3” 的时间复杂度是 O(N*M),M 是 N 的二进制数中的“1”的个数,介于 1 ~ logN 之间。

上面三个版本的 countBits 的时间复杂度都大于 O(N)。那么有没有时间复杂度 O(N) 的算法呢?

实际上,“版本3”已经为我们提示了答案,答案就在上面的那个定律里,我把那个等式再写一遍:

countBit(n & (n - 1)) === countBit(n) - 1

1
countBit(n & (n - 1)) === countBit(n) - 1

也就是说,如果我们知道了 countBit(n & (n - 1)),那么我们也就知道了 countBit(n)

而我们知道 countBit(0) 的值是 0,于是,我们可以很简单的递推:

版本4

function countBits(nums){ var ret = [0]; for(var i = 1; i <= nums; i ){ ret.push(ret[i & i - 1] 1); } return ret; }

1
2
3
4
5
6
7
function countBits(nums){
   var ret = [0];
   for(var i = 1; i <= nums; i ){
       ret.push(ret[i & i - 1] 1);
   }
   return ret;
}

原来就这么简单,你想到了吗 ╮(╯▽╰)╭

以上就是所有的内容,简单的题目思考起来很有意思吧?程序员就应该追求完美的算法,不是吗?

这是 leetcode 算法面试题系列的第一期,下一期我们讨论另外一道题,这道题也很有趣:判断一个非负整数是否是 4 的整数次方,别告诉我你用循环,想想更巧妙的办法吧~

打赏支持我写出更多好文章,谢谢!

打赏作者

1.冒泡排序(Bubble Sort)

好的,开始总结第一个排序算法,冒泡排序。我想对于它每个学过C语言的都会了解的吧,这可能是很多人接触的第一个排序算法。

后台预下载

预下载是最直观的一种方法,既然不能直接引用,那我就先后台下载下来,然后将图片链接到下载后的图片即可。这个方法还是比较稳妥的,图片下载下来就是自己的了,不会再受人限制。不过这总有种侵犯知识产权的感觉,而且每张图片都要后台先下载,逻辑处理起来还是有点麻烦的;而且对于那种纯静态页面,没有后台程序供我们发挥,这也就无法实现了。

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

图片 9 图片 10

3 赞 8 收藏 5 评论

(1)算法描述

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

第三方代理

第三方代理其实算是后台与下载的升级版,其实就是将下载图片的这个过程交给第三方的网站。一个非常好用的代理是images.weserv.nl,我们可以直接将自己需要“盗链”的图片写在请求中即可。我们甚至可以指定一些简单的图片处理参数,让代理帮我们处理。
比如我想盗链https://foo.com/foo.jpg,并且将图片宽度设置成100,我们就可以直接这样引用:

<img src="" />

1
<img src="https://images.weserv.nl/?url=foo.com/foo.jpg&w=100" />

这还是很方便的,不过美中不足的是这个国外的网站在国内的访问速度似乎有点慢,有时候甚至还会被墙,这就有点尴尬了。

关于作者:十年踪迹

图片 11

月影,奇舞团团长,热爱前端开发,JavaScript 程序猿一枚,能写代码也能打杂卖萌说段子。 个人主页 · 我的文章 · 14 ·     

图片 12

(2)算法描述和实现

具体算法描述如下:

  • <1>.比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • <2>.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • <3>.针对所有的元素重复以上的步骤,除了最后一个;
  • <4>.重复步骤1~3,直到排序完成。

JavaScript代码实现:

JavaScript

function bubbleSort(arr) { var len = arr.length; for (var i = 0; i < len; i ) { for (var j = 0; j < len - 1 - i; j ) { if (arr[j] > arr[j 1]) { //相邻元素两两对比 var temp = arr[j 1]; //元素交换 arr[j 1] = arr[j]; arr[j] = temp; } } } return arr; } var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]; console.log(bubbleSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len; i ) {
        for (var j = 0; j < len - 1 - i; j ) {
            if (arr[j] > arr[j 1]) {        //相邻元素两两对比
                var temp = arr[j 1];        //元素交换
                arr[j 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

 

改进冒泡排序: 设置一标志性变量pos,用于记录每趟排序中最后一次进行交换的位置。由于pos位置之后的记录均已交换到位,故在进行下一趟排序时只要扫描到pos位置即可。

改进后算法如下:

JavaScript

function bubbleSort2(arr) { console.time('改进后冒泡排序耗时'); var i = arr.length-1; //初始时,最后位置保持不变 while ( i> 0) { var pos= 0; //每趟开始时,无记录交换 for (var j= 0; j< i; j ) if (arr[j]> arr[j 1]) { pos= j; //记录交换的位置 var tmp = arr[j]; arr[j]=arr[j 1];arr[j 1]=tmp; } i= pos; //为下一趟排序作准备 } console.timeEnd('改进后冒泡排序耗时'); return arr; } var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]; console.log(bubbleSort2(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function bubbleSort2(arr) {
    console.time('改进后冒泡排序耗时');
    var i = arr.length-1;  //初始时,最后位置保持不变
    while ( i> 0) {
        var pos= 0; //每趟开始时,无记录交换
        for (var j= 0; j< i; j )
            if (arr[j]> arr[j 1]) {
                pos= j; //记录交换的位置
                var tmp = arr[j]; arr[j]=arr[j 1];arr[j 1]=tmp;
            }
        i= pos; //为下一趟排序作准备
     }
     console.timeEnd('改进后冒泡排序耗时');
     return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort2(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

 

传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,我们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法一次可以得到两个最终值(最大者和最小者) , 从而使排序趟数几乎减少了一半。

改进后的算法实现为:

JavaScript

function bubbleSort3(arr3) { var low = 0; var high= arr.length-1; //设置变量的初始值 var tmp,j; console.time('2.改进后冒泡排序耗时'); while (low < high) { for (j= low; j< high; j) //正向冒泡,找到最大者 if (arr[j]> arr[j 1]) { tmp = arr[j]; arr[j]=arr[j 1];arr[j 1]=tmp; } --high; //修改high值, 前移一位 for (j=high; j>low; --j) //反向冒泡,找到最小者 if (arr[j]<arr[j-1]) { tmp = arr[j]; arr[j]=arr[j-1];arr[j-1]=tmp; } low; //修改low值,后移一位 } console.timeEnd('2.改进后冒泡排序耗时'); return arr3; } var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]; console.log(bubbleSort3(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function bubbleSort3(arr3) {
    var low = 0;
    var high= arr.length-1; //设置变量的初始值
    var tmp,j;
    console.time('2.改进后冒泡排序耗时');
    while (low < high) {
        for (j= low; j< high; j) //正向冒泡,找到最大者
            if (arr[j]> arr[j 1]) {
                tmp = arr[j]; arr[j]=arr[j 1];arr[j 1]=tmp;
            }
        --high;                 //修改high值, 前移一位
        for (j=high; j>low; --j) //反向冒泡,找到最小者
            if (arr[j]<arr[j-1]) {
                tmp = arr[j]; arr[j]=arr[j-1];arr[j-1]=tmp;
            }
         low;                  //修改low值,后移一位
    }
    console.timeEnd('2.改进后冒泡排序耗时');
    return arr3;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort3(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

三种方法耗时对比:

图片 13

由图可以看出改进后的冒泡排序明显的时间复杂度更低,耗时更短了。读者自行尝试可以戳这,博主在github建了个库,读者可以Clone下来本地尝试。此博文配合源码体验更棒哦~~~

冒泡排序动图演示:

图片 14

(3)算法分析

  • 最佳情况:T(n) = O(n)

当输入的数据已经是正序时(都已经是正序了,为毛何必还排序呢….)

  • 最差情况:T(n) = O(n2)

当输入的数据是反序时(卧槽,我直接反序不就完了….)

  • 平均情况:T(n) = O(n2)

删除Header中的Referrer

相比上面两种折腾的方法,如果能直接修改Referrer,那不就省了很多事了么。但是事实上这里的配置还是有挺多坑的,方法也有很多种,一不小心就会跟我一样踩了一遍又一遍。

2.选择排序(Selection Sort)

表现最稳定的排序算法之一(这个稳定不是指算法层面上的稳定哈,相信聪明的你能明白我说的意思2333),因为无论什么数据进去都是O(n²)的时间复杂度…..所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。

添加meta标签

一种方法是给页面添加一个meta标签,在meta标签里指定referrer的值,比如`。网上可以查到各种奇奇怪怪的值,其实我总结了来源于两个地方。 一个是来自[whatwg](https://wiki.whatwg.org/wiki/Meta_referrer)的标准。他给meta标签的referrer属性定义了四个值:never,always,origin,default。如果需要关闭referrer,就将referrer的值设置成”never”。这个标准还是比较老的,而且在他的主页上也明确写了”This document is obsolete.”。不过据我调研,或许正是由于这个标准比较老,反而导致绝大多数浏览器对他的支持都很好,因祸得福蛤蛤。 另外一个是来自[MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta)的标准。他给meta标签的referrer属性定义了五个值,如果要关闭referrer,就将它的值设置成no-referrer`。
不过我们需要注意的是,meta标签添加的位置也很重要,有的浏览器能够识别非head标签中的meta标签,有的就不行。在实际使用的时候还要小心,这一点下文会有一个更具体的比较。

(1)算法简介

选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

添加ReferrerPolicy属性

添加meta标签相当于对文档中的所有链接都取消了referrer,而ReferrerPolicy则更精确的指定了某一个资源的referrer策略。关于这个策略的定义可以参照MDN。比如我想只对某一个图片取消referrer,如下编写即可:

<img src="xxxx.jpg" referrerPolicy="no-referrer" />

1
<img src="xxxx.jpg"  referrerPolicy="no-referrer" />

(2)算法描述和实现

n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  • <1>.初始状态:无序区为R[1..n],有序区为空;
  • <2>.第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i 1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  • <3>.n-1趟结束,数组有序化了。

Javascript代码实现:

JavaScript

function selectionSort(arr) { var len = arr.length; var minIndex, temp; console.time('选择排序耗时'); for (var i = 0; i < len - 1; i ) { minIndex = i; for (var j = i 1; j < len; j ) { if (arr[j] < arr[minIndex]) { //寻找最小的数 minIndex = j; //将最小数的索引保存 } } temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } console.timeEnd('选择排序耗时'); return arr; } var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]; console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    console.time('选择排序耗时');
    for (var i = 0; i < len - 1; i ) {
        minIndex = i;
        for (var j = i 1; j < len; j ) {
            if (arr[j] < arr[minIndex]) {     //寻找最小的数
                minIndex = j;                 //将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    console.timeEnd('选择排序耗时');
    return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

选择排序动图演示:

图片 15

浏览器支持对比

上面我们讲了两种取消referrer头信息的方法,但其实这却对应了五种写法,我们来看下面的对比表:

NOTHING META IN HEAD REFERRER=NEVER META IN HEAD REFERRER=NO-REFERRER META REFERRER=NEVER META REFERRER=NO-REFERRER IMG REFERRERPOLICY=NO-REFERRER
Chrome N Y Y Y Y Y
Firefox N Y Y N N Y
Edge/IE N Y N Y N N

可以看出Chrome浏览器对各种写法都支持的最好,棒棒哒;Firefox支持所有标准的写法,但是不支持没有写在head标签中的meta标签;Edge/IE则不支持MDN里定义的”no-referrer”配置项,果然是个古董。。。

总的来说,保证最佳效果的最简单的写法就是添加一个meta标签``,这样就不用考虑浏览器的差别了,虽然这种写法并不被官方推荐(主要还是要迁就IE这个古董,放弃了理论上更为正确的标准)。

(3)算法分析

  • 最佳情况:T(n) = O(n2)
  • 最差情况:T(n) = O(n2)
  • 平均情况:T(n) = O(n2)

参考资料

whatwg
MDN
使用Referer Meta标签控制referer

2 赞 2 收藏 评论

图片 16

3.插入排序(Insertion Sort)

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。当然,如果你说你打扑克牌摸牌的时候从来不按牌的大小整理牌,那估计这辈子你对插入排序的算法都不会产生任何兴趣了…..

本文由小鱼儿玄机30码发布于小鱼儿主页高手论坛,转载请注明出处:原文出处,未经作者许可

关键词: 小鱼儿玄机30码