Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

节点排序 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;
  }
}

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(2301)  评论(2编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2010-01-30 Ext的DomQuery学习笔记
点击右上角即可分享
微信分享提示