696 行
17 KiB
JavaScript
696 行
17 KiB
JavaScript
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
// permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
// conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
// of conditions and the following disclaimer in the documentation and/or other materials
|
|
// provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY David Galles ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Galles OR
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// The views and conclusions contained in the software and documentation are those of the
|
|
// authors and should not be interpreted as representing official policies, either expressed
|
|
// or implied, of the University of San Francisco
|
|
|
|
|
|
var ARRAY_START_X = 50;
|
|
var ARRAY_WIDTH = 30;
|
|
var ARRAY_HEIGHT = 30;
|
|
|
|
var TREE_START_X = 50;
|
|
var TREE_ELEM_WIDTH = 50;
|
|
var TREE_ELEM_HEIGHT = 50;
|
|
|
|
var SIZE = 16;
|
|
|
|
var LINK_COLOR = "#007700"
|
|
var HIGHLIGHT_CIRCLE_COLOR = "#007700";
|
|
var FOREGROUND_COLOR = "#007700";
|
|
var BACKGROUND_COLOR = "#EEFFEE";
|
|
var PRINT_COLOR = FOREGROUND_COLOR;
|
|
|
|
function DisjointSet(am, w, h)
|
|
{
|
|
this.array_start_y = h - 2 * ARRAY_HEIGHT;
|
|
this.tree_start_y = this.array_start_y - 50;
|
|
this.init(am);
|
|
|
|
}
|
|
|
|
DisjointSet.prototype = new Algorithm();
|
|
DisjointSet.prototype.constructor = DisjointSet;
|
|
DisjointSet.superclass = Algorithm.prototype;
|
|
|
|
DisjointSet.prototype.init = function(am, w, h)
|
|
{
|
|
var sc = DisjointSet.superclass.init.call(this, am, w, h);
|
|
this.addControls();
|
|
|
|
this.commands = [];
|
|
this.nextIndex = 0;
|
|
this.highlight1ID = this.nextIndex++;
|
|
this.highlight2ID = this.nextIndex++;
|
|
|
|
this.arrayID = new Array(SIZE);
|
|
this.arrayLabelID = new Array(SIZE);
|
|
this.treeID = new Array(SIZE);
|
|
this.setData = new Array(SIZE);
|
|
this.treeY = new Array(SIZE);
|
|
this.treeIndexToLocation = new Array(SIZE);
|
|
this.locationToTreeIndex = new Array(SIZE);
|
|
this.heights = new Array(SIZE);
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
this.treeIndexToLocation[i] = i;
|
|
this.locationToTreeIndex[i] = i;
|
|
this.arrayID[i]= this.nextIndex++;
|
|
this.arrayLabelID[i]= this.nextIndex++;
|
|
this.treeID[i] = this.nextIndex++;
|
|
this.setData[i] = -1;
|
|
this.treeY[i] = this.tree_start_y;
|
|
this.heights[i] = 0;
|
|
}
|
|
|
|
this.pathCompression = false;
|
|
this.unionByRank = false;
|
|
this.rankAsHeight = false;
|
|
this.setup();
|
|
}
|
|
|
|
DisjointSet.prototype.addControls = function()
|
|
{
|
|
this.controls = [];
|
|
|
|
|
|
this.findField = addControlToAlgorithmBar("Text", "");
|
|
this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4, true);
|
|
this.controls.push(this.findField);
|
|
|
|
var findButton = addControlToAlgorithmBar("Button", "搜索");
|
|
findButton.onclick = this.findCallback.bind(this);
|
|
|
|
this.controls.push(findButton);
|
|
|
|
|
|
this.unionField1 = addControlToAlgorithmBar("Text", "");
|
|
this.unionField1.onkeydown = this.returnSubmit(this.unionField1, this.unionCallback.bind(this), 4, true);
|
|
|
|
this.controls.push(this.unionField1);
|
|
|
|
|
|
this.unionField2 = addControlToAlgorithmBar("Text", "");
|
|
this.unionField2.onkeydown = this.returnSubmit(this.unionField2, this.unionCallback.bind(this), 4, true);
|
|
|
|
this.unionButton = addControlToAlgorithmBar("Button", "Union");
|
|
this.unionButton.onclick = this.unionCallback.bind(this);
|
|
|
|
this.controls.push(this.unionField2);
|
|
|
|
this.pathCompressionBox = addCheckboxToAlgorithmBar("Path Compression");
|
|
this.pathCompressionBox.onclick = this.pathCompressionChangeCallback.bind(this);
|
|
|
|
this.controls.push(this.pathCompressionBox);
|
|
|
|
this.unionByRankBox = addCheckboxToAlgorithmBar("Union By Rank");
|
|
this.unionByRankBox.onclick = this.unionByRankChangeCallback.bind(this);
|
|
|
|
this.controls.push(this.unionByRankBox);
|
|
|
|
var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Rank = # of nodes",
|
|
"Rank = estimated height",
|
|
],
|
|
"RankType");
|
|
this.rankNumberOfNodesButton = radioButtonList[0];
|
|
this.rankNumberOfNodesButton.onclick = this.rankTypeChangedCallback.bind(this, false);
|
|
this.controls.push(this.rankNumberOfNodesButton);
|
|
|
|
|
|
this.rankEstimatedHeightButton = radioButtonList[1];
|
|
this.rankEstimatedHeightButton.onclick = this.rankTypeChangedCallback.bind(this, true);
|
|
this.controls.push(this.rankEstimatedHeightButton);
|
|
|
|
this.rankNumberOfNodesButton.checked = !this.rankAsHeight;
|
|
this.rankEstimatedHeightButton.checked = this.rankAsHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DisjointSet.prototype.setup = function()
|
|
{
|
|
this.commands = new Array();
|
|
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
this.cmd("CreateRectangle", this.arrayID[i], this.setData[i], ARRAY_WIDTH, ARRAY_HEIGHT, ARRAY_START_X + i *ARRAY_WIDTH, this.array_start_y);
|
|
this.cmd("CreateLabel",this.arrayLabelID[i], i, ARRAY_START_X + i *ARRAY_WIDTH, this.array_start_y + ARRAY_HEIGHT);
|
|
this.cmd("SetForegroundColor", this.arrayLabelID[i], "#0000FF");
|
|
|
|
this.cmd("CreateCircle", this.treeID[i], i, TREE_START_X + this.treeIndexToLocation[i] * TREE_ELEM_WIDTH, this.treeY[i]);
|
|
this.cmd("SetForegroundColor", this.treeID[i], FOREGROUND_COLOR);
|
|
this.cmd("SetBackgroundColor", this.treeID[i], BACKGROUND_COLOR);
|
|
|
|
}
|
|
|
|
|
|
animationManager.StartNewAnimation(this.commands);
|
|
animationManager.skipForward();
|
|
animationManager.clearHistory();
|
|
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.reset = function()
|
|
{
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
this.setData[i] = -1;
|
|
}
|
|
this.pathCompression = false;
|
|
this.unionByRank = false;
|
|
this.rankAsHeight = false;
|
|
this.pathCompressionBox.selected = this.pathCompression;
|
|
this.unionByRankBox.selected = this.unionByRank;
|
|
this.rankNumberOfNodesButton.checked = !this.rankAsHeight;
|
|
this.rankEstimatedHeightButton.checked = this.rankAsHeight;
|
|
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.enableUI = function(event)
|
|
{
|
|
for (var i = 0; i < this.controls.length; i++)
|
|
{
|
|
this.controls[i].disabled = false;
|
|
}
|
|
|
|
|
|
}
|
|
DisjointSet.prototype.disableUI = function(event)
|
|
{
|
|
for (var i = 0; i < this.controls.length; i++)
|
|
{
|
|
this.controls[i].disabled = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
DisjointSet.prototype.rankTypeChangedCallback = function(rankAsHeight, event)
|
|
{
|
|
if (this.rankAsHeight != rankAsHeight)
|
|
{
|
|
this.implementAction(this.changeRankType.bind(this), rankAsHeight);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DisjointSet.prototype.pathCompressionChangeCallback = function(event)
|
|
{
|
|
if (this.pathCompression != this.pathCompressionBox.checked)
|
|
{
|
|
this.implementAction(this.changePathCompression.bind(this), this.pathCompressionBox.checked);
|
|
}
|
|
}
|
|
|
|
DisjointSet.prototype.unionByRankChangeCallback = function(event)
|
|
{
|
|
if (this.unionByRank != this.unionByRankBox.checked)
|
|
{
|
|
this.implementAction(this.changeUnionByRank.bind(this), this.unionByRankBox.checked);
|
|
}
|
|
}
|
|
|
|
DisjointSet.prototype.changeRankType = function(newValue)
|
|
{
|
|
this.commands = new Array();
|
|
this.rankAsHeight = newValue
|
|
if (this.rankNumberOfNodesButton.checked == this.rankAsHeight)
|
|
{
|
|
this.rankNumberOfNodesButton.checked = !this.rankAsHeight;
|
|
}
|
|
if (this.rankEstimatedHeightButton.checked != this.rankAsHeight)
|
|
{
|
|
this.rankEstimatedHeightButton.checked = this.rankAsHeight;
|
|
}
|
|
// When we change union by rank, we can either create a blank slate using clearAll,
|
|
// or we can rebuild the root values to what they shoue be given the current state of
|
|
// the tree.
|
|
// clearAll();
|
|
this.rebuildRootValues();
|
|
return this.commands;
|
|
|
|
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.changeUnionByRank = function(newValue)
|
|
{
|
|
this.commands = new Array();
|
|
this.unionByRank = newValue;
|
|
if (this.unionByRankBox.selected != this.unionByRank)
|
|
{
|
|
this.unionByRankBox.selected = this.unionByRank;
|
|
}
|
|
// When we change union by rank, we can either create a blank slate using clearAll,
|
|
// or we can rebuild the root values to what they shoue be given the current state of
|
|
// the tree.
|
|
// clearAll();
|
|
this.rebuildRootValues();
|
|
return this.commands;
|
|
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.changePathCompression = function(newValue)
|
|
{
|
|
this.commands = new Array();
|
|
this.cmd("Step");
|
|
this.pathCompression = newValue;
|
|
if (this.pathCompressionBox.selected != this.pathCompression)
|
|
{
|
|
this.pathCompressionBox.selected = this.pathCompression;
|
|
}
|
|
this.rebuildRootValues();
|
|
// clearAll();
|
|
return this.commands;
|
|
|
|
}
|
|
|
|
DisjointSet.prototype.findCallback = function(event)
|
|
{
|
|
var findValue;
|
|
|
|
findValue = this.findField.value;
|
|
if (findValue != "" && parseInt(findValue) < SIZE)
|
|
{
|
|
this.findField.value.value = "";
|
|
this.implementAction(this.findElement.bind(this), findValue);
|
|
}
|
|
}
|
|
|
|
DisjointSet.prototype.clearCallback = function(event)
|
|
{
|
|
this.implementAction(this.clearData.bind(this), "");
|
|
}
|
|
|
|
DisjointSet.prototype.clearData = function(ignored)
|
|
{
|
|
this.commands = new Array();
|
|
clearAll();
|
|
return this.commands;
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.getSizes = function()
|
|
{
|
|
var sizes = new Array(SIZE);
|
|
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
sizes[i] = 1;
|
|
}
|
|
var changed = true;
|
|
while (changed)
|
|
{
|
|
changed = false;
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
if (sizes[i] > 0 && this.setData[i] >= 0)
|
|
{
|
|
sizes[this.setData[i]] += sizes[i];
|
|
sizes[i] = 0;
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
return sizes;
|
|
}
|
|
|
|
DisjointSet.prototype.rebuildRootValues = function()
|
|
{
|
|
var changed = false;
|
|
|
|
if (this.unionByRank)
|
|
{
|
|
if (!this.rankAsHeight)
|
|
{
|
|
var sizes = this.getSizes();
|
|
}
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
if (this.setData[i] < 0)
|
|
{
|
|
if (this.rankAsHeight)
|
|
{
|
|
this.setData[i] = 0 - this.heights[i] - 1;
|
|
}
|
|
else
|
|
{
|
|
this.setData[i] = - sizes[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
if (this.setData[i] < 0)
|
|
{
|
|
this.setData[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
this.cmd("SetText", this.arrayID[i], this.setData[i]);
|
|
}
|
|
|
|
}
|
|
|
|
DisjointSet.prototype.unionCallback = function(event)
|
|
{
|
|
var union1;
|
|
var union2;
|
|
|
|
union1 = this.unionField1.value;
|
|
union2 = this.unionField2.value;
|
|
|
|
|
|
if ( union1 != "" && parseInt(union1) < SIZE &&
|
|
union2 != "" && parseInt(union2) < SIZE)
|
|
{
|
|
this.unionField1.value = "";
|
|
this.unionField2.value = "";
|
|
this.implementAction(this.doUnion.bind(this), union1 + ";" + union2);
|
|
}
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.clearAll = function()
|
|
{
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
if (this.setData[i] >= 0)
|
|
{
|
|
this.cmd("Disconnect", this.treeID[i], this.treeID[this.setData[i]]);
|
|
}
|
|
this.setData[i] = -1;
|
|
this.cmd("SetText", this.arrayID[i], this.setData[i]);
|
|
this.treeIndexToLocation[i] = i;
|
|
this.locationToTreeIndex[i] = i;
|
|
this.treeY[i] = this.tree_start_y;
|
|
this.cmd("SetPosition", this.treeID[i], TREE_START_X + this.treeIndexToLocation[i] * TREE_ELEM_WIDTH, this.treeY[i]);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.findElement = function(findValue)
|
|
{
|
|
this.commands = new Array();
|
|
|
|
|
|
var found = this.doFind(parseInt(findValue));
|
|
|
|
if (this.pathCompression)
|
|
{
|
|
var changed = this.adjustHeights();
|
|
if (changed)
|
|
{
|
|
this.animateNewPositions();
|
|
}
|
|
}
|
|
return this.commands;
|
|
}
|
|
|
|
|
|
|
|
DisjointSet.prototype.doFind = function(elem)
|
|
{
|
|
this.cmd("SetHighlight", this.treeID[elem], 1);
|
|
this.cmd("SetHighlight", this.arrayID[elem], 1);
|
|
this.cmd("Step");
|
|
this.cmd("SetHighlight", this.treeID[elem], 0);
|
|
this.cmd("SetHighlight", this.arrayID[elem], 0);
|
|
if (this.setData[elem] >= 0)
|
|
{
|
|
var treeRoot = this.doFind(this.setData[elem]);
|
|
if (this.pathCompression)
|
|
{
|
|
if (this.setData[elem] != treeRoot)
|
|
{
|
|
this.cmd("Disconnect", this.treeID[elem], this.treeID[this.setData[elem]]);
|
|
this.setData[elem] = treeRoot;
|
|
this.cmd("SetText", this.arrayID[elem], this.setData[elem]);
|
|
this.cmd("Connect", this.treeID[elem],
|
|
this.treeID[treeRoot],
|
|
FOREGROUND_COLOR,
|
|
0, // Curve
|
|
1, // Directed
|
|
""); // Label
|
|
}
|
|
}
|
|
return treeRoot;
|
|
}
|
|
else
|
|
{
|
|
return elem;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.findRoot = function (elem)
|
|
{
|
|
while (this.setData[elem] >= 0)
|
|
elem = this.setData[elem];
|
|
return elem;
|
|
}
|
|
|
|
|
|
|
|
// After linking two trees, move them next to each other.
|
|
DisjointSet.prototype.adjustXPos = function(pos1, pos2)
|
|
{
|
|
|
|
var left1 = this.treeIndexToLocation[pos1];
|
|
while (left1 > 0 && this.findRoot(this.locationToTreeIndex[left1 - 1]) == pos1)
|
|
{
|
|
left1--;
|
|
}
|
|
var right1 = this.treeIndexToLocation[pos1];
|
|
while (right1 < SIZE - 1 && this.findRoot(this.locationToTreeIndex[right1 + 1]) == pos1)
|
|
{
|
|
right1++;
|
|
}
|
|
var left2 = this.treeIndexToLocation[pos2];
|
|
while (left2 > 0 && this.findRoot(this.locationToTreeIndex[left2-1]) == pos2)
|
|
{
|
|
left2--;
|
|
}
|
|
var right2 = this.treeIndexToLocation[pos2];
|
|
while (right2 < SIZE - 1 && this.findRoot(this.locationToTreeIndex[right2 + 1]) == pos2)
|
|
{
|
|
right2++;
|
|
}
|
|
if (right1 == left2-1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var tmpLocationToTreeIndex = new Array(SIZE);
|
|
var nextInsertIndex = 0;
|
|
for (var i = 0; i <= right1; i++)
|
|
{
|
|
tmpLocationToTreeIndex[nextInsertIndex++] = this.locationToTreeIndex[i];
|
|
}
|
|
for (i = left2; i <= right2; i++)
|
|
{
|
|
tmpLocationToTreeIndex[nextInsertIndex++] = this.locationToTreeIndex[i];
|
|
}
|
|
for (i = right1+1; i < left2; i++)
|
|
{
|
|
tmpLocationToTreeIndex[nextInsertIndex++] = this.locationToTreeIndex[i];
|
|
}
|
|
for (i = right2+1; i < SIZE; i++)
|
|
{
|
|
tmpLocationToTreeIndex[nextInsertIndex++] = this.locationToTreeIndex[i];
|
|
}
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
this.locationToTreeIndex[i] = tmpLocationToTreeIndex[i];
|
|
}
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
this.treeIndexToLocation[this.locationToTreeIndex[i]] = i;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
DisjointSet.prototype.doUnion = function(value)
|
|
{
|
|
this.commands = new Array();
|
|
var args = value.split(";");
|
|
var arg1 = this.doFind(parseInt(args[0]));
|
|
|
|
this.cmd("CreateHighlightCircle", this.highlight1ID, HIGHLIGHT_CIRCLE_COLOR, TREE_START_X + this.treeIndexToLocation[arg1] * TREE_ELEM_WIDTH, this.treeY[arg1]);
|
|
|
|
|
|
var arg2 = this.doFind(parseInt(args[1]));
|
|
this.cmd("CreateHighlightCircle", this.highlight2ID, HIGHLIGHT_CIRCLE_COLOR, TREE_START_X + this.treeIndexToLocation[arg2] * TREE_ELEM_WIDTH, this.treeY[arg2]);
|
|
|
|
|
|
if (arg1 == arg2)
|
|
{
|
|
this.cmd("Delete", this.highlight1ID);
|
|
this.cmd("Delete", this.highlight2ID);
|
|
return this.commands;
|
|
}
|
|
|
|
var changed;
|
|
|
|
if (this.treeIndexToLocation[arg1] < this.treeIndexToLocation[arg2])
|
|
{
|
|
changed = this.adjustXPos(arg1, arg2) || changed
|
|
}
|
|
else
|
|
{
|
|
changed = this.adjustXPos(arg2, arg1) || changed
|
|
}
|
|
|
|
|
|
if (this.unionByRank && this.setData[arg1] < this.setData[arg2])
|
|
{
|
|
var tmp = arg1;
|
|
arg1 = arg2;
|
|
arg2 = tmp;
|
|
}
|
|
|
|
if (this.unionByRank && this.rankAsHeight)
|
|
{
|
|
if (this.setData[arg2] == this.setData[arg1])
|
|
{
|
|
this.setData[arg2] -= 1;
|
|
}
|
|
}
|
|
else if (this.unionByRank)
|
|
{
|
|
this.setData[arg2] = this.setData[arg2] + this.setData[arg1];
|
|
}
|
|
|
|
this.setData[arg1] = arg2;
|
|
|
|
this.cmd("SetText", this.arrayID[arg1], this.setData[arg1]);
|
|
this.cmd("SetText", this.arrayID[arg2], this.setData[arg2]);
|
|
|
|
this.cmd("Connect", this.treeID[arg1],
|
|
this.treeID[arg2],
|
|
FOREGROUND_COLOR,
|
|
0, // Curve
|
|
1, // Directed
|
|
""); // Label
|
|
|
|
if (this.adjustHeights())
|
|
{
|
|
changed = true;
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
this.cmd("Step");
|
|
this.cmd("Delete", this.highlight1ID);
|
|
this.cmd("Delete", this.highlight2ID);
|
|
this.animateNewPositions();
|
|
}
|
|
else
|
|
{
|
|
this.cmd("Delete", this.highlight1ID);
|
|
this.cmd("Delete", this.highlight2ID);
|
|
}
|
|
|
|
return this.commands;
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.adjustHeights = function()
|
|
{
|
|
var changed = false;
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
this.heights[i] = 0;
|
|
}
|
|
|
|
for (var j = 0; j < SIZE; j++)
|
|
{
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
if (this.setData[i] >= 0)
|
|
{
|
|
this.heights[this.setData[i]] = Math.max(this.heights[this.setData[i]], this.heights[i] + 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
for (j = 0; j < SIZE; j++)
|
|
{
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
if (this.setData[i] >= 0)
|
|
{
|
|
this.heights[i] = this.heights[this.setData[i]] - 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
for (i = 0; i < SIZE; i++)
|
|
{
|
|
var newY = this.tree_start_y - this.heights[i] * TREE_ELEM_HEIGHT;
|
|
if (this.treeY[i] != newY)
|
|
{
|
|
this.treeY[i] = newY;
|
|
changed = true;
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
|
|
DisjointSet.prototype.animateNewPositions = function()
|
|
{
|
|
for (var i = 0; i < SIZE; i++)
|
|
{
|
|
this.cmd("Move", this.treeID[i], TREE_START_X + this.treeIndexToLocation[i] * TREE_ELEM_WIDTH, this.treeY[i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var currentAlg;
|
|
|
|
function init()
|
|
{
|
|
var animManag = initCanvas();
|
|
currentAlg = new DisjointSet(animManag, canvas.width, canvas.height);
|
|
}
|
|
|