如何使此代码运行得更快

时间:2017-04-19 19:22:59

标签: javascript binary-search-tree avl-tree

数组包含数字,未分类。它的长度可能大到100000。 我需要计算每个数字右侧的较小数字。

示例:

    100, 10, 10, 10, 10]should return 4, 0, 0, 0, 0

    1, 2, 3             should return 0, 0, 0

    1, 2, 0             should return 1, 1, 0

    1, 2, 1             should return 0, 1, 0

任务:我要完成100项测试,目标是在12ms内完成所有测试。 以下函数是AVL Tree实现。它完成了工作但速度不够快。

它在12秒内完成了100分中的48分。

===============

function smaller(arr) {
  function TreeNode(key) {
    this.key    = key;
    this.size   = 1;
    this.height = 1;
    this.left   = null;
    this.right  = null;
    this.count  = 1;
  }
  var size        = (node) => node == null ? 0 : node.size + node.count - 1;
  var height      = (node) => node == null ? 0 : node.height;
  var getBalance  = (node) => node == null ? 0 : height(node.left) - height(node.right);

  var rotateRight = function(root) {
    var newRoot      = root.left;
    var rightSubTree = newRoot.right;
    newRoot.right    = root;
    root.left        = rightSubTree;
    root.height      = Math.max(height(root.left), height(root.right)) + 1;
    newRoot.height   = Math.max(height(newRoot.left), height(newRoot.right)) + 1;
    root.size        = size(root.left) + size(root.right) + 1;
    newRoot.size     = size(newRoot.left) + size(newRoot.right) + 1;
    return newRoot;
  }
  var rotateLeft = function(root) {
    var newRoot     = root.right;
    var leftSubTree = newRoot.left;
    newRoot.left    = root;
    root.right      = leftSubTree;
    root.height     = Math.max(height(root.left), height(root.right)) + 1;
    newRoot.height  = Math.max(height(newRoot.left), height(newRoot.right)) + 1;
    root.size       = size(root.left) + size(root.right) + 1;
    newRoot.size    = size(newRoot.left) + size(newRoot.right) + 1;
    return newRoot;
  }
  var insertIntoAVL = function(node, key, count, index) {
    if(node == null)return new TreeNode(key);
    if(key  <  node.key){node.left    = insertIntoAVL(node.left, key, count, index);}
    if(key  == node.key){count[index] = count[index] + size(node.left); node.count++; return node;}
    if(key  >  node.key){node.right   = insertIntoAVL(node.right, key, count, index); count[index] = count[index] + size(node.left) + node.count;}
    node.height = Math.max(height(node.left), height(node.right)) + 1;
    node.size   = size(node.left) + size(node.right) + 1;
    var balance = getBalance(node);
    if(balance >  1 && key < node.left.key ){return rotateRight(node);}
    if(balance < -1 && key > node.right.key){return rotateLeft(node);}
    if(balance >  1 && key > node.left.key ){node.left = rotateLeft(node.left); return rotateRight(node);}
    if(balance < -1 && key < node.right.key){node.right = rotateRight(node.right); return rotateLeft(node);}
    return node;
  }
  var countSmallerOnRight = function( arr ) {
    var result = new Array(arr.length).fill(0);
    var root   = null;
    for (var i = arr.length; i--;){root = insertIntoAVL(root, arr[i], result, i);}
    return result;
  }
  return countSmallerOnRight(arr);
  }

=================

我有第二种方法,速度更快,但仍然不够快。 它在12毫秒内完成了84个中的84个;

=================

function smaller(arr) {
  function BSTNode(val, count) {
    this.dup   = 1;
    this.left  = null;
    this.right = null;
    this.val   = val;
    this.count = count;
  }
  var countSmaller = arr => {
    var result = [];
    var root   = null;
    for (var i = arr.length; i--;){root = insert(root, arr[i], result, 0, i);}
    return result;
  }
  var insert = (root, num, result, sum, i) => {
    if (root == null) {
      root = new BSTNode(num, 0);
      result[i] = sum;
      return root;
    } else if (root.val == num) {
      root.dup++;
      result[i] = sum + root.count;
      return root;
    } else if (root.val > num) {
      root.count++;
      root.left = insert(root.left, num, result, sum, i);
    } else {
      root.right = insert(root.right, num, result, sum + root.count + root.dup, i);
    }
    return root;
  }
  return countSmaller(arr);
}

=================

我想了解为什么他们没有实现这个目标,我该如何改进它们。

3 个答案:

答案 0 :(得分:0)

这很不错,但我不知道(代码大战?)挑战是什么,所以我无法测试它。不使用树木。

mailTo.setBody(test.value);

答案 1 :(得分:0)

我可以在没有树的情况下完成,只需使用简单的链接列表:

function Node(value, next){
	this.value = value;
	this.next = next;
	this.count = 1;
}

function smaller(array){
	return array.reduceRight(function(root, value, i){
		var count = 0;
		for(var prev = root, node; (node = prev.next) && node.value < value; prev = node)
			count += node.count;
		root.counts[i] = count;
		
		if(node && node.value === value){
			node.count++;
		}else{
			prev.next = new Node(value, prev.next);
		}
		
		return root;
	}, {
		next: null, 
		counts: Array(array.length).fill(0) 
	}).counts;
}

console.log("100, 10, 10, 10, 10 -> " + smaller([100, 10, 10, 10, 10]));
console.log("1, 2, 3 -> " + smaller([1, 2, 3]));
console.log("1, 2, 0 -> " + smaller([1, 2, 0]));
console.log("1, 2, 1 -> " + smaller([1, 2, 1]));

var sampleData = Array.from({length: 100000}, () => 0|(Math.random() * 100));

console.time("100000 items");
smaller(sampleData);
console.timeEnd("100000 items");

在控制台中快速测试了三个四个具有100000值的实现。

  • 你的第一个代码:~700-800ms
  • 你的第二个代码:~350-400ms
  • 我的代码:~15-30ms
  • 詹姆斯的代码:~25000ms

所有实现都在相同的预生成的100000项阵列上进行测试。

smaller导出节点构造函数可以提高性能,因此第二次和第三次测试更可能在15ms而不是30ms。这与JS引擎如何优化代码有关。同样使用0值预填充数组,加快代码大约十倍。

但对于具有超过100个不同值的短数组或数组,差异应该更小。

答案 2 :(得分:0)

好的,我通过做一些重构来加速你的代码。

dspBody()

我很想知道他们抛出这个函数需要很长时间来计算。我们在12秒内谈论100次计算而不是12ms。我猜大数组和许多不同的值(浮点数或使用整个范围的整数,而不是像8位:0 ... 255)。

仍在尝试不同的方法。