Ruby's Louvre

每天学习一点点算法

导航

节点排序 2

对支持sourceIndex的HTML文档的节点重排,使用JK提供的思路,速度至少比单纯使用nodes.sort(function(a,b){return a.sourceIndex - b.sourceIndex})这种方式快两倍:

//灵感来自
//http://www.cnblogs.com/jkisjk/archive/2011/01/28/array_quickly_sortby.html
        var hasDuplicate = false;
        var sortBy = function(nodes){
          var result = [], array = [], n = nodes.length, i = n, node;
          while(node = nodes[--n]){
            (array[n] = new Number(~~node.sourceIndex))._ = node;
          }
          array.sort(function(a,b){
            if(a === b) hasDuplicate = true;
            return a - b ;
          });
          while( i )
            result[--i] = array[i]._;
          return result;
        }

但标准浏览器不支持这属性,在IE中,XML文档也没有此属性,这时就需要跟据节点的parentNode与nextSibling,但如果单单是两两比较,速度是提升不了的。因此我们就转而比较最近公共祖先的孩子们的顺序了。这时,算法的威力就体现出来了。这是第一版,根据某一朋友提供的LCA搞出来的东西,当然大体思路还是归功于JK大神。但实际效果不如意,比jQuery的那个sortOrder慢,估计问题出在求LCA上。

//根据这里JK提供的思路
//http://www.cnblogs.com/rubylouvre/archive/2011/01/28/1947286.html#2020900
var tick = 0, hasDuplicate = false;
var Rage = {
//form http://www.cnblogs.com/GrayZhang/archive/2010/12/29/find-closest-common-parent.html
	getLCA:function(nodes){
		var hash = {}, i = 0,
			attr = "data-find"+(++tick),
			length = nodes.length,
			node,
			parent,
			counter = 0,
			uuid;
		while(node = nodes[i++]){
			parent = node;
			while(parent){
				if(parent.nodeType === 1){
					break;
				}
				uuid = parent.getAttribute(attr);
				if(!uuid){
					uuid = "_" + (++counter);
					parent.setAttribute(attr,uuid);
					hash[uuid] = {node:parent,count:1};
				}else{
					hash[uuid].count ++;
				}
				parent = parent.parentNode;
			}
		}
		for(var i in hash){
			if(hash[i].count === length){
				return hash[i].node;
			}
		}
	},
	getList : function(nodes,parent){//获取当前元素到最近公共祖先间的所有祖先,包括自己
		var list = [];
		while(node){
			if(node === parent){
				break;
			}
			list.unshift(node);
			node = node.parentNode;
		}
		return list;
	},
	getLists : function(){
		var lists = [], getList = Rage.getList, i=0, node, list;
		while(node = nodes[i++]){
			list = getList(node,parent);
			if(list.length){
				lists[ lists.length ] = list;
		    }
		}
		return lists;
	},
         sortList : function(a,b){
            var n = Math.min(a.length,b.length),ap,bp;
            for(var i=0; i < n; i++){
              ap = a[i],bp = b[i]
              if(ap !== bp){
                while(ap = ap.nextSibling){
                  if(ap === bp){
                    return -1
                  }
                }
                return 1
              }
            }
            return a.length-b.length;
     },
    uniqueSort : function(nodes){
    	var length = nodes.length;
    	var LCA = Rage.getLCA(nodes);
    	var lists = Rage.getLists(nodes,LCA);
    	lists.sort(Rage.sortList);
    	var list, i = 0, result = [];
    	while(list = lists[i++]){
    		result[result.length] list.pop();
    	}
    	if(result.length !== length){
    		result.unshift(LAC);
    		if(result.length != length){
    			hasDuplicate = true;
    		}
    	}
    	return result;
    }
}

下面是第二版,经过改进,终于比jQuery的那个快上三倍(测试对象为拥有260多个节点的文档)

        var hasDuplicate = false;
        var Rage = {

          getList : function(node){
            var list = [];
            while(node){
              if(node.nodeType === 9){
                break;
              }
              list.unshift(node);
              node = node.parentNode;
            }
            return list;
          },
          getLists : function(nodes){
            var lists = [], getList = Rage.getList, i=0, node;
            while(node = nodes[i++]){
              lists[ lists.length ] = getList(node);
            }
            return lists;
          },
          sliceList : function(lists,num){
            var result = [], i = 0, list;
            while(list = lists[i++]){
              list = list.slice(num);
              if(list.length){
                result[ result.length ] = list;
              }
            }
            return result;
          },
          sortList : function(a,b){
            var n = Math.min(a.length,b.length),ap,bp;
            for(var i=0; i < n; i++){
              ap = a[i],bp = b[i]
              if(ap !== bp){
                while(ap = ap.nextSibling){
                  if(ap === bp){
                    return -1
                  }
                }
                return 1
              }
            }
            return a.length-b.length;
          },
          uniqueSort : function(nodes){
            var length = nodes.length;
            var lists = Rage.getLists(nodes);
            lists.sort(function(a,b){
              return a.length - b.length;
            });
            var depth = lists[0].length, length = lists.length, parent, cut, ii = 0;
            for(var i =0; i < depth; i++){
              parent = lists[0][i];
              cut = true;
              for(var j = 1;j <  length; j++){
                if(parent !== lists[j][i]){
                  cut = false;
                  break;
                }
              }
              if(cut){
                ii++
              }else{
                break;
              }
            }
            var LCA = lists[0][ii-1];
            lists = Rage.sliceList(lists,ii);
            lists.sort(Rage.sortList);
            var list, i = 0, result = [];
            while(list = lists[i++]){
              result[result.length] = list.pop();
            }
             
            if(result.length !== length){
              result.unshift(LCA);
              if(result.length != length){
                hasDuplicate = true;
              }
            }
            return result;
          }
        }

posted on 2011-01-30 16:09  司徒正美  阅读(2282)  评论(2编辑  收藏  举报