circle clock

canvas实现的圆圈时钟,你看得出现在是几点么?

发表在 未分类 | 一条评论

javascript node sort

var sortNodes = function(nodes){
var list = [], llen = 0;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i],
nodeUp = node,
ans = [node];
while (nodeUp = nodeUp.parentNode) {
ans.unshift(nodeUp);
}
list[llen++] = ans;
}
list.sort(function(a, b){
var alen = a.length, blen = b.length;
if (a[alen - 1] == b[blen - 1]) {
return -1;
}
var minLen = alen < blen ? alen – 1 : blen – 1;
if (a[minLen] == b[minLen]) {
return alen – blen;
}
var latestAnPos = minLen – 1;
while (a[latestAnPos] != b[latestAnPos]) {
latestAnPos–;
}
latestAnPos++;

var aup = a[latestAnPos], bup = b[latestAnPos];

while (aup = aup.nextSibling) {
if (aup === bup) {
return -1
}
}
return 1;
});
var eachList, k = 0, ret = [];
while (eachList = list[k++]) {
ret[ret.length] = eachList.pop();
}
return ret;
}

发表在 未分类 | 4 条评论

矩阵连乘积

矩阵连乘积问题是对于给定n个矩阵{A1,A2,A3….,An},记An的行列分别为An_row、An_col,则有A1_col == A2_row, A2_col == A3_row…..,目的是要找出其最优运算次序(括号决定其运算次序),使得矩阵的连乘次数最少。矩阵连乘符合结合律,那么其加括号方式会影响最终的运算次序,比如给定A1A2A3A4,加括号方式共有五种:

(A1(A2(A3A4)))、(A1((A2A3)A4))、((A1A2)(A3A4))、((a1(a2a3))a4)、(((A1A2)A3)A4),对应的运算次序不同,连乘的次数也不同。

加括号对最终的连乘次数有很大影响,考虑这样的3个矩阵连乘:A1A2A3,其维度分别为10*100,100*5,5*50,如果按((A1A2)A3)加括号计算,那么最终连乘次数为10*100*5 + 10*5*50 = 7500,如果按(A1(A2A3))计算,结果为100*5*50 + 10*100*50 = 75000次。

矩阵连乘积问题适合用动态规划算法求解,其最优解具有最优子结构性质;考虑n个连乘矩阵,从第k个矩阵断开,那么其加括号方式是这样(A1A2…Ak)(Ak+1…An),从整体考虑,如果从k出断开是其最好的断开方式,连乘次数应为:断开得到的两个连乘矩阵(记为A何B),A和B各自的连乘数,再加上A*B的连乘数就是最终的连乘数;如果A,B各自的连乘数不是最优的,则k就不是从整体断开的最优位置,这是一个矛盾,故A,B自身的连乘数也应该是最优的。

矩阵连乘积问题具有子问题重叠性质。对于从n个矩阵{A1,A2,A3….,An},第一次的断开位置有n-1种可能,最优断开位置要从n-1种方式中筛选,要递归的对子问题继续进行筛选。而这些子问题可以自底向上的求解。设p[i][j]为Ai到Aj的最优连乘数,得到以下递归表达式:

        m[i][j] =  0                                   i == j
        min { p[i][j] + p[k+1][j] + Ai-1*Ak*pj         i < j

以下是js写的代码:

//共13个矩阵其行列分别为:40*22,22*15,......,16*41,41*24
var matrix = [40,22,15,25,10,20,15,45,18,68,16,41,24];
function MatrixChain(m){
    var len = m.length-1, p = [], splitPos = [];
    //初始化p
    for (var i = 0; i < len; i++) {
        p[i] = [];
        splitPos[i] = [];
        p[i][i] = 0; //对角线全部置为零
    }

    for (var i = 1; i < len; i++) { //遍历所有的连乘长度
        for (var j = 0, jlen = len - i; j < jlen; j++) { //遍历计算当前连乘长度为i的连乘积
            for (var k = j + 1; k <= j + i ; k++) { //遍历所有的断开位置
                var sum = p[j][k-1]+p[k][j+i]+m[j]*m[k]*m[j+i+1];
                if(sum < p[j][j+i] || !p[j][j+i]){ //筛选最小连乘积
                    p[j][j+i] = sum;
                    splitPos[j][j+i] = k;  //记录j到j+i之间的最优断开位置
                };
            }
        }
    }

    //以字符窜形式输出结果
    var a = 1;
    var marixStr = matrix.join(",").replace(/\d+/g,function(){
        return "A" + (a++).toString()
    }).split(",").slice(0,len);
    function getResult(l,r){  //利用splitPos数据递归输出结果
        if(Math.abs(r-l)<2)
           return ;
        var pos = splitPos[l][r];
        if (l < pos-1) {
            marixStr[l] = "(" + marixStr[l];
            marixStr[pos - 1] = marixStr[pos - 1] + ")";
        }
        if(r > pos){
            marixStr[pos] = "(" + marixStr[pos];
            marixStr[r] = marixStr[r] + ")";
        }
        getResult(l,pos-1);
        getResult(pos,r);
    }
    getResult(0,len-1);
    return marixStr.join("").replace(/(A\dA\d)/g,function(match){
        return  match.substring(0,2)+"*"+match.substring(2)
    });
}
//调用示例
alert(MatrixChain(matrix));


发表在 未分类 | 4 条评论

js: why [] == ![]

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

1. If Type(x) is the same as Type(y), then
a. If Type(x) is Undefined, return true.
b. If Type(x) is Null, return true.
c. If Type(x) is Number, then
i. If x is NaN, return false.
ii. If y is NaN, return false.
iii. If x is the same Number value as y, return true.
iv. If x is +0 and y is -0, return true.
v. If x is -0 and y is +0, return true.
vi. Return false. d. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
e. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
f. Return true if x and y refer to the same object. Otherwise, return false.
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
8. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
9. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
10. Return false.

so, [] == ![] -> [] == false -> Number([]) == false -> 0 == false, retuen true

发表在 未分类 | 留下评论

js钱额转中文大写

//最多处理到万亿
 function toChinesePrice(lownum){
     if (isNaN(lownum))
         return "";
     var num = "零壹贰叁肆伍陆柒捌玖";
     var wei = ["", "拾", "佰", "仟"], bigWei = ["元", "万", "亿","万"];
     var wei_offet = 0,  curWei = -1,  curN,  preZero = -2, ret = [];
     //处理整数部分
     var quotient = lownum, remainder, temQuo;
     while (quotient > 0) {
         remainder = quotient % 10;
         quotient = Math.floor(quotient / 10);
         curWei++;
         wei_offet = curWei % 4;
         if (wei_offet == 0)
             ret.unshift(bigWei[Math.floor(curWei / 4)]);
         if (remainder == 0) { //处理0的几种情况
             var temPreZero = preZero;
             preZero = curWei;
             if (wei_offet == 0) //如果这个0的权值对应的是这些位:"元","万","亿","万(亿)",则不需要输出零
                 continue;
             if (curWei != (temPreZero + 1)) //如果后面跟着的不是零,输出这个零
                 ret.unshift("零");
             continue;
         }
         ret.unshift(num.substring(remainder, remainder + 1) + wei[wei_offet]);
     }
     if (ret[0] == "壹拾") //处理头部的“壹拾”
         ret[0] = "拾";
     //处理小数部分
     var numStr = lownum.toString(), k = numStr.indexOf('.');
     if (k > -1) {
         var jiao = numStr.substring(k + 1, k + 2);
         jiao && jiao != "0" && ret.push(num[parseInt(jiao)] + "角");
         var fen = numStr.substring(k + 2, k + 3);
         fen && fen != "0" && ret.push(num[parseInt(fen)] + "分");
     }
     else   ret.push("整");
     return ret.join('');
 }

示例: toChinesePrice(2123456789111.02))

发表在 未分类 | 7 条评论

关于js伪数组的转换

伪数组是指domcument.links、document.images返回的HTMLCollection集,querySelectetAll方法的返回staticNodeList实例等。他们拥有length属性,可以通过下标访问,但并不真正的数组,通过下标访问元素在效率上较慢,不能调用Array原生的方法,故有必要对他们转换为真正的数组。
实际上除IE8以下的浏览器,其他都支持默认的伪数组转换,可通过调用Array的原生方法触发转换,如

var array = document.links;
array = Array.prototype.slice.call( array, 0);  //转换
//OR
var ret = [];
Array.prototype.push.apply( ret, array );

在IE下则只能过遍历一次处理了,参考Sizzle里伪数组转换的源代码:

var makeArray = function( array, results ) {
    array = Array.prototype.slice.call( array, 0 );
    if ( results ) {
        results.push.apply( results, array );
        return results;
    }
    return array;
};
// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
// Also verifies that the returned array holds DOM nodes
// (which is not the case in the Blackberry browser)
try {
    Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
// Provide a fallback method if it does not work
} catch( e ) {
    makeArray = function( array, results ) {
        var i = 0,
        ret = results || [];
        if ( toString.call(array) === "[object Array]" ) {
            Array.prototype.push.apply( ret, array );
        } else {
            if ( typeof array.length === "number" ) {
                for ( var l = array.length; i < l; i++ ) {
                    ret.push( array[i] );
                }
            } else {
                   for ( ; array[i]; i++ ) {
                       ret.push( array[i] );
                  }
            }
        }
        return ret;
    };
}


发表在 未分类 | 一条评论