diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/JavaScript.iml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/JavaScript.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/JavaScript.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/modules.xml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/modules.xml
new file mode 100644
index 0000000..3ecf87a
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/workspace.xml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/workspace.xml
new file mode 100644
index 0000000..8bc29f5
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/.idea/workspace.xml
@@ -0,0 +1,479 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "SetText"
+ "Deleting:
+ "Deleting
+ Node to delete is a leaf. Delete it.
+ Node to delete has no left child. \nSet parent of deleted node to right child of deleted node.
+ Node to delete has no left child.
+ Node to delete has no left child
+ Node to delete has no right child
+ Node to delete has two childern
+ Find largest node in left subtree
+ "Elemet
+ " not found
+ could not delete
+ valueToDelete
+ 没有找到
+ 调整
+ Adjusting height after recursive call
+ Unwinding Recursion
+ 正在搜索
+ " : "
+ Show Null Leaves
+ 显示
+ "NULL"
+ #
+ text color
+ BACKGROUND_COLOR
+ BACKGROUND_BLACK
+ deleteElement
+ treeDelete
+ Deleted node was red. No tree rotations required.
+
+
+ 找不到元素
+ 右单旋
+ 左单旋
+ , 访问左子树
+ , 访问右子树
+ "正在删除
+ "正在删除元素:
+ 元素已删除
+ 正在搜索元素:
+ 未找到!
+ 已找到!
+ " 正在添加
+ "正在搜索:
+ "正在刪除:
+ "正在刪除
+ 需要删除的是叶子节点,直接删除!
+ 需要删除的节点没有左子树
+ 需要删除的节点没有右子树
+ 需要删除的节点有2棵子树
+ 找到左子树中最大的节点
+ 元素
+ "元素
+ " 未找到
+ 无法删除
+ 更新高度值
+ 检测平衡因子
+ ":"
+ NULL
+ "null"
+ 删除的是红色节点. 不需要旋转.
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+ true
+
+
+
+ DIRECTORY
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+ 1555083398362
+
+
+ 1555083398362
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AVLtree.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AVLtree.html
new file mode 100644
index 0000000..c3525f6
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AVLtree.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ AVL Tree Visualzation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/AVL.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/AVL.js
new file mode 100644
index 0000000..c87ec1b
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/AVL.js
@@ -0,0 +1,1222 @@
+// 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 ``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 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
+
+function AVL(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+AVL.prototype = new Algorithm();
+AVL.prototype.constructor = AVL;
+AVL.superclass = Algorithm.prototype;
+
+
+// Various constants
+
+AVL.HIGHLIGHT_LABEL_COLOR = "#FF0000"
+AVL.HIGHLIGHT_LINK_COLOR = "#FF0000"
+
+AVL.HIGHLIGHT_COLOR = "#007700"
+AVL.HEIGHT_LABEL_COLOR = "#007700"
+
+
+AVL.LINK_COLOR = "#007700";
+AVL.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+AVL.FOREGROUND_COLOR = "0x007700";
+AVL.BACKGROUND_COLOR = "#DDFFDD";
+AVL.PRINT_COLOR = AVL.FOREGROUND_COLOR;
+
+AVL.WIDTH_DELTA = 50;
+AVL.HEIGHT_DELTA = 50;
+AVL.STARTING_Y = 50;
+
+AVL.FIRST_PRINT_POS_X = 50;
+AVL.PRINT_VERTICAL_GAP = 20;
+AVL.PRINT_HORIZONTAL_GAP = 50;
+AVL.EXPLANITORY_TEXT_X = 10;
+AVL.EXPLANITORY_TEXT_Y = 10;
+
+
+
+AVL.prototype.init = function(am, w, h)
+{
+ var sc = AVL.superclass;
+ var fn = sc.init;
+ this.first_print_pos_y = h - 2 * AVL.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ fn.call(this, am, w, h);
+ this.startingX = w / 2;
+ this.addControls();
+ this.nextIndex = 1;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", AVL.EXPLANITORY_TEXT_X, AVL.EXPLANITORY_TEXT_Y, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+AVL.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 4);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+}
+
+AVL.prototype.reset = function()
+{
+ this.nextIndex = 1;
+ this.treeRoot = null;
+}
+
+
+
+
+AVL.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value;
+ // Get text value
+ insertedValue = this.normalizeNumber(insertedValue, 4);
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this), insertedValue);
+ }
+}
+
+AVL.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value;
+ if (deletedValue != "")
+ {
+ deletedValue = this.normalizeNumber(deletedValue, 4);
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+
+AVL.prototype.findCallback = function(event)
+{
+ var findValue = this.findField.value;
+ if (findValue != "")
+ {
+ findValue = this.normalizeNumber(findValue, 4);
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+ }
+}
+
+AVL.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+AVL.prototype.sizeChanged = function(newWidth, newHeight)
+{
+ this.startingX = newWidth / 2;
+}
+
+
+
+AVL.prototype.printTree = function(unused)
+{
+ this.commands = [];
+
+ if (this.treeRoot != null)
+ {
+ this.highlightID = this.nextIndex++;
+ var firstLabel = this.nextIndex;
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, this.treeRoot.x, this.treeRoot.y);
+ this.xPosOfNextLabel = AVL.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.treeRoot);
+ this.cmd("Delete",this.highlightID);
+ this.cmd("Step");
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ this.cmd("Delete", i);
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+}
+
+AVL.prototype.printTreeRec = function(tree)
+{
+ this.cmd("Step");
+ if (tree.left != null)
+ {
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.printTreeRec(tree.left);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.data, tree.x, tree.y);
+ this.cmd("SetForegroundColor", nextLabelID, AVL.PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += AVL.PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = AVL.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += AVL.PRINT_VERTICAL_GAP;
+
+ }
+ if (tree.right != null)
+ {
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.printTreeRec(tree.right);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ return;
+}
+
+
+AVL.prototype.findElement = function(findValue)
+{
+ this.commands = [];
+
+ this.highlightID = this.nextIndex++;
+
+ this.doFind(this.treeRoot, findValue);
+
+
+ return this.commands;
+}
+
+
+AVL.prototype.doFind = function(tree, value)
+{
+ this.cmd("SetText", 0, "Searchiing for "+value);
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (tree.data == value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " = " + value + " (Element found!)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "Found:"+value);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ else
+ {
+ if (tree.data > value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " < " + tree.data + " (访问左子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.left!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.doFind(tree.left, value);
+ }
+ else
+ {
+ this.cmd("SetText", 0, " 正在搜索 "+value+":" + value + " > " + tree.data + " (访问右子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.right!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.doFind(tree.right, value);
+ }
+
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, " 正在搜索 "+value+":" + "< 空树 > (找不到元素)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, " 正在搜索 "+value+":" + " (找不到元素)");
+ }
+}
+
+AVL.prototype.insertElement = function(insertedValue)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, " 正在添加 "+insertedValue);
+
+ if (this.treeRoot == null)
+ {
+ var treeNodeID = this.nextIndex++;
+ var labelID = this.nextIndex++;
+ this.cmd("CreateCircle", treeNodeID, insertedValue, this.startingX, AVL.STARTING_Y);
+ this.cmd("SetForegroundColor", treeNodeID, AVL.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", treeNodeID, AVL.BACKGROUND_COLOR);
+ this.cmd("CreateLabel", labelID, 1, this.startingX - 20, AVL.STARTING_Y-20);
+ this.cmd("SetForegroundColor", labelID, AVL.HEIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.treeRoot = new AVLNode(insertedValue, treeNodeID, labelID, this.startingX, AVL.STARTING_Y);
+ this.treeRoot.height = 1;
+ }
+ else
+ {
+ treeNodeID = this.nextIndex++;
+ labelID = this.nextIndex++;
+ this.highlightID = this.nextIndex++;
+
+ this.cmd("CreateCircle", treeNodeID, insertedValue, 30, AVL.STARTING_Y);
+
+ this.cmd("SetForegroundColor", treeNodeID, AVL.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", treeNodeID, AVL.BACKGROUND_COLOR);
+ this.cmd("CreateLabel", labelID, "", 100-20, 100-20);
+ this.cmd("SetForegroundColor", labelID, AVL.HEIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ var insertElem = new AVLNode(insertedValue, treeNodeID, labelID, 100, 100)
+
+ this.cmd("SetHighlight", insertElem.graphicID, 1);
+ insertElem.height = 1;
+ this.insert(insertElem, this.treeRoot);
+ // this.resizeTree();
+ }
+ this.cmd("SetText", 0, " ");
+ return this.commands;
+}
+
+
+AVL.prototype.singleRotateRight = function(tree)
+{
+ var B = tree;
+ var t3 = B.right;
+ var A = tree.left;
+ var t1 = A.left;
+ var t2 = A.right;
+
+ this.cmd("SetText", 0, "右单旋");
+ this.cmd("SetEdgeHighlight", B.graphicID, A.graphicID, 1);
+ this.cmd("Step");
+
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", A.graphicID, t2.graphicID);
+ this.cmd("Connect", B.graphicID, t2.graphicID, AVL.LINK_COLOR);
+ t2.parent = B;
+ }
+ this.cmd("Disconnect", B.graphicID, A.graphicID);
+ this.cmd("Connect", A.graphicID, B.graphicID, AVL.LINK_COLOR);
+ A.parent = B.parent;
+ if (this.treeRoot == B)
+ {
+ this.treeRoot = A;
+ }
+ else
+ {
+ this.cmd("Disconnect", B.parent.graphicID, B.graphicID, AVL.LINK_COLOR);
+ this.cmd("Connect", B.parent.graphicID, A.graphicID, AVL.LINK_COLOR)
+ if (B.isLeftChild())
+ {
+ B.parent.left = A;
+ }
+ else
+ {
+ B.parent.right = A;
+ }
+ }
+ A.right = B;
+ B.parent = A;
+ B.left = t2;
+ this. resetHeight(B);
+ this. resetHeight(A);
+ this.resizeTree();
+}
+
+
+
+AVL.prototype.singleRotateLeft = function(tree)
+{
+ var A = tree;
+ var B = tree.right;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+
+ this.cmd("SetText", 0, "左单旋");
+ this.cmd("SetEdgeHighlight", A.graphicID, B.graphicID, 1);
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", B.graphicID, t2.graphicID);
+ this.cmd("Connect", A.graphicID, t2.graphicID, AVL.LINK_COLOR);
+ t2.parent = A;
+ }
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, AVL.LINK_COLOR);
+ B.parent = A.parent;
+ if (this.treeRoot == A)
+ {
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect", A.parent.graphicID, A.graphicID, AVL.LINK_COLOR);
+ this.cmd("Connect", A.parent.graphicID, B.graphicID, AVL.LINK_COLOR)
+
+ if (A.isLeftChild())
+ {
+ A.parent.left = B;
+ }
+ else
+ {
+ A.parent.right = B;
+ }
+ }
+ B.left = A;
+ A.parent = B;
+ A.right = t2;
+ this. resetHeight(A);
+ this. resetHeight(B);
+
+ this.resizeTree();
+}
+
+
+
+
+AVL.prototype.getHeight = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ return tree.height;
+}
+
+AVL.prototype.resetHeight = function(tree)
+{
+ if (tree != null)
+ {
+ var newHeight = Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1;
+ if (tree.height != newHeight)
+ {
+ tree.height = Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1
+ this.cmd("SetText",tree.heightLabelID, newHeight);
+// this.cmd("SetText",tree.heightLabelID, newHeight);
+ }
+ }
+}
+
+AVL.prototype.doubleRotateRight = function(tree)
+{
+ this.cmd("SetText", 0, "Double Rotate Right");
+ var A = tree.left;
+ var B = tree.left.right;
+ var C = tree;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+ var t4 = C.right;
+
+ this.cmd("Disconnect", C.graphicID, A.graphicID);
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Connect", C.graphicID, A.graphicID, AVL.HIGHLIGHT_LINK_COLOR);
+ this.cmd("Connect", A.graphicID, B.graphicID, AVL.HIGHLIGHT_LINK_COLOR);
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t2.graphicID);
+ t2.parent = A;
+ A.right = t2;
+ this.cmd("Connect", A.graphicID, t2.graphicID, AVL.LINK_COLOR);
+ }
+ if (t3 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t3.graphicID);
+ t3.parent = C;
+ C.left = t2;
+ this.cmd("Connect", C.graphicID, t3.graphicID, AVL.LINK_COLOR);
+ }
+ if (C.parent == null)
+ {
+ B.parent = null;
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect",C.parent.graphicID, C.graphicID);
+ this.cmd("Connect",C.parent.graphicID, B.graphicID, AVL.LINK_COLOR);
+ if (C.isLeftChild())
+ {
+ C.parent.left = B
+ }
+ else
+ {
+ C.parent.right = B;
+ }
+ B.parent = C.parent;
+ C.parent = B;
+ }
+ this.cmd("Disconnect", C.graphicID, A.graphicID);
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, AVL.LINK_COLOR);
+ this.cmd("Connect", B.graphicID, C.graphicID, AVL.LINK_COLOR);
+ B.left = A;
+ A.parent = B;
+ B.right=C;
+ C.parent=B;
+ A.right=t2;
+ C.left = t3;
+ this. resetHeight(A);
+ this. resetHeight(C);
+ this. resetHeight(B);
+
+ this.resizeTree();
+
+
+}
+
+AVL.prototype.doubleRotateLeft = function(tree)
+{
+ this.cmd("SetText", 0, "Double Rotate Left");
+ var A = tree;
+ var B = tree.right.left;
+ var C = tree.right;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+ var t4 = C.right;
+
+ this.cmd("Disconnect", A.graphicID, C.graphicID);
+ this.cmd("Disconnect", C.graphicID, B.graphicID);
+ this.cmd("Connect", A.graphicID, C.graphicID, AVL.HIGHLIGHT_LINK_COLOR);
+ this.cmd("Connect", C.graphicID, B.graphicID, AVL.HIGHLIGHT_LINK_COLOR);
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t2.graphicID);
+ t2.parent = A;
+ A.right = t2;
+ this.cmd("Connect", A.graphicID, t2.graphicID, AVL.LINK_COLOR);
+ }
+ if (t3 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t3.graphicID);
+ t3.parent = C;
+ C.left = t2;
+ this.cmd("Connect", C.graphicID, t3.graphicID, AVL.LINK_COLOR);
+ }
+
+
+ if (A.parent == null)
+ {
+ B.parent = null;
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect",A.parent.graphicID, A.graphicID);
+ this.cmd("Connect",A.parent.graphicID, B.graphicID, AVL.LINK_COLOR);
+ if (A.isLeftChild())
+ {
+ A.parent.left = B
+ }
+ else
+ {
+ A.parent.right = B;
+ }
+ B.parent = A.parent;
+ A.parent = B;
+ }
+ this.cmd("Disconnect", A.graphicID, C.graphicID);
+ this.cmd("Disconnect", C.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, AVL.LINK_COLOR);
+ this.cmd("Connect", B.graphicID, C.graphicID, AVL.LINK_COLOR);
+ B.left = A;
+ A.parent = B;
+ B.right=C;
+ C.parent=B;
+ A.right=t2;
+ C.left = t3;
+ this. resetHeight(A);
+ this. resetHeight(C);
+ this. resetHeight(B);
+
+ this.resizeTree();
+
+
+}
+
+AVL.prototype.insert = function(elem, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("SetHighlight", elem.graphicID, 1);
+
+ if (elem.data < tree.data)
+ {
+ this.cmd("SetText", 0, elem.data + " < " + tree.data + ", 访问左子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, elem.data + " >= " + tree.data + ", 访问右子树");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlight", elem.graphicID, 0);
+
+ if (elem.data < tree.data)
+ {
+ if (tree.left == null)
+ {
+ this.cmd("SetText", 0, "左子树为null,添加元素");
+ this.cmd("SetText",elem.heightLabelID,1);
+
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.left=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, AVL.LINK_COLOR);
+
+ this.resizeTree();
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.left.x, tree.left.y);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", 0, "Unwinding Recursion");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+
+ if (tree.height < tree.left.height + 1)
+ {
+ tree.height = tree.left.height + 1
+ this.cmd("SetText",tree.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+ }
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.left);
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.left.x, tree.left.y);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", 0,"Unwinding Recursion");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+
+ if (tree.height < tree.left.height + 1)
+ {
+ tree.height = tree.left.height + 1
+ this.cmd("SetText",tree.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+
+ }
+ if ((tree.right != null && tree.left.height > tree.right.height + 1) ||
+ (tree.right == null && tree.left.height > 1))
+ {
+ if (elem.data < tree.left.data)
+ {
+ this.singleRotateRight(tree);
+ }
+ else
+ {
+ this.doubleRotateRight(tree);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (tree.right == null)
+ {
+ this.cmd("SetText", 0, "右子树为null,添加元素");
+ this.cmd("SetText", elem.heightLabelID,1);
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.right=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, AVL.LINK_COLOR);
+ elem.x = tree.x + AVL.WIDTH_DELTA/2;
+ elem.y = tree.y + AVL.HEIGHT_DELTA
+ this.cmd("Move", elem.graphicID, elem.x, elem.y);
+
+ this.resizeTree();
+
+
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.right.x, tree.right.y);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", 0, "Unwinding Recursion");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+
+ if (tree.height < tree.right.height + 1)
+ {
+ tree.height = tree.right.height + 1
+ this.cmd("SetText",tree.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+ }
+
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.right);
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.right.x, tree.right.y);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", 0, "Unwinding Recursion");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ if (tree.height < tree.right.height + 1)
+ {
+ tree.height = tree.right.height + 1
+ this.cmd("SetText",tree.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+
+
+ }
+ if ((tree.left != null && tree.right.height > tree.left.height + 1) ||
+ (tree.left == null && tree.right.height > 1))
+ {
+ if (elem.data >= tree.right.data)
+ {
+ this.singleRotateLeft(tree);
+ }
+ else
+ {
+ this.doubleRotateLeft(tree);
+ }
+ }
+ }
+ }
+
+
+}
+
+AVL.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "正在刪除 "+deletedValue);
+ this.cmd("Step");
+ this.cmd("SetText", 0, " ");
+ this.highlightID = this.nextIndex++;
+ this.treeDelete(this.treeRoot, deletedValue);
+ this.cmd("SetText", 0, " ");
+ return this.commands;
+}
+
+AVL.prototype.treeDelete = function(tree, valueToDelete)
+{
+ var leftchild = false;
+ if (tree != null)
+ {
+ if (tree.parent != null)
+ {
+ leftchild = tree.parent.left == tree;
+ }
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (valueToDelete < tree.data)
+ {
+ this.cmd("SetText", 0, valueToDelete + " < " + tree.data + ", 访问左子树");
+ }
+ else if (valueToDelete > tree.data)
+ {
+ this.cmd("SetText", 0, valueToDelete + " > " + tree.data + ", 访问右子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, valueToDelete + " == " + tree.data + ". Found node to delete");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ if (valueToDelete == tree.data)
+ {
+ if (tree.left == null && tree.right == null)
+ {
+ this.cmd("SetText", 0, "需要删除的是叶子节点,直接删除!");
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Delete", tree.heightLabelID);
+ if (leftchild && tree.parent != null)
+ {
+ tree.parent.left = null;
+ }
+ else if (tree.parent != null)
+ {
+ tree.parent.right = null;
+ }
+ else
+ {
+ this.treeRoot = null;
+ }
+ this.resizeTree();
+ this.cmd("Step");
+
+ }
+ else if (tree.left == null)
+ {
+ this.cmd("SetText", 0, "需要删除的节点没有左子树. \nSet parent of deleted node to right child of deleted node.");
+ if (tree.parent != null)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, tree.right.graphicID, AVL.LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Delete", tree.heightLabelID);
+ if (leftchild)
+ {
+ tree.parent.left = tree.right;
+ }
+ else
+ {
+ tree.parent.right = tree.right;
+ }
+ tree.right.parent = tree.parent;
+ }
+ else
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Delete", tree.heightLabelID);
+ this.treeRoot = tree.right;
+ this.treeRoot.parent = null;
+ }
+ this.resizeTree();
+ }
+ else if (tree.right == null)
+ {
+ this.cmd("SetText", 0,"需要删除的节点没有右子树. \nSet parent of deleted node to left child of deleted node.");
+ if (tree.parent != null)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, tree.left.graphicID, AVL.LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Delete", tree.heightLabelID);
+ if (leftchild)
+ {
+ tree.parent.left = tree.left;
+ }
+ else
+ {
+ tree.parent.right = tree.left;
+ }
+ tree.left.parent = tree.parent;
+ }
+ else
+ {
+ this.cmd("Delete" , tree.graphicID);
+ this.cmd("Delete", tree.heightLabelID);
+ this.treeRoot = tree.left;
+ this.treeRoot.parent = null;
+ }
+ this.resizeTree();
+ }
+ else // tree.left != null && tree.right != null
+ {
+ this.cmd("SetText", 0, "需要删除的节点有2棵子树. \n找到左子树中最大的节点.");
+
+ this.highlightID = this.nextIndex;
+ this.nextIndex += 1;
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ var tmp = tree;
+ tmp = tree.left;
+ this.cmd("Move", this.highlightID, tmp.x, tmp.y);
+ this.cmd("Step");
+ while (tmp.right != null)
+ {
+ tmp = tmp.right;
+ this.cmd("Move", this.highlightID, tmp.x, tmp.y);
+ this.cmd("Step");
+ }
+ this.cmd("SetText", tree.graphicID, " ");
+ var labelID = this.nextIndex;
+ this.nextIndex += 1;
+ this.cmd("CreateLabel", labelID, tmp.data, tmp.x, tmp.y);
+ this.cmd("SetForegroundColor", labelID, AVL.HEIGHT_LABEL_COLOR);
+ tree.data = tmp.data;
+ this.cmd("Move", labelID, tree.x, tree.y);
+ this.cmd("SetText", 0, "Copy largest value of left subtree into node to delete.");
+
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("Delete", labelID);
+ this.cmd("SetText", tree.graphicID, tree.data);
+ this.cmd("Delete", this.highlightID);
+ this.cmd("SetText", 0, "Remove node whose value we copied.");
+
+ if (tmp.left == null)
+ {
+ if (tmp.parent != tree)
+ {
+ tmp.parent.right = null;
+ }
+ else
+ {
+ tree.left = null;
+ }
+ this.cmd("Delete", tmp.graphicID);
+ this.cmd("Delete", tmp.heightLabelID);
+ this.resizeTree();
+ }
+ else
+ {
+ this.cmd("Disconnect", tmp.parent.graphicID, tmp.graphicID);
+ this.cmd("Connect", tmp.parent.graphicID, tmp.left.graphicID, AVL.LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tmp.graphicID);
+ this.cmd("Delete", tmp.heightLabelID);
+ if (tmp.parent != tree)
+ {
+ tmp.parent.right = tmp.left;
+ tmp.left.parent = tmp.parent;
+ }
+ else
+ {
+ tree.left = tmp.left;
+ tmp.left.parent = tree;
+ }
+ this.resizeTree();
+ }
+ tmp = tmp.parent;
+
+ if (this.getHeight(tmp) != Math.max(this.getHeight(tmp.left), this.getHeight(tmp.right)) + 1)
+ {
+ tmp.height = Math.max(this.getHeight(tmp.left), this.getHeight(tmp.right)) + 1
+ this.cmd("SetText",tmp.heightLabelID,tmp.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tmp.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tmp.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+ }
+
+
+
+ while (tmp != tree)
+ {
+ var tmpPar = tmp.parent;
+ // TODO: Add extra animation here?
+ if (this.getHeight(tmp.left)- this.getHeight(tmp.right) > 1)
+ {
+ if (this.getHeight(tmp.left.right) > this.getHeight(tmp.left.left))
+ {
+ this.doubleRotateRight(tmp);
+ }
+ else
+ {
+ this.singleRotateRight(tmp);
+ }
+ }
+ if (tmpPar.right != null)
+ {
+ if (tmpPar == tree)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tmpPar.left.x, tmpPar.left.y);
+
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tmpPar.right.x, tmpPar.right.y);
+ }
+ this.cmd("Move", this.highlightID, tmpPar.x, tmpPar.y);
+ this.cmd("SetText", 0, "Backing up ...");
+
+ if (this.getHeight(tmpPar) != Math.max(this.getHeight(tmpPar.left), this.getHeight(tmpPar.right)) + 1)
+ {
+ tmpPar.height = Math.max(this.getHeight(tmpPar.left), this.getHeight(tmpPar.right)) + 1
+ this.cmd("SetText",tmpPar.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tmpPar.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tmpPar.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+ }
+
+//28,15,50,7,22,39,55,10,33,42,63,30 .
+
+
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ tmp = tmpPar;
+ }
+ if (this.getHeight(tree.right)- this.getHeight(tree.left) > 1)
+ {
+ if (this.getHeight(tree.right.left) > this.getHeight(tree.right.right))
+ {
+ this.doubleRotateLeft(tree);
+ }
+ else
+ {
+ this.singleRotateLeft(tree);
+ }
+ }
+
+ }
+ }
+ else if (valueToDelete < tree.data)
+ {
+ if (tree.left != null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.treeDelete(tree.left, valueToDelete);
+ if (tree.left != null)
+ {
+ this.cmd("SetText", 0, "Unwinding recursion.");
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.left.x, tree.left.y);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ if (this.getHeight(tree.right)- this.getHeight(tree.left) > 1)
+ {
+ if (this.getHeight(tree.right.left) > this.getHeight(tree.right.right))
+ {
+ this.doubleRotateLeft(tree);
+ }
+ else
+ {
+ this.singleRotateLeft(tree);
+ }
+ }
+ if (this.getHeight(tree) != Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1)
+ {
+ tree.height = Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1
+ this.cmd("SetText",tree.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+ }
+ }
+ else
+ {
+ if (tree.right != null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.treeDelete(tree.right, valueToDelete);
+ if (tree.right != null)
+ {
+ this.cmd("SetText", 0, "Unwinding recursion.");
+ this.cmd("CreateHighlightCircle", this.highlightID, AVL.HIGHLIGHT_COLOR, tree.right.x, tree.right.y);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+
+
+ if (this.getHeight(tree.left)- this.getHeight(tree.right) > 1)
+ {
+ if (this.getHeight(tree.left.right) > this.getHeight(tree.left.left))
+ {
+ this.doubleRotateRight(tree);
+ }
+ else
+ {
+ this.singleRotateRight(tree);
+ }
+ }
+ if (this.getHeight(tree) != Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1)
+ {
+ tree.height = Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1
+ this.cmd("SetText",tree.heightLabelID,tree.height);
+ this.cmd("SetText", 0, "更新高度值");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HIGHLIGHT_LABEL_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", tree.heightLabelID, AVL.HEIGHT_LABEL_COLOR);
+ }
+
+
+ }
+ }
+ else
+ {
+ this.cmd("SetText", 0, "元素 "+valueToDelete+" 未找到, 无法删除");
+ }
+
+}
+
+AVL.prototype.resizeTree = function()
+{
+ var startingPoint = this.startingX;
+ this.resizeWidths(this.treeRoot);
+ if (this.treeRoot != null)
+ {
+ if (this.treeRoot.leftWidth > startingPoint)
+ {
+ startingPoint = this.treeRoot.leftWidth;
+ }
+ else if (this.treeRoot.rightWidth > startingPoint)
+ {
+ startingPoint = Math.max(this.treeRoot.leftWidth, 2 * startingPoint - this.treeRoot.rightWidth);
+ }
+ this.setNewPositions(this.treeRoot, startingPoint, AVL.STARTING_Y, 0);
+ this.animateNewPositions(this.treeRoot);
+ this.cmd("Step");
+ }
+
+}
+
+AVL.prototype.setNewPositions = function(tree, xPosition, yPosition, side)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ if (side == -1)
+ {
+ xPosition = xPosition - tree.rightWidth;
+ tree.heightLabelX = xPosition - 20;
+ }
+ else if (side == 1)
+ {
+ xPosition = xPosition + tree.leftWidth;
+ tree.heightLabelX = xPosition + 20;
+ }
+ else
+ {
+ tree.heightLabelX = xPosition - 20;
+ }
+ tree.x = xPosition;
+ tree.heightLabelY = tree.y - 20;
+ this.setNewPositions(tree.left, xPosition, yPosition + AVL.HEIGHT_DELTA, -1)
+ this.setNewPositions(tree.right, xPosition, yPosition + AVL.HEIGHT_DELTA, 1)
+ }
+
+}
+AVL.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.cmd("Move", tree.heightLabelID, tree.heightLabelX, tree.heightLabelY);
+ this.animateNewPositions(tree.left);
+ this.animateNewPositions(tree.right);
+ }
+}
+
+AVL.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = Math.max(this.resizeWidths(tree.left), AVL.WIDTH_DELTA / 2);
+ tree.rightWidth = Math.max(this.resizeWidths(tree.right), AVL.WIDTH_DELTA / 2);
+ return tree.leftWidth + tree.rightWidth;
+}
+
+
+AVL.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+AVL.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+function AVLNode(val, id, hid, initialX, initialY)
+{
+ this.data = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.heightLabelID= hid;
+ this.height = 1;
+
+ this.graphicID = id;
+ this.left = null;
+ this.right = null;
+ this.parent = null;
+}
+
+AVLNode.prototype.isLeftChild = function()
+{
+ if (this. parent == null)
+ {
+ return true;
+ }
+ return this.parent.left == this;
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new AVL(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Algorithm.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Algorithm.js
new file mode 100644
index 0000000..6c97932
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Algorithm.js
@@ -0,0 +1,391 @@
+// 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 ``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 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
+
+function addLabelToAlgorithmBar(labelName)
+{
+ var element = document.createTextNode(labelName);
+
+ var tableEntry = document.createElement("td");
+ tableEntry.appendChild(element);
+
+
+ var controlBar = document.getElementById("AlgorithmSpecificControls");
+
+ //Append the element in page (in span).
+ controlBar.appendChild(tableEntry);
+ return element;
+}
+
+// TODO: Make this stackable like radio butons
+// (keep backwards compatible, thought)
+function addCheckboxToAlgorithmBar(boxLabel)
+{
+ var element = document.createElement("input");
+
+ element.setAttribute("type", "checkbox");
+ element.setAttribute("value", boxLabel);
+
+ var label = document.createTextNode(boxLabel);
+
+ var tableEntry = document.createElement("td");
+ tableEntry.appendChild(element);
+ tableEntry.appendChild(label);
+
+ var controlBar = document.getElementById("AlgorithmSpecificControls");
+
+ //Append the element in page (in span).
+ controlBar.appendChild(tableEntry);
+ return element;
+}
+
+function addRadioButtonGroupToAlgorithmBar(buttonNames, groupName)
+{
+ var buttonList = [];
+ var newTable = document.createElement("table");
+
+ for (var i = 0; i < buttonNames.length; i++)
+ {
+ var midLevel = document.createElement("tr");
+ var bottomLevel = document.createElement("td");
+
+ var button = document.createElement("input");
+ button.setAttribute("type", "radio");
+ button.setAttribute("name", groupName);
+ button.setAttribute("value", buttonNames[i]);
+ bottomLevel.appendChild(button);
+ midLevel.appendChild(bottomLevel);
+ var txtNode = document.createTextNode(" " + buttonNames[i]);
+ bottomLevel.appendChild(txtNode);
+ newTable.appendChild(midLevel);
+ buttonList.push(button);
+ }
+
+ var topLevelTableEntry = document.createElement("td");
+ topLevelTableEntry.appendChild(newTable);
+
+ var controlBar = document.getElementById("AlgorithmSpecificControls");
+ controlBar.appendChild(topLevelTableEntry);
+
+ return buttonList
+}
+
+
+function addControlToAlgorithmBar(type, name) {
+
+ var element = document.createElement("input");
+
+ element.setAttribute("type", type);
+ element.setAttribute("value", name);
+// element.setAttribute("name", name);
+
+
+ var tableEntry = document.createElement("td");
+
+ tableEntry.appendChild(element);
+
+
+ var controlBar = document.getElementById("AlgorithmSpecificControls");
+
+ //Append the element in page (in span).
+ controlBar.appendChild(tableEntry);
+ return element;
+
+}
+
+
+
+
+function Algorithm(am)
+{
+
+}
+
+
+
+Algorithm.prototype.setCodeAlpha = function(code, newAlpha)
+{
+ var i,j;
+ for (i = 0; i < code.length; i++)
+ for (j = 0; j < code[i].length; j++) {
+ this.cmd("SetAlpha", code[i][j], newAlpha);
+ }
+}
+
+
+Algorithm.prototype.addCodeToCanvasBase = function(code, start_x, start_y, line_height, standard_color, layer)
+{
+ layer = typeof layer !== 'undefined' ? layer : 0;
+ var codeID = Array(code.length);
+ var i, j;
+ for (i = 0; i < code.length; i++)
+ {
+ codeID[i] = new Array(code[i].length);
+ for (j = 0; j < code[i].length; j++)
+ {
+ codeID[i][j] = this.nextIndex++;
+ this.cmd("CreateLabel", codeID[i][j], code[i][j], start_x, start_y + i * line_height, 0);
+ this.cmd("SetForegroundColor", codeID[i][j], standard_color);
+ this.cmd("SetLayer", codeID[i][j], layer);
+ if (j > 0)
+ {
+ this.cmd("AlignRight", codeID[i][j], codeID[i][j-1]);
+ }
+ }
+
+
+ }
+ return codeID;
+}
+
+
+Algorithm.prototype.init = function(am, w, h)
+{
+ this.animationManager = am;
+ am.addListener("AnimationStarted", this, this.disableUI);
+ am.addListener("AnimationEnded", this, this.enableUI);
+ am.addListener("AnimationUndo", this, this.undo);
+ this.canvasWidth = w;
+ this.canvasHeight = h;
+
+ this.actionHistory = [];
+ this.recordAnimation = true;
+ this.commands = []
+}
+
+
+// Overload in subclass
+Algorithm.prototype.sizeChanged = function(newWidth, newHeight)
+{
+
+}
+
+
+
+Algorithm.prototype.implementAction = function(funct, val)
+{
+ var nxt = [funct, val];
+ this.actionHistory.push(nxt);
+ var retVal = funct(val);
+ this.animationManager.StartNewAnimation(retVal);
+}
+
+
+Algorithm.prototype.isAllDigits = function(str)
+{
+ for (var i = str.length - 1; i >= 0; i--)
+ {
+ if (str.charAt(i) < "0" || str.charAt(i) > "9")
+ {
+ return false;
+
+ }
+ }
+ return true;
+}
+
+
+Algorithm.prototype.normalizeNumber = function(input, maxLen)
+{
+ return parseInt(input);
+}
+
+Algorithm.prototype.disableUI = function(event)
+{
+ // to be overridden in base class
+}
+
+Algorithm.prototype.enableUI = function(event)
+{
+ // to be overridden in base class
+}
+
+
+
+function controlKey(keyASCII)
+{
+ return keyASCII == 8 || keyASCII == 9 || keyASCII == 37 || keyASCII == 38 ||
+ keyASCII == 39 || keyASCII == 40 || keyASCII == 46;
+}
+
+
+
+Algorithm.prototype.returnSubmitFloat = function(field, funct, maxsize)
+{
+ if (maxsize != undefined)
+ {
+ field.size = maxsize;
+ }
+ return function(event)
+ {
+ var keyASCII = 0;
+ if(window.event) // IE
+ {
+ keyASCII = event.keyCode
+ }
+ else if (event.which) // Netscape/Firefox/Opera
+ {
+ keyASCII = event.which
+ }
+ // Submit on return
+ if (keyASCII == 13)
+ {
+ funct();
+ }
+ // Control keys (arrows, del, etc) are always OK
+ else if (controlKey(keyASCII))
+ {
+ return;
+ }
+ // - (minus sign) only OK at beginning of number
+ // (For now we will allow anywhere -- hard to see where the beginning of the
+ // number is ...)
+ //else if (keyASCII == 109 && field.value.length == 0)
+ else if (keyASCII == 109)
+ {
+ return;
+ }
+ // Digis are OK if we have enough space
+ else if ((maxsize != undefined || field.value.length < maxsize) &&
+ (keyASCII >= 48 && keyASCII <= 57))
+ {
+ return;
+ }
+ // . (Decimal point) is OK if we haven't had one yet, and there is space
+ else if ((maxsize != undefined || field.value.length < maxsize) &&
+ (keyASCII == 190) && field.value.indexOf(".") == -1)
+
+ {
+ return;
+ }
+ // Nothing else is OK
+ else
+ {
+ return false;
+ }
+
+ }
+}
+
+
+Algorithm.prototype.returnSubmit = function(field, funct, maxsize, intOnly)
+{
+ if (maxsize != undefined)
+ {
+ field.size = maxsize;
+ }
+ return function(event)
+ {
+ var keyASCII = 0;
+ if(window.event) // IE
+ {
+ keyASCII = event.keyCode
+ }
+ else if (event.which) // Netscape/Firefox/Opera
+ {
+ keyASCII = event.which
+ }
+
+ if (keyASCII == 13 && funct !== null)
+ {
+ funct();
+ }
+ else if (keyASCII == 190 || keyASCII == 59 || keyASCII == 173 || keyASCII == 189)
+ {
+ return false;
+
+ }
+ else if ((maxsize != undefined && field.value.length >= maxsize) ||
+ intOnly && (keyASCII < 48 || keyASCII > 57))
+ {
+ if (!controlKey(keyASCII))
+ return false;
+ }
+
+ }
+
+}
+
+Algorithm.prototype.addReturnSubmit = function(field, action)
+{
+ field.onkeydown = this.returnSubmit(field, action, 4, false);
+}
+
+Algorithm.prototype.reset = function()
+{
+ // to be overriden in base class
+ // (Throw exception here?)
+}
+
+Algorithm.prototype.undo = function(event)
+{
+ // Remvoe the last action (the one that we are going to undo)
+ this.actionHistory.pop();
+ // Clear out our data structure. Be sure to implement reset in
+ // every AlgorithmAnimation subclass!
+ this.reset();
+ // Redo all actions from the beginning, throwing out the animation
+ // commands (the animation manager will update the animation on its own).
+ // Note that if you do something non-deterministic, you might cause problems!
+ // Be sure if you do anything non-deterministic (that is, calls to a random
+ // number generator) you clear out the undo stack here and in the animation
+ // manager.
+ //
+ // If this seems horribly inefficient -- it is! However, it seems to work well
+ // in practice, and you get undo for free for all algorithms, which is a non-trivial
+ // gain.
+ var len = this.actionHistory.length;
+ this.recordAnimation = false;
+ for (var i = 0; i < len; i++)
+ {
+ this.actionHistory[i][0](this.actionHistory[i][1]);
+ }
+ this.recordAnimation = true;
+}
+
+
+Algorithm.prototype.clearHistory = function()
+{
+ this.actionHistory = [];
+}
+
+ // Helper method to add text input with nice border.
+ // AS3 probably has a built-in way to do this. Replace when found.
+
+
+ // Helper method to create a command string from a bunch of arguments
+Algorithm.prototype.cmd = function()
+{
+ if (this.recordAnimation)
+ {
+ var command = arguments[0];
+ for(i = 1; i < arguments.length; i++)
+ {
+ command = command + "<;>" + String(arguments[i]);
+ }
+ this.commands.push(command);
+ }
+
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BFS.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BFS.js
new file mode 100644
index 0000000..9035e58
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BFS.js
@@ -0,0 +1,258 @@
+// 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 ``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 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 AUX_ARRAY_WIDTH = 25;
+var AUX_ARRAY_HEIGHT = 25;
+var AUX_ARRAY_START_Y = 50;
+
+var VISITED_START_X = 475;
+var PARENT_START_X = 400;
+
+var HIGHLIGHT_CIRCLE_COLOR = "#000000";
+var BFS_TREE_COLOR = "#0000FF";
+var BFS_QUEUE_HEAD_COLOR = "#0000FF";
+
+
+var QUEUE_START_X = 30;
+var QUEUE_START_Y = 50;
+var QUEUE_SPACING = 30;
+
+
+function BFS(am)
+{
+ this.init(am);
+
+}
+
+BFS.prototype = new Graph();
+BFS.prototype.constructor = BFS;
+BFS.superclass = Graph.prototype;
+
+BFS.prototype.addControls = function()
+{
+ addLabelToAlgorithmBar("Start Vertex: ");
+ this.startField = addControlToAlgorithmBar("Text", "");
+ this.startField.onkeydown = this.returnSubmit(this.startField, this.startCallback.bind(this), 2, true);
+ this.startField.size = 2;
+ this.startButton = addControlToAlgorithmBar("Button", "Run BFS");
+ this.startButton.onclick = this.startCallback.bind(this);
+ BFS.superclass.addControls.call(this);
+}
+
+
+BFS.prototype.init = function(am, w, h)
+{
+ showEdgeCosts = false;
+ BFS.superclass.init.call(this, am, w, h); // TODO: add no edge label flag to this?
+ // Setup called in base class constructor
+}
+
+
+BFS.prototype.setup = function()
+{
+ BFS.superclass.setup.call(this);
+ this.messageID = new Array();
+ this.commands = new Array();
+ this.visitedID = new Array(this.size);
+ this.visitedIndexID = new Array(this.size);
+ this.parentID = new Array(this.size);
+ this.parentIndexID = new Array(this.size);
+
+ for (var i = 0; i < this.size; i++)
+ {
+ this.visitedID[i] = this.nextIndex++;
+ this.visitedIndexID[i] = this.nextIndex++;
+ this.parentID[i] = this.nextIndex++;
+ this.parentIndexID[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.visitedID[i], "f", AUX_ARRAY_WIDTH, AUX_ARRAY_HEIGHT, VISITED_START_X, AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("CreateLabel", this.visitedIndexID[i], i, VISITED_START_X - AUX_ARRAY_WIDTH , AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("SetForegroundColor", this.visitedIndexID[i], VERTEX_INDEX_COLOR);
+ this.cmd("CreateRectangle", this.parentID[i], "", AUX_ARRAY_WIDTH, AUX_ARRAY_HEIGHT, PARENT_START_X, AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("CreateLabel", this.parentIndexID[i], i, PARENT_START_X - AUX_ARRAY_WIDTH , AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("SetForegroundColor", this.parentIndexID[i], VERTEX_INDEX_COLOR);
+
+ }
+ this.cmd("CreateLabel", this.nextIndex++, "Parent", PARENT_START_X - AUX_ARRAY_WIDTH, AUX_ARRAY_START_Y - AUX_ARRAY_HEIGHT * 1.5, 0);
+ this.cmd("CreateLabel", this.nextIndex++, "Visited", VISITED_START_X - AUX_ARRAY_WIDTH, AUX_ARRAY_START_Y - AUX_ARRAY_HEIGHT * 1.5, 0);
+ this.cmd("CreateLabel", this.nextIndex++, "BFS Queue", QUEUE_START_X, QUEUE_START_Y - 30, 0);
+ animationManager.setAllLayers([0, this.currentLayer]);
+ animationManager.StartNewAnimation(this.commands);
+ animationManager.skipForward();
+ animationManager.clearHistory();
+ this.highlightCircleL = this.nextIndex++;
+ this.highlightCircleAL = this.nextIndex++;
+ this.highlightCircleAM= this.nextIndex++
+}
+
+BFS.prototype.startCallback = function(event)
+{
+ var startValue;
+
+ if (this.startField.value != "")
+ {
+ startvalue = this.startField.value;
+ this.startField.value = "";
+ if (parseInt(startvalue) < this.size)
+ this.implementAction(this.doBFS.bind(this),startvalue);
+ }
+}
+
+
+
+BFS.prototype.doBFS = function(startVetex)
+{
+ this.visited = new Array(this.size);
+ this.commands = new Array();
+ this.queue = new Array(this.size);
+ var head = 0;
+ var tail = 0;
+ var queueID = new Array(this.size);
+ var queueSize = 0;
+
+ if (this.messageID != null)
+ {
+ for (var i = 0; i < this.messageID.length; i++)
+ {
+ this.cmd("Delete", this.messageID[i]);
+ }
+ }
+
+ this.rebuildEdges();
+ this.messageID = new Array();
+ for (i = 0; i < this.size; i++)
+ {
+ this.cmd("SetText", this.visitedID[i], "f");
+ this.cmd("SetText", this.parentID[i], "");
+ this.visited[i] = false;
+ queueID[i] = this.nextIndex++;
+
+ }
+ var vertex = parseInt(startVetex);
+ this.visited[vertex] = true;
+ this.queue[tail] = vertex;
+ this.cmd("CreateLabel", queueID[tail], vertex, QUEUE_START_X + queueSize * QUEUE_SPACING, QUEUE_START_Y);
+ queueSize = queueSize + 1;
+ tail = (tail + 1) % (this.size);
+
+
+ while (queueSize > 0)
+ {
+ vertex = this.queue[head];
+ this.cmd("CreateHighlightCircle", this.highlightCircleL, HIGHLIGHT_CIRCLE_COLOR, this.x_pos_logical[vertex], this.y_pos_logical[vertex]);
+ this.cmd("SetLayer", this.highlightCircleL, 1);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAL, HIGHLIGHT_CIRCLE_COLOR,this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + vertex*this.adj_list_height);
+ this.cmd("SetLayer", this.highlightCircleAL, 2);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAM, HIGHLIGHT_CIRCLE_COLOR,this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + vertex*this.adj_matrix_height);
+ this.cmd("SetLayer", this.highlightCircleAM, 3);
+
+ this.cmd("SetTextColor", queueID[head], BFS_QUEUE_HEAD_COLOR);
+
+
+ for (var neighbor = 0; neighbor < this.size; neighbor++)
+ {
+ if (this.adj_matrix[vertex][neighbor] > 0)
+ {
+ this.highlightEdge(vertex, neighbor, 1);
+ this.cmd("SetHighlight", this.visitedID[neighbor], 1);
+ this.cmd("Step");
+ if (!this.visited[neighbor])
+ {
+ this.visited[neighbor] = true;
+ this.cmd("SetText", this.visitedID[neighbor], "T");
+ this.cmd("SetText", this.parentID[neighbor], vertex);
+ this.highlightEdge(vertex, neighbor, 0);
+ this.cmd("Disconnect", this.circleID[vertex], this.circleID[neighbor]);
+ this.cmd("Connect", this.circleID[vertex], this.circleID[neighbor], BFS_TREE_COLOR, this.curve[vertex][neighbor], 1, "");
+ this.queue[tail] = neighbor;
+ this.cmd("CreateLabel", queueID[tail], neighbor, QUEUE_START_X + queueSize * QUEUE_SPACING, QUEUE_START_Y);
+ tail = (tail + 1) % (this.size);
+ queueSize = queueSize + 1;
+ }
+ else
+ {
+ this.highlightEdge(vertex, neighbor, 0);
+ }
+ this.cmd("SetHighlight", this.visitedID[neighbor], 0);
+ this.cmd("Step");
+ }
+
+ }
+ this.cmd("Delete", queueID[head]);
+ head = (head + 1) % (this.size);
+ queueSize = queueSize - 1;
+ for (i = 0; i < queueSize; i++)
+ {
+ var nextQueueIndex = (i + head) % this.size;
+ this.cmd("Move", queueID[nextQueueIndex], QUEUE_START_X + i * QUEUE_SPACING, QUEUE_START_Y);
+ }
+
+ this.cmd("Delete", this.highlightCircleL);
+ this.cmd("Delete", this.highlightCircleAM);
+ this.cmd("Delete", this.highlightCircleAL);
+
+ }
+
+ return this.commands
+
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+BFS.prototype.reset = function()
+{
+ // Throw an error?
+}
+
+
+
+
+BFS.prototype.enableUI = function(event)
+{
+ this.startField.disabled = false;
+ this.startButton.disabled = false;
+ this.startButton
+
+
+ BFS.superclass.enableUI.call(this,event);
+}
+BFS.prototype.disableUI = function(event)
+{
+
+ this.startField.disabled = true;
+ this.startButton.disabled = true;
+
+ BFS.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new BFS(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BPlusTree.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BPlusTree.js
new file mode 100644
index 0000000..1524475
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BPlusTree.js
@@ -0,0 +1,1419 @@
+// 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 ``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 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 FIRST_PRINT_POS_X = 50;
+var PRINT_VERTICAL_GAP = 20;
+var PRINT_MAX = 990;
+var PRINT_HORIZONTAL_GAP = 50;
+
+var MIN_MAX_DEGREE = 3;
+var MAX_MAX_DEGREE = 7;
+
+var HEIGHT_DELTA = 50;
+var NODE_SPACING = 15;
+var STARTING_Y = 30;
+var WIDTH_PER_ELEM = 40;
+var NODE_HEIGHT = 20;
+
+var MESSAGE_X = 5;
+var MESSAGE_Y = 10;
+
+var LINK_COLOR = "#007700";
+var HIGHLIGHT_CIRCLE_COLOR = "#007700";
+var FOREGROUND_COLOR = "#007700";
+var BACKGROUND_COLOR = "#EEFFEE";
+var PRINT_COLOR = FOREGROUND_COLOR;
+
+
+
+function BPlusTree(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+BPlusTree.prototype = new Algorithm();
+BPlusTree.prototype.varructor = BPlusTree;
+BPlusTree.superclass = Algorithm.prototype;
+
+
+
+
+
+BPlusTree.prototype.init = function(am, w, h)
+{
+ BPlusTree.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+
+ this.preemptiveSplit = false
+
+ this.starting_x = w / 2;
+
+ this.addControls();
+
+
+ this.max_keys = 2;
+ this.min_keys = 1;
+ this.split_index = 1;
+
+ this.max_degree = 3;
+
+
+
+
+ this.messageID = this.nextIndex++;
+ this.cmd("CreateLabel", this.messageID, "", MESSAGE_X, MESSAGE_Y, 0);
+ this.moveLabel1ID = this.nextIndex++;
+ this.moveLabel2ID = this.nextIndex++;
+
+ animationManager.StartNewAnimation(this.commands);
+ animationManager.skipForward();
+ animationManager.clearHistory();
+ this.commands = new Array();
+
+ this.first_print_pos_y = h - 3 * PRINT_VERTICAL_GAP;
+
+
+ this.xPosOfNextLabel = 100;
+ this.yPosOfNextLabel = 200;
+}
+
+BPlusTree.prototype.addControls = function()
+{
+ this.controls = [];
+
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.controls.push(this.insertField);
+
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.controls.push(this.insertButton);
+
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 4);
+ this.controls.push(this.deleteField);
+
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.controls.push(this.deleteButton);
+
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4);
+ this.controls.push(this.findField);
+
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.controls.push(this.findButton);
+
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+ this.controls.push(this.printButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "Clear");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+ var i;
+ radioButtonNames = [];
+ for (i = MIN_MAX_DEGREE; i <= MAX_MAX_DEGREE; i++)
+ {
+ radioButtonNames.push("Max. Degree = " + String(i));
+ }
+
+ this.maxDegreeRadioButtons = addRadioButtonGroupToAlgorithmBar(radioButtonNames, "MaxDegree");
+
+ this.maxDegreeRadioButtons[0].checked = true;
+ for(i = 0; i < this.maxDegreeRadioButtons.length; i++)
+ {
+ this.maxDegreeRadioButtons[i].onclick = this.maxDegreeChangedHandler.bind(this,i+MIN_MAX_DEGREE);
+ }
+
+
+// this.premptiveSplitBox = addCheckboxToAlgorithmBar("Preemtive Split / Merge (Even max degree only)");
+// this.premptiveSplitBox.onclick = this.premtiveSplitCallback.bind(this);
+
+
+ // Other buttons ...
+
+}
+
+
+
+
+
+BPlusTree.prototype.reset = function()
+{
+ this.nextIndex = 3;
+ this.max_degree = 3;
+ this.max_keys = 2;
+ this.min_keys = 1;
+ this.split_index = 1;
+ // NOTE: The order of these last two this.commands matters!
+ this.treeRoot = null;
+ this.ignoreInputs = true;
+ // maxDegreeButtonArray[this.max_degree].selected = true;
+ this.ignoreInputs = false;
+}
+
+
+BPlusTree.prototype.enableUI = function(event)
+{
+ var i;
+ for (i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+ for (i = 0; i < this.maxDegreeRadioButtons.length; i++)
+ {
+ this.maxDegreeRadioButtons[i].disabled = false;
+ }
+}
+
+BPlusTree.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+
+ for (i = 0; i < this.maxDegreeRadioButtons.length; i++)
+ {
+ this.maxDegreeRadioButtons[i].disabled = true;
+ }
+
+}
+
+
+//TODO: Fix me!
+BPlusTree.prototype.maxDegreeChangedHandler = function(newMaxDegree, event)
+{
+ if (this.max_degree != newMaxDegree)
+ {
+ this.implementAction(this.changeDegree.bind(this), newMaxDegree);
+ }
+}
+
+
+
+BPlusTree.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+BPlusTree.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value;
+ if (deletedValue != "")
+ {
+ deletedValue = this.normalizeNumber(this.deleteField.value, 4);
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+BPlusTree.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clearTree.bind(this), "");
+}
+
+
+BPlusTree.prototype.premtiveSplitCallback = function(event)
+{
+// if (this.preemptiveSplit != this.premptiveSplitBox.checked)
+// {
+// this.implementAction(this.changePreemtiveSplit.bind(this), this.premptiveSplitBox.checked);
+// }
+}
+
+
+BPlusTree.prototype.changePreemtiveSplit = function(newValue)
+{
+// this.commands = new Array();
+// this.cmd("Step");
+// this.preemptiveSplit = newValue;
+// if (this.premptiveSplitBox.checked != this.preemptiveSplit)
+// {
+// this.premptiveSplitBox.checked = this.preemptiveSplit;
+// }
+// return this.commands;
+}
+
+
+BPlusTree.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+
+
+BPlusTree.prototype.printTree = function(unused)
+{
+
+ this.commands = new Array();
+ this.cmd("SetText", this.messageID, "Printing tree");
+ var firstLabel = this.nextIndex;
+
+ if (this.treeRoot != null)
+ {
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+
+ var tmp = this.treeRoot;
+
+ this.cmd("SetHighlight", tmp.graphicID, 1);
+ this.cmd("Step");
+ while (!tmp.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tmp.graphicID, tmp.children[0].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tmp.graphicID, 0);
+ this.cmd("SetHighlight", tmp.children[0].graphicID, 1);
+ this.cmd("SetEdgeHighlight", tmp.graphicID, tmp.children[0].graphicID, 0);
+ this.cmd("Step");
+ tmp = tmp.children[0];
+ }
+
+ while (tmp!= null)
+ {
+ this.cmd("SetHighlight", tmp.graphicID, 1);
+ for (i = 0; i < tmp.numKeys; i++)
+ {
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tmp.keys[i], this.getLabelX(tmp, i), tmp.y);
+ this.cmd("SetForegroundColor", nextLabelID, PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+ this.xPosOfNextLabel += PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > PRINT_MAX)
+ {
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += PRINT_VERTICAL_GAP;
+ }
+ }
+ if (tmp.next != null)
+ {
+ this.cmd("SetEdgeHighlight", tmp.graphicID, tmp.next.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", tmp.graphicID, tmp.next.graphicID, 0);
+ }
+ this.cmd("SetHighlight", tmp.graphicID, 0);
+ tmp = tmp.next;
+ }
+ this.cmd("Step");
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = firstLabel;
+ }
+ this.cmd("SetText", this.messageID, "");
+ return this.commands;
+}
+
+
+
+
+
+
+
+
+BPlusTree.prototype.clearTree = function(ignored)
+{
+ this.commands = new Array();
+ this.deleteTree(this.treeRoot);
+ this.treeRoot = null;
+ this.nextIndex = 3;
+ return this.commands;
+}
+
+BPlusTree.prototype.deleteTree = function(tree)
+{
+ if (tree != null)
+ {
+ if (!tree.isLeaf)
+ {
+ for (var i = 0; i <= tree.numKeys; i++)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.children[i].graphicID);
+ this.deleteTree(tree.children[i]);
+ tree.children[i] == null;
+ }
+ }
+ this.cmd("Delete", tree.graphicID);
+ }
+}
+
+
+BPlusTree.prototype.changeDegree = function(degree)
+{
+ this.commands = new Array();
+ this.deleteTree(this.treeRoot);
+ this.treeRoot = null;
+ this.nextIndex = 3;
+ var newDegree = degree;
+ this.ignoreInputs = true;
+ //TODO: Check me!
+ this.maxDegreeRadioButtons[newDegree - MIN_MAX_DEGREE].checked = true;
+
+ this.ignoreInputs = false;
+ this.max_degree = newDegree;
+ this.max_keys = newDegree - 1;
+ this.min_keys = Math.floor((newDegree + 1) / 2) - 1;
+ this.split_index = Math.floor((newDegree) / 2);
+ if (this.commands.length == 0)
+ {
+ this.cmd("Step");
+ }
+ if (newDegree % 2 != 0 && this.preemptiveSplit)
+ {
+ this.preemptiveSplit = false;
+ this.premptiveSplitBox.checked = false;
+ }
+ return this.commands;
+}
+
+
+BPlusTree.prototype.findCallback = function(event)
+{
+ var findValue;
+ findValue = this.normalizeNumber(this.findField.value, 4);
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+BPlusTree.prototype.findElement = function(findValue)
+{
+ this.commands = new Array();
+
+ this.cmd("SetText", this.messageID, "Finding " + findValue);
+ this.findInTree(this.treeRoot, findValue);
+
+ return this.commands;
+}
+
+
+
+BPlusTree.prototype.findInTree = function(tree, val)
+{
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ var i;
+ for (i = 0; i < tree.numKeys && tree.keys[i] < val; i++);
+ if (i == tree.numKeys)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 0);
+ this.findInTree(tree.children[tree.numKeys], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetText", this.messageID, "Element " + val + " is not in the tree");
+ }
+ }
+ else if (tree.keys[i] > val)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 0);
+ this.findInTree(tree.children[i], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetText", this.messageID, "Element " + val + " is not in the tree");
+ }
+ }
+ else
+ {
+ if (tree.isLeaf)
+ {
+ this.cmd("SetTextColor", tree.graphicID, "#FF0000", i);
+ this.cmd("SetText", this.messageID, "Element " + val + " found");
+ this.cmd("Step");
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ this.cmd("Step");
+ }
+ else
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 0);
+ this.findInTree(tree.children[i+1], val);
+ }
+ }
+ }
+ else
+ {
+ this.cmd("SetText", this.messageID, "Element " + val + " is not in the tree");
+ }
+}
+
+
+BPlusTree.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+
+ this.cmd("SetText", this.messageID, "Inserting " + insertedValue);
+ this.cmd("Step");
+
+ if (this.treeRoot == null)
+ {
+ this.treeRoot = new BTreeNode(this.nextIndex++, this.starting_x, STARTING_Y);
+ this.cmd("CreateBTreeNode",this.treeRoot.graphicID, WIDTH_PER_ELEM, NODE_HEIGHT, 1, this.starting_x, STARTING_Y, BACKGROUND_COLOR, FOREGROUND_COLOR);
+ this.treeRoot.keys[0] = insertedValue;
+ this.cmd("SetText", this.treeRoot.graphicID, insertedValue, 0);
+ }
+ else
+ {
+ this.insert(this.treeRoot, insertedValue);
+ if (!this.treeRoot.isLeaf)
+ {
+ this.resizeTree();
+ }
+ }
+
+ this.cmd("SetText", this.messageID, "");
+
+ return this.commands;
+
+}
+
+
+
+
+BPlusTree.prototype.insert = function(tree, insertValue)
+{
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ if (tree.isLeaf)
+ {
+ this.cmd("SetText", this.messageID, "Inserting " + insertValue + ". Inserting into a leaf");
+ tree.numKeys++;
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ var insertIndex = tree.numKeys - 1;
+ while (insertIndex > 0 && tree.keys[insertIndex - 1] > insertValue)
+ {
+ tree.keys[insertIndex] = tree.keys[insertIndex - 1];
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ insertIndex--;
+ }
+ tree.keys[insertIndex] = insertValue;
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.next != null)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.next.graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ tree.numKeys);
+
+
+ }
+ this.resizeTree();
+ this.insertRepair(tree);
+ }
+ else
+ {
+ var findIndex = 0;
+ while (findIndex < tree.numKeys && tree.keys[findIndex] < insertValue)
+ {
+ findIndex++;
+ }
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[findIndex].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[findIndex].graphicID, 0);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.insert(tree.children[findIndex], insertValue);
+ }
+}
+
+BPlusTree.prototype.insertRepair = function(tree)
+{
+ if (tree.numKeys <= this.max_keys)
+ {
+ return;
+ }
+ else if (tree.parent == null)
+ {
+ this.treeRoot = this.split(tree);
+ return;
+ }
+ else
+ {
+ var newNode = this.split(tree);
+ this.insertRepair(newNode);
+ }
+}
+
+BPlusTree.prototype.split = function(tree)
+{
+ this.cmd("SetText", this.messageID, "Node now contains too many keys. Splittig ...");
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ var rightNode = new BTreeNode(this.nextIndex++, tree.x + 100, tree.y);
+
+ var risingNode = tree.keys[this.split_index];
+
+ var i;
+ var parentIndex
+ if (tree.parent != null)
+ {
+ var currentParent = tree.parent;
+ for (parentIndex = 0; parentIndex < currentParent.numKeys + 1 && currentParent.children[parentIndex] != tree; parentIndex++);
+ if (parentIndex == currentParent.numKeys + 1)
+ {
+ throw new Error("Couldn't find which child we were!");
+ }
+ this.cmd("SetNumElements", currentParent.graphicID, currentParent.numKeys + 1);
+ for (i = currentParent.numKeys; i > parentIndex; i--)
+ {
+ currentParent.children[i+1] = currentParent.children[i];
+ this.cmd("Disconnect", currentParent.graphicID, currentParent.children[i].graphicID);
+ this.cmd("Connect", currentParent.graphicID, currentParent.children[i].graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i+1);
+
+ currentParent.keys[i] = currentParent.keys[i-1];
+ this.cmd("SetText", currentParent.graphicID, currentParent.keys[i] ,i);
+ }
+ currentParent.numKeys++;
+ currentParent.keys[parentIndex] = risingNode;
+ this.cmd("SetText", currentParent.graphicID, "", parentIndex);
+ this.cmd("CreateLabel", this.moveLabel1ID, risingNode, this.getLabelX(tree, this.split_index), tree.y)
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(currentParent, parentIndex), currentParent.y)
+
+
+
+
+ currentParent.children[parentIndex+1] = rightNode;
+ rightNode.parent = currentParent;
+
+ }
+
+ var rightSplit;
+
+ if (tree.isLeaf)
+ {
+ rightSplit = this.split_index;
+ rightNode.next = tree.next;
+ tree.next = rightNode;
+ }
+ else
+ {
+ rightSplit = this.split_index + 1;
+ }
+
+ rightNode.numKeys = tree.numKeys - rightSplit;
+
+ this.cmd("CreateBTreeNode",rightNode.graphicID, WIDTH_PER_ELEM, NODE_HEIGHT, tree.numKeys -rightSplit, tree.x, tree.y, BACKGROUND_COLOR, FOREGROUND_COLOR);
+
+ if (tree.isLeaf)
+ {
+ if (rightNode.next != null)
+ {
+
+ this.cmd("Disconnect", tree.graphicID, rightNode.next.graphicID);
+ this.cmd("Connect", rightNode.graphicID,
+ rightNode.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ rightNode.numKeys);
+
+
+ }
+ this.cmd("Connect", tree.graphicID,
+ rightNode.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ this.split_index);
+ }
+
+
+ for (var i = rightSplit; i < tree.numKeys + 1; i++)
+ {
+ rightNode.children[i - rightSplit] = tree.children[i];
+ if (tree.children[i] != null)
+ {
+ rightNode.isLeaf = false;
+ this.cmd("Disconnect", tree.graphicID, tree.children[i].graphicID);
+
+ this.cmd("Connect", rightNode.graphicID,
+ rightNode.children[i - rightSplit].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i - rightSplit);
+ if (tree.children[i] != null)
+ {
+ tree.children[i].parent = rightNode;
+ }
+ tree.children[i] = null;
+
+ }
+ }
+ for (i =rightSplit; i < tree.numKeys; i++)
+ {
+ rightNode.keys[i - rightSplit] = tree.keys[i];
+ this.cmd("SetText", rightNode.graphicID, rightNode.keys[i -rightSplit], i - rightSplit);
+ }
+ var leftNode = tree;
+ leftNode.numKeys = this.split_index;
+ // TO MAKE UNDO WORK -- CAN REMOVE LATER VV
+ for (i = this.split_index; i < tree.numKeys; i++)
+ {
+ this.cmd("SetText", tree.graphicID, "", i);
+ }
+ // TO MAKE UNDO WORK -- CAN REMOVE LATER ^^
+ this.cmd("SetNumElements", tree.graphicID, this.split_index);
+
+ if (tree.parent != null)
+ {
+ this.cmd("Connect", currentParent.graphicID, rightNode.graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ parentIndex + 1);
+ this.resizeTree();
+ this.cmd("Step")
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", currentParent.graphicID, risingNode, parentIndex);
+ return tree.parent;
+ }
+ else // if (tree.parent == null)
+ {
+ this.treeRoot = new BTreeNode(this.nextIndex++, this.starting_x, STARTING_Y);
+ this.cmd("CreateBTreeNode",this.treeRoot.graphicID, WIDTH_PER_ELEM, NODE_HEIGHT, 1, this.starting_x, STARTING_Y,BACKGROUND_COLOR, FOREGROUND_COLOR);
+ this.treeRoot.keys[0] = risingNode;
+ this.cmd("SetText", this.treeRoot.graphicID, risingNode, 0);
+ this.treeRoot.children[0] = leftNode;
+ this.treeRoot.children[1] = rightNode;
+ leftNode.parent = this.treeRoot;
+ rightNode.parent = this.treeRoot;
+ this.cmd("Connect", this.treeRoot.graphicID, leftNode.graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ 0); // Connection Point
+ this.cmd("Connect", this.treeRoot.graphicID, rightNode.graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ 1); // Connection Point
+ this.treeRoot.isLeaf = false;
+ return this.treeRoot;
+ }
+
+
+
+}
+
+BPlusTree.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在刪除 "+deletedValue);
+ this.cmd("Step");
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 0, "");
+ this.doDelete(this.treeRoot, deletedValue);
+ if (this.treeRoot.numKeys == 0)
+ {
+ this.cmd("Delete", this.treeRoot.graphicID);
+ this.treeRoot = this.treeRoot.children[0];
+ this.treeRoot.parent = null;
+ this.resizeTree();
+ }
+ return this.commands;
+}
+
+
+
+
+BPlusTree.prototype.doDelete = function(tree, val)
+{
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ var i;
+ for (i = 0; i < tree.numKeys && tree.keys[i] < val; i++);
+ if (i == tree.numKeys)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 0);
+ this.doDelete(tree.children[tree.numKeys], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ }
+ else if (!tree.isLeaf && tree.keys[i] == val)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 0);
+ this.doDelete(tree.children[i+1], val);
+ }
+ else if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 0);
+ this.doDelete(tree.children[i], val);
+ }
+ else if (tree.isLeaf && tree.keys[i] == val)
+ {
+ this.cmd("SetTextColor", tree.graphicID, 0xFF0000, i);
+ this.cmd("Step");
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ for (var j = i; j < tree.numKeys - 1; j++)
+ {
+ tree.keys[j] = tree.keys[j+1];
+ this.cmd("SetText", tree.graphicID, tree.keys[j], j);
+ }
+ tree.numKeys--;
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys);
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ if (tree.next != null)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.next.graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ tree.numKeys);
+ }
+
+ // Bit of a hack -- if we remove the smallest element in a leaf, then find the *next* smallest element
+ // (somewhat tricky if the leaf is now empty!), go up our parent stack, and fix index keys
+ if (i == 0 && tree.parent != null)
+ {
+ var nextSmallest = "";
+ var parentNode = tree.parent;
+ var parentIndex;
+ for (parentIndex = 0; parentNode.children[parentIndex] != tree; parentIndex++);
+ if (tree.numKeys == 0)
+ {
+ if (parentIndex == parentNode.numKeys)
+ {
+ nextSmallest == "";
+ }
+ else
+ {
+ nextSmallest = parentNode.children[parentIndex+1].keys[0];
+ }
+ }
+ else
+ {
+ nextSmallest = tree.keys[0];
+ }
+ while (parentNode != null)
+ {
+ if (parentIndex > 0 && parentNode.keys[parentIndex - 1] == val)
+ {
+ parentNode.keys[parentIndex - 1] = nextSmallest;
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[parentIndex - 1], parentIndex - 1);
+ }
+ var grandParent = parentNode.parent;
+ for (parentIndex = 0; grandParent != null && grandParent.children[parentIndex] != parentNode; parentIndex++);
+ parentNode = grandParent;
+
+ }
+
+ }
+ this.repairAfterDelete(tree);
+
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+
+ }
+}
+
+
+
+BPlusTree.prototype.mergeRight = function(tree)
+{
+ this.cmd("SetText", this.messageID, "Merging node");
+
+ var parentNode = tree.parent;
+ var parentIndex = 0;
+ for (parentIndex = 0; parentNode.children[parentIndex] != tree; parentIndex++);
+ var rightSib = parentNode.children[parentIndex+1];
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("SetHighlight", parentNode.graphicID, 1);
+ this.cmd("SetHighlight", rightSib.graphicID, 1);
+
+ this.cmd("Step");
+ if (tree.isLeaf)
+ {
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys + rightSib.numKeys);
+ }
+ else
+ {
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys + rightSib.numKeys + 1);
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys);
+ this.cmd("CreateLabel", this.moveLabel1ID, parentNode.keys[parentIndex], this.getLabelX(parentNode, parentIndex), parentNode.y);
+ tree.keys[tree.numKeys] = parentNode.keys[parentIndex];
+ }
+ tree.x = (tree.x + rightSib.x) / 2
+ this.cmd("SetPosition", tree.graphicID, tree.x, tree.y);
+
+
+ var fromParentIndex = tree.numKeys;
+
+
+ for (var i = 0; i < rightSib.numKeys; i++)
+ {
+ var insertIndex = tree.numKeys + 1 + i;
+ if (tree.isLeaf)
+ {
+ insertIndex -= 1;
+ }
+ tree.keys[insertIndex] = rightSib.keys[i];
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ this.cmd("SetText", rightSib.graphicID, "", i);
+ }
+ if (!tree.isLeaf)
+ {
+ for (i = 0; i <= rightSib.numKeys; i++)
+ {
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.children[i].graphicID);
+ tree.children[tree.numKeys + 1 + i] = rightSib.children[i];
+ tree.children[tree.numKeys + 1 + i].parent = tree;
+ this.cmd("Connect", tree.graphicID,
+ tree.children[tree.numKeys + 1 + i].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ tree.numKeys + 1 + i);
+ }
+ tree.numKeys = tree.numKeys + rightSib.numKeys + 1;
+
+ }
+ else
+ {
+ tree.numKeys = tree.numKeys + rightSib.numKeys;
+
+ tree.next = rightSib.next;
+ if (rightSib.next != null)
+ {
+ this.cmd("Connect", tree.graphicID,
+ tree.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ tree.numKeys);
+
+ }
+ }
+ this.cmd("Disconnect", parentNode.graphicID, rightSib.graphicID);
+ for (i = parentIndex+1; i < parentNode.numKeys; i++)
+ {
+ this.cmd("Disconnect", parentNode.graphicID, parentNode.children[i+1].graphicID);
+ parentNode.children[i] = parentNode.children[i+1];
+ this.cmd("Connect", parentNode.graphicID,
+ parentNode.children[i].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i);
+ parentNode.keys[i-1] = parentNode.keys[i];
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[i-1], i-1);
+ }
+ this.cmd("SetText", parentNode.graphicID, "", parentNode.numKeys - 1);
+ parentNode.numKeys--;
+ this.cmd("SetNumElements", parentNode.graphicID, parentNode.numKeys);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetHighlight", parentNode.graphicID, 0);
+ this.cmd("SetHighlight", rightSib.graphicID, 0);
+
+ this.cmd("Delete", rightSib.graphicID);
+ if (!tree.isLeaf)
+ {
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(tree, fromParentIndex), tree.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", tree.graphicID, tree.keys[fromParentIndex], fromParentIndex);
+ }
+ // this.resizeTree();
+
+ this.cmd("SetText", this.messageID, "");
+ return tree;
+}
+
+
+BPlusTree.prototype.stealFromRight = function(tree, parentIndex)
+{
+ // Steal from right sibling
+ var parentNode = tree.parent;
+
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys+1);
+
+ this.cmd("SetText", this.messageID, "Stealing from right sibling");
+
+ var rightSib = parentNode.children[parentIndex + 1];
+ tree.numKeys++;
+
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+
+ if (tree.isLeaf)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.next.graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ tree.numKeys);
+ }
+
+
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys - 1);
+ this.cmd("SetText", parentNode.graphicID, "", parentIndex);
+ this.cmd("SetText", rightSib.graphicID, "", 0);
+
+ if (tree.isLeaf)
+ {
+ this.cmd("CreateLabel", this.moveLabel1ID, rightSib.keys[1], this.getLabelX(rightSib, 1), rightSib.y)
+ this.cmd("CreateLabel", this.moveLabel2ID, rightSib.keys[0], this.getLabelX(rightSib, 0), rightSib.y)
+ tree.keys[tree.numKeys - 1] = rightSib.keys[0];
+ parentNode.keys[parentIndex] = rightSib.keys[1];
+
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.moveLabel1ID, rightSib.keys[0], this.getLabelX(rightSib, 0), rightSib.y)
+ this.cmd("CreateLabel", this.moveLabel2ID, parentNode.keys[parentIndex], this.getLabelX(parentNode, parentIndex), parentNode.y)
+ tree.keys[tree.numKeys - 1] = parentNode.keys[parentIndex];
+ parentNode.keys[parentIndex] = rightSib.keys[0];
+ }
+
+
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(parentNode, parentIndex), parentNode.y);
+ this.cmd("Move", this.moveLabel2ID, this.getLabelX(tree, tree.numKeys - 1), tree.y);
+
+ this.cmd("Step")
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("Delete", this.moveLabel2ID);
+
+
+
+
+ this.cmd("SetText", tree.graphicID, tree.keys[tree.numKeys - 1], tree.numKeys - 1);
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[parentIndex], parentIndex);
+ if (!tree.isLeaf)
+ {
+ tree.children[tree.numKeys] = rightSib.children[0];
+ tree.children[tree.numKeys].parent = tree;
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.children[0].graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.children[tree.numKeys].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ tree.numKeys);
+ // TODO::CHECKME!
+
+ for (var i = 1; i < rightSib.numKeys + 1; i++)
+ {
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.children[i].graphicID);
+ rightSib.children[i-1] = rightSib.children[i];
+ this.cmd("Connect", rightSib.graphicID,
+ rightSib.children[i-1].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i-1);
+ }
+
+ }
+ for (i = 1; i < rightSib.numKeys; i++)
+ {
+ rightSib.keys[i-1] = rightSib.keys[i];
+ this.cmd("SetText", rightSib.graphicID, rightSib.keys[i-1], i-1);
+ }
+ this.cmd("SetText", rightSib.graphicID, "", rightSib.numKeys-1);
+ rightSib.numKeys--;
+ this.cmd("SetNumElements", rightSib.graphicID, rightSib.numKeys);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+
+ if (tree.isLeaf)
+ {
+
+ if (rightSib.next != null)
+ {
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.next.graphicID);
+ this.cmd("Connect", rightSib.graphicID,
+ rightSib.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ rightSib.numKeys);
+ }
+
+ }
+ return tree;
+
+}
+
+
+ BPlusTree.prototype.stealFromLeft = function(tree, parentIndex)
+{
+ var parentNode = tree.parent;
+ // Steal from left sibling
+ tree.numKeys++;
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+
+ if (tree.isLeaf && tree.next != null)
+ {
+
+ this.cmd("Disconnect", tree.graphicID, tree.next.graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.next.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ tree.numKeys);
+ }
+
+
+ this.cmd("SetText", this.messageID, "Node has too few keys. Stealing from left sibling.");
+
+ for (i = tree.numKeys - 1; i > 0; i--)
+ {
+ tree.keys[i] = tree.keys[i-1];
+ this.cmd("SetText", tree.graphicID, tree.keys[i], i);
+ }
+ var leftSib = parentNode.children[parentIndex -1];
+
+ this.cmd("SetText", tree.graphicID, "", 0);
+ this.cmd("SetText", parentNode.graphicID, "", parentIndex - 1);
+ this.cmd("SetText", leftSib.graphicID, "", leftSib.numKeys - 1);
+
+
+ if (tree.isLeaf)
+ {
+ this.cmd("CreateLabel", this.moveLabel1ID, leftSib.keys[leftSib.numKeys - 1], this.getLabelX(leftSib, leftSib.numKeys - 1), leftSib.y)
+ this.cmd("CreateLabel", this.moveLabel2ID,leftSib.keys[leftSib.numKeys - 1], this.getLabelX(leftSib, leftSib.numKeys - 1), leftSib.y)
+ tree.keys[0] = leftSib.keys[leftSib.numKeys - 1];
+ parentNode.keys[parentIndex-1] = leftSib.keys[leftSib.numKeys - 1];
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.moveLabel1ID, leftSib.keys[leftSib.numKeys - 1], this.getLabelX(leftSib, leftSib.numKeys - 1), leftSib.y)
+ this.cmd("CreateLabel", this.moveLabel2ID, parentNode.keys[parentIndex - 1], this.getLabelX(parentNode, parentIndex - 1), parentNode.y)
+ tree.keys[0] = parentNode.keys[parentIndex - 1];
+ parentNode.keys[parentIndex-1] = leftSib.keys[leftSib.numKeys - 1];
+ }
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(parentNode, parentIndex - 1), parentNode.y);
+ this.cmd("Move", this.moveLabel2ID, this.getLabelX(tree, 0), tree.y);
+
+ this.cmd("Step")
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("Delete", this.moveLabel2ID);
+
+
+ if (!tree.isLeaf)
+ {
+ for (var i = tree.numKeys; i > 0; i--)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.children[i-1].graphicID);
+ tree.children[i] =tree.children[i-1];
+ this.cmd("Connect", tree.graphicID,
+ tree.children[i].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i);
+ }
+ tree.children[0] = leftSib.children[leftSib.numKeys];
+ this.cmd("Disconnect", leftSib.graphicID, leftSib.children[leftSib.numKeys].graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.children[0].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ 0);
+ leftSib.children[leftSib.numKeys] = null;
+ tree.children[0].parent = tree;
+
+ }
+
+ this.cmd("SetText", tree.graphicID, tree.keys[0], 0);
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[parentIndex - 1], parentIndex - 1);
+ this.cmd("SetText", leftSib.graphicID,"", leftSib.numKeys - 1);
+
+ leftSib.numKeys--;
+ this.cmd("SetNumElements", leftSib.graphicID, leftSib.numKeys);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+
+
+ if (tree.isLeaf)
+ {
+ this.cmd("Disconnect", leftSib.graphicID, tree.graphicID);
+ this.cmd("Connect", leftSib.graphicID,
+ tree.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ "", // Label
+ leftSib.numKeys);
+
+ }
+
+
+ return tree;
+}
+
+
+BPlusTree.prototype.repairAfterDelete = function(tree)
+{
+ if (tree.numKeys < this.min_keys)
+ {
+ if (tree.parent == null)
+ {
+ if (tree.numKeys == 0)
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.treeRoot = tree.children[0];
+ if (this.treeRoot != null)
+ this.treeRoot.parent = null;
+ this.resizeTree();
+ }
+ }
+ else
+ {
+ var parentNode = tree.parent;
+ for (var parentIndex = 0; parentNode.children[parentIndex] != tree; parentIndex++);
+
+
+ if (parentIndex > 0 && parentNode.children[parentIndex - 1].numKeys > this.min_keys)
+ {
+ this.stealFromLeft(tree, parentIndex);
+
+ }
+ else if (parentIndex < parentNode.numKeys && parentNode.children[parentIndex + 1].numKeys > this.min_keys)
+ {
+ this.stealFromRight(tree,parentIndex);
+
+ }
+ else if (parentIndex == 0)
+ {
+ // Merge with right sibling
+ var nextNode = this.mergeRight(tree);
+ this.repairAfterDelete(nextNode.parent);
+ }
+ else
+ {
+ // Merge with left sibling
+ nextNode = this.mergeRight(parentNode.children[parentIndex-1]);
+ this.repairAfterDelete(nextNode.parent);
+
+ }
+
+
+ }
+ }
+ else if (tree.parent != null)
+ {
+
+
+ }
+}
+
+
+
+
+
+
+
+
+
+BPlusTree.prototype.getLabelX = function(tree, index)
+{
+ return tree.x - WIDTH_PER_ELEM * tree.numKeys / 2 + WIDTH_PER_ELEM / 2 + index * WIDTH_PER_ELEM;
+}
+
+BPlusTree.prototype.resizeTree = function()
+{
+ this.resizeWidths(this.treeRoot);
+ this.setNewPositions(this.treeRoot, this.starting_x, STARTING_Y);
+ this.animateNewPositions(this.treeRoot);
+}
+
+BPlusTree.prototype.setNewPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ tree.x = xPosition;
+ if (!tree.isLeaf)
+ {
+ var leftEdge = xPosition - tree.width / 2;
+ var priorWidth = 0;
+ for (var i = 0; i < tree.numKeys+1; i++)
+ {
+ this.setNewPositions(tree.children[i], leftEdge + priorWidth + tree.widths[i] / 2, yPosition+HEIGHT_DELTA);
+ priorWidth += tree.widths[i];
+ }
+ }
+ }
+}
+
+BPlusTree.prototype.animateNewPositions = function(tree)
+{
+ if (tree == null)
+ {
+ return;
+ }
+ var i;
+ for (i = 0; i < tree.numKeys + 1; i++)
+ {
+ this.animateNewPositions(tree.children[i]);
+ }
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+}
+
+BPlusTree.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ if (tree.isLeaf)
+ {
+ for (var i = 0; i < tree.numKeys + 1; i++)
+ {
+ tree.widths[i] = 0;
+ }
+ tree.width = tree.numKeys * WIDTH_PER_ELEM + NODE_SPACING;
+ return tree.width;
+ }
+ else
+ {
+ var treeWidth = 0;
+ for (i = 0; i < tree.numKeys+1; i++)
+ {
+ tree.widths[i] = this.resizeWidths(tree.children[i]);
+ treeWidth = treeWidth + tree.widths[i];
+ }
+ treeWidth = Math.max(treeWidth, tree.numKeys * WIDTH_PER_ELEM + NODE_SPACING);
+ tree.width = treeWidth;
+ return treeWidth;
+ }
+}
+
+
+
+
+function BTreeNode(id, initialX, initialY)
+{
+ this.widths = [];
+ this.keys = [];
+ this.children = [];
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.numKeys = 1;
+ this.isLeaf = true;
+ this.parent = null;
+
+ this.leftWidth = 0;
+ this.rightWidth = 0;
+ // Could use children for next pointer, but I got lazy ...
+ this.next = null;
+
+
+}
+
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new BPlusTree(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BST.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BST.js
new file mode 100644
index 0000000..e7dfe09
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BST.js
@@ -0,0 +1,675 @@
+// 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 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
+
+
+// Constants.
+
+BST.LINK_COLOR = "#007700";
+BST.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+BST.FOREGROUND_COLOR = "#007700";
+BST.BACKGROUND_COLOR = "#EEFFEE";
+BST.PRINT_COLOR = BST.FOREGROUND_COLOR;
+
+BST.WIDTH_DELTA = 50;
+BST.HEIGHT_DELTA = 50;
+BST.STARTING_Y = 50;
+
+
+BST.FIRST_PRINT_POS_X = 50;
+BST.PRINT_VERTICAL_GAP = 20;
+BST.PRINT_HORIZONTAL_GAP = 50;
+
+
+
+function BST(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+BST.prototype = new Algorithm();
+BST.prototype.constructor = BST;
+BST.superclass = Algorithm.prototype;
+
+BST.prototype.init = function(am, w, h)
+{
+ var sc = BST.superclass;
+ this.startingX = w / 2;
+ this.first_print_pos_y = h - 2 * BST.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 10, 0);
+ this.nextIndex = 1;
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+BST.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 4);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+}
+
+BST.prototype.reset = function()
+{
+ this.nextIndex = 1;
+ this.treeRoot = null;
+}
+
+BST.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value;
+ // Get text value
+ insertedValue = this.normalizeNumber(insertedValue, 4);
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this), insertedValue);
+ }
+}
+
+BST.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value;
+ if (deletedValue != "")
+ {
+ deletedValue = this.normalizeNumber(deletedValue, 4);
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+
+BST.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+BST.prototype.printTree = function(unused)
+{
+ this.commands = [];
+
+ if (this.treeRoot != null)
+ {
+ this.highlightID = this.nextIndex++;
+ var firstLabel = this.nextIndex;
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, this.treeRoot.x, this.treeRoot.y);
+ this.xPosOfNextLabel = BST.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.treeRoot);
+ this.cmd("Delete", this.highlightID);
+ this.cmd("Step")
+
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+}
+
+BST.prototype.printTreeRec = function(tree)
+{
+ this.cmd("Step");
+ if (tree.left != null)
+ {
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.printTreeRec(tree.left);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.data, tree.x, tree.y);
+ this.cmd("SetForegroundColor", nextLabelID, BST.PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += BST.PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = BST.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += BST.PRINT_VERTICAL_GAP;
+
+ }
+ if (tree.right != null)
+ {
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.printTreeRec(tree.right);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ return;
+}
+
+BST.prototype.findCallback = function(event)
+{
+ var findValue;
+ findValue = this.normalizeNumber(this.findField.value, 4);
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+BST.prototype.findElement = function(findValue)
+{
+ this.commands = [];
+
+ this.highlightID = this.nextIndex++;
+
+ this.doFind(this.treeRoot, findValue);
+
+
+ return this.commands;
+}
+
+
+BST.prototype.doFind = function(tree, value)
+{
+ this.cmd("SetText", 0, "正在搜索 "+value);
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (tree.data == value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " = " + value + " (找不到元素)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "已找到 :"+value);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ else
+ {
+ if (tree.data > value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " < " + tree.data + " (访问左子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.left!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.doFind(tree.left, value);
+ }
+ else
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " > " + tree.data + " (访问右子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.right!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.doFind(tree.right, value);
+ }
+
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + "< 空树 > (找不到元素)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + " (找不到元素)");
+ }
+}
+
+BST.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在添加 "+insertedValue);
+ this.highlightID = this.nextIndex++;
+
+ if (this.treeRoot == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, insertedValue, this.startingX, BST.STARTING_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, BST.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, BST.BACKGROUND_COLOR);
+ this.cmd("Step");
+ this.treeRoot = new BSTNode(insertedValue, this.nextIndex, this.startingX, BST.STARTING_Y)
+ this.nextIndex += 1;
+ }
+ else
+ {
+ this.cmd("CreateCircle", this.nextIndex, insertedValue, 100, 100);
+ this.cmd("SetForegroundColor", this.nextIndex, BST.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, BST.BACKGROUND_COLOR);
+ this.cmd("Step");
+ var insertElem = new BSTNode(insertedValue, this.nextIndex, 100, 100)
+
+
+ this.nextIndex += 1;
+ this.cmd("SetHighlight", insertElem.graphicID, 1);
+ this.insert(insertElem, this.treeRoot)
+ this.resizeTree();
+ }
+ this.cmd("SetText", 0, "");
+ return this.commands;
+}
+
+
+BST.prototype.insert = function(elem, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID , 1);
+ this.cmd("SetHighlight", elem.graphicID , 1);
+
+ if (elem.data < tree.data)
+ {
+ this.cmd("SetText", 0, elem.data + " < " + tree.data + ",访问左子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, elem.data + " >= " + tree.data + ",访问右子树");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetHighlight", elem.graphicID, 0);
+
+ if (elem.data < tree.data)
+ {
+ if (tree.left == null)
+ {
+ this.cmd("SetText", 0, "左子树为null,添加元素");
+
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.left=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, BST.LINK_COLOR);
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.left);
+ }
+ }
+ else
+ {
+ if (tree.right == null)
+ {
+ this.cmd("SetText", 0, "右子树为null,添加元素");
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.right=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, BST.LINK_COLOR);
+ elem.x = tree.x + BST.WIDTH_DELTA/2;
+ elem.y = tree.y + BST.HEIGHT_DELTA
+ this.cmd("Move", elem.graphicID, elem.x, elem.y);
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.right);
+ }
+ }
+
+
+}
+
+BST.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "正在刪除 "+deletedValue);
+ this.cmd("Step");
+ this.cmd("SetText", 0, "");
+ this.highlightID = this.nextIndex++;
+ this.treeDelete(this.treeRoot, deletedValue);
+ this.cmd("SetText", 0, "");
+ // Do delete
+ return this.commands;
+}
+
+BST.prototype.treeDelete = function(tree, valueToDelete)
+{
+ var leftchild = false;
+ if (tree != null)
+ {
+ if (tree.parent != null)
+ {
+ leftchild = tree.parent.left == tree;
+ }
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (valueToDelete < tree.data)
+ {
+ this.cmd("SetText", 0, valueToDelete + " < " + tree.data + ", 访问左子树");
+ }
+ else if (valueToDelete > tree.data)
+ {
+ this.cmd("SetText", 0, valueToDelete + " > " + tree.data + ", 访问右子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, valueToDelete + " == " + tree.data + ". Found node to delete");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ if (valueToDelete == tree.data)
+ {
+ if (tree.left == null && tree.right == null)
+ {
+ this.cmd("SetText", 0, "需要删除的是叶子节点,直接删除!");
+ this.cmd("Delete", tree.graphicID);
+ if (leftchild && tree.parent != null)
+ {
+ tree.parent.left = null;
+ }
+ else if (tree.parent != null)
+ {
+ tree.parent.right = null;
+ }
+ else
+ {
+ treeRoot = null;
+ }
+ this.resizeTree();
+ this.cmd("Step");
+
+ }
+ else if (tree.left == null)
+ {
+ this.cmd("SetText", 0, "需要删除的节点没有左子树. \nSet parent of deleted node to right child of deleted node.");
+ if (tree.parent != null)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, tree.right.graphicID, BST.LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ if (leftchild)
+ {
+ tree.parent.left = tree.right;
+ }
+ else
+ {
+ tree.parent.right = tree.right;
+ }
+ tree.right.parent = tree.parent;
+ }
+ else
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.treeRoot = tree.right;
+ this.treeRoot.parent = null;
+ }
+ this.resizeTree();
+ }
+ else if (tree.right == null)
+ {
+ this.cmd("SetText", 0, "需要删除的节点没有右子树. \nSet parent of deleted node to left child of deleted node.");
+ if (tree.parent != null)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, tree.left.graphicID, BST.LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ if (leftchild)
+ {
+ tree.parent.left = tree.left;
+ }
+ else
+ {
+ tree.parent.right = tree.left;
+ }
+ tree.left.parent = tree.parent;
+ }
+ else
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.treeRoot = tree.left;
+ this.treeRoot.parent = null;
+ }
+ this.resizeTree();
+ }
+ else // tree.left != null && tree.right != null
+ {
+ this.cmd("SetText", 0, "需要删除的节点有2棵子树. \n找到左子树中最大的节点.");
+
+ this.highlightID = this.nextIndex;
+ this.nextIndex += 1;
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ var tmp = tree;
+ tmp = tree.left;
+ this.cmd("Move", this.highlightID, tmp.x, tmp.y);
+ this.cmd("Step");
+ while (tmp.right != null)
+ {
+ tmp = tmp.right;
+ this.cmd("Move", this.highlightID, tmp.x, tmp.y);
+ this.cmd("Step");
+ }
+ this.cmd("SetText", tree.graphicID, " ");
+ var labelID = this.nextIndex;
+ this.nextIndex += 1;
+ this.cmd("CreateLabel", labelID, tmp.data, tmp.x, tmp.y);
+ tree.data = tmp.data;
+ this.cmd("Move", labelID, tree.x, tree.y);
+ this.cmd("SetText", 0, "Copy largest value of left subtree into node to delete.");
+
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("Delete", labelID);
+ this.cmd("SetText", tree.graphicID, tree.data);
+ this.cmd("Delete", this.highlightID);
+ this.cmd("SetText", 0,"Remove node whose value we copied.");
+
+ if (tmp.left == null)
+ {
+ if (tmp.parent != tree)
+ {
+ tmp.parent.right = null;
+ }
+ else
+ {
+ tree.left = null;
+ }
+ this.cmd("Delete", tmp.graphicID);
+ this.resizeTree();
+ }
+ else
+ {
+ this.cmd("Disconnect", tmp.parent.graphicID, tmp.graphicID);
+ this.cmd("Connect", tmp.parent.graphicID, tmp.left.graphicID, BST.LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tmp.graphicID);
+ if (tmp.parent != tree)
+ {
+ tmp.parent.right = tmp.left;
+ tmp.left.parent = tmp.parent;
+ }
+ else
+ {
+ tree.left = tmp.left;
+ tmp.left.parent = tree;
+ }
+ this.resizeTree();
+ }
+
+ }
+ }
+ else if (valueToDelete < tree.data)
+ {
+ if (tree.left != null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.treeDelete(tree.left, valueToDelete);
+ }
+ else
+ {
+ if (tree.right != null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.treeDelete(tree.right, valueToDelete);
+ }
+ }
+ else
+ {
+ this.cmd("SetText", 0, "元素 "+valueToDelete+" 未找到, 无法删除");
+ }
+
+}
+
+BST.prototype.resizeTree = function()
+{
+ var startingPoint = this.startingX;
+ this.resizeWidths(this.treeRoot);
+ if (this.treeRoot != null)
+ {
+ if (this.treeRoot.leftWidth > startingPoint)
+ {
+ startingPoint = this.treeRoot.leftWidth;
+ }
+ else if (this.treeRoot.rightWidth > startingPoint)
+ {
+ startingPoint = Math.max(this.treeRoot.leftWidth, 2 * startingPoint - this.treeRoot.rightWidth);
+ }
+ this.setNewPositions(this.treeRoot, startingPoint, BST.STARTING_Y, 0);
+ this.animateNewPositions(this.treeRoot);
+ this.cmd("Step");
+ }
+
+}
+
+BST.prototype.setNewPositions = function(tree, xPosition, yPosition, side)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ if (side == -1)
+ {
+ xPosition = xPosition - tree.rightWidth;
+ }
+ else if (side == 1)
+ {
+ xPosition = xPosition + tree.leftWidth;
+ }
+ tree.x = xPosition;
+ this.setNewPositions(tree.left, xPosition, yPosition + BST.HEIGHT_DELTA, -1)
+ this.setNewPositions(tree.right, xPosition, yPosition + BST.HEIGHT_DELTA, 1)
+ }
+
+}
+BST.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.animateNewPositions(tree.left);
+ this.animateNewPositions(tree.right);
+ }
+}
+
+BST.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = Math.max(this.resizeWidths(tree.left), BST.WIDTH_DELTA / 2);
+ tree.rightWidth = Math.max(this.resizeWidths(tree.right), BST.WIDTH_DELTA / 2);
+ return tree.leftWidth + tree.rightWidth;
+}
+
+
+
+
+function BSTNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.left = null;
+ this.right = null;
+ this.parent = null;
+}
+
+BST.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+BST.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new BST(animManag, canvas.width, canvas.height);
+
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BTree.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BTree.js
new file mode 100644
index 0000000..1589b14
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BTree.js
@@ -0,0 +1,1582 @@
+// 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 ``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 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 FIRST_PRINT_POS_X = 50;
+var PRINT_VERTICAL_GAP = 20;
+var PRINT_MAX = 990;
+var PRINT_HORIZONTAL_GAP = 50;
+
+var MIN_MAX_DEGREE = 3;
+var MAX_MAX_DEGREE = 7;
+
+var HEIGHT_DELTA = 50;
+var NODE_SPACING = 15;
+var STARTING_Y = 30;
+var WIDTH_PER_ELEM = 40;
+var NODE_HEIGHT = 25;
+
+var MESSAGE_X = 5;
+var MESSAGE_Y = 10;
+
+var LINK_COLOR = "#007700";
+var HIGHLIGHT_CIRCLE_COLOR = "#007700";
+var FOREGROUND_COLOR = "#007700";
+var BACKGROUND_COLOR = "#EEFFEE";
+var PRINT_COLOR = FOREGROUND_COLOR;
+
+
+
+function BTree(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+BTree.prototype = new Algorithm();
+BTree.prototype.varructor = BTree;
+BTree.superclass = Algorithm.prototype;
+
+
+
+
+
+BTree.prototype.init = function(am, w, h)
+{
+ BTree.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+
+ this.starting_x = w / 2;
+
+ this.preemptiveSplit = false
+
+
+ this.addControls();
+
+
+ this.max_keys = 2;
+ this.min_keys = 1;
+ this.split_index = 1;
+
+ this.max_degree = 3;
+
+
+
+
+ this.messageID = this.nextIndex++;
+ this.cmd("CreateLabel", this.messageID, "", MESSAGE_X, MESSAGE_Y, 0);
+ this.moveLabel1ID = this.nextIndex++;
+ this.moveLabel2ID = this.nextIndex++;
+
+ animationManager.StartNewAnimation(this.commands);
+ animationManager.skipForward();
+ animationManager.clearHistory();
+ this.commands = new Array();
+
+ this.first_print_pos_y = h - 3 * PRINT_VERTICAL_GAP;
+
+
+ this.xPosOfNextLabel = 100;
+ this.yPosOfNextLabel = 200;
+}
+
+BTree.prototype.addControls = function()
+{
+ this.controls = [];
+
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.controls.push(this.insertField);
+
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.controls.push(this.insertButton);
+
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 4);
+ this.controls.push(this.deleteField);
+
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.controls.push(this.deleteButton);
+
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4);
+ this.controls.push(this.findField);
+
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.controls.push(this.findButton);
+
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+ this.controls.push(this.printButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "清空");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+ var i;
+ radioButtonNames = [];
+ for (i = MIN_MAX_DEGREE; i <= MAX_MAX_DEGREE; i++)
+ {
+ radioButtonNames.push(' ' + String(i) + ' 阶');
+ }
+
+ this.maxDegreeRadioButtons = addRadioButtonGroupToAlgorithmBar(radioButtonNames, "MaxDegree");
+
+ this.maxDegreeRadioButtons[0].checked = true;
+ for(i = 0; i < this.maxDegreeRadioButtons.length; i++)
+ {
+ this.maxDegreeRadioButtons[i].onclick = this.maxDegreeChangedHandler.bind(this,i+MIN_MAX_DEGREE);
+ }
+
+
+ this.premptiveSplitBox = addCheckboxToAlgorithmBar("Preemtive Split / Merge (Even max degree only)");
+ this.premptiveSplitBox.onclick = this.premtiveSplitCallback.bind(this);
+
+
+ // Other buttons ...
+
+}
+
+
+
+
+
+BTree.prototype.reset = function()
+{
+ this.nextIndex = 3;
+ this.max_degree = 3;
+ this.max_keys = 2;
+ this.min_keys = 1;
+ this.split_index = 1;
+ // NOTE: The order of these last two this.commands matters!
+ this.treeRoot = null;
+ this.ignoreInputs = true;
+ // maxDegreeButtonArray[this.max_degree].selected = true;
+ this.ignoreInputs = false;
+}
+
+
+BTree.prototype.enableUI = function(event)
+{
+ var i;
+ for (i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+ // TODO Only enable even maxdegree if preemptive merge is on
+
+ if (this.preemptiveSplit)
+ {
+ var initialEven = MIN_MAX_DEGREE % 2;
+ var i;
+ for (i = initialEven; i <= MAX_MAX_DEGREE - MIN_MAX_DEGREE; i+= 2)
+ {
+ this.maxDegreeRadioButtons[i].disabled = false;
+ }
+ }
+ else
+ {
+ for (i = 0; i < this.maxDegreeRadioButtons.length; i++)
+ {
+ this.maxDegreeRadioButtons[i].disabled = false;
+ }
+ }
+
+
+
+
+
+ if (this.max_degree % 2 == 0)
+ {
+ this.premptiveSplitBox.disabled = false;
+ }
+
+
+}
+BTree.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+
+ for (i = 0; i < this.maxDegreeRadioButtons.length; i++)
+ {
+ this.maxDegreeRadioButtons[i].disabled = true;
+ }
+
+ this.premptiveSplitBox.disabled = true;
+
+
+
+}
+
+
+//TODO: Fix me!
+BTree.prototype.maxDegreeChangedHandler = function(newMaxDegree, event)
+{
+ if (this.max_degree != newMaxDegree)
+ {
+ this.implementAction(this.changeDegree.bind(this), newMaxDegree);
+ animationManager.skipForward();
+ animationManager.clearHistory();
+
+
+ }
+}
+
+
+
+BTree.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+BTree.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value;
+ if (deletedValue != "")
+ {
+ deletedValue = this.normalizeNumber(this.deleteField.value, 4);
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+BTree.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clearTree.bind(this), "");
+}
+
+
+BTree.prototype.premtiveSplitCallback = function(event)
+{
+ if (this.preemptiveSplit != this.premptiveSplitBox.checked)
+ {
+ this.implementAction(this.changePreemtiveSplit.bind(this), this.premptiveSplitBox.checked);
+ }
+}
+
+
+BTree.prototype.changePreemtiveSplit = function(newValue)
+{
+ this.commands = new Array();
+ this.cmd("Step");
+ this.preemptiveSplit = newValue;
+ if (this.premptiveSplitBox.checked != this.preemptiveSplit)
+ {
+ this.premptiveSplitBox.checked = this.preemptiveSplit;
+ }
+ return this.commands;
+}
+
+
+BTree.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+BTree.prototype.printTree = function(unused)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.messageID, "Printing tree");
+ var firstLabel = this.nextIndex;
+
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+
+ this.printTreeRec(this.treeRoot);
+ this.cmd("Step");
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = firstLabel;
+ this.cmd("SetText", this.messageID, "");
+ return this.commands;
+}
+
+BTree.prototype.printTreeRec =function (tree)
+{
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ var nextLabelID;
+ if (tree.isLeaf)
+ {
+ for (var i = 0; i < tree.numKeys;i++)
+ {
+ nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.keys[i], this.getLabelX(tree, i), tree.y);
+ this.cmd("SetForegroundColor", nextLabelID, PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+ this.xPosOfNextLabel += PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > PRINT_MAX)
+ {
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += PRINT_VERTICAL_GAP;
+ }
+ }
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ else
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[0].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[0].graphicID, 0);
+ this.printTreeRec(tree.children[0]);
+ for (i = 0; i < tree.numKeys; i++)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.keys[i], this.getLabelX(tree, i), tree.y);
+ this.cmd("SetForegroundColor", nextLabelID, PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+ this.xPosOfNextLabel += PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > PRINT_MAX)
+ {
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += PRINT_VERTICAL_GAP;
+ }
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 0);
+ this.printTreeRec(tree.children[i+1]);
+ }
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ }
+
+
+}
+
+BTree.prototype.clearTree = function(ignored)
+{
+ this.commands = new Array();
+ this.deleteTree(this.treeRoot);
+ this.treeRoot = null;
+ this.nextIndex = 3;
+ return this.commands;
+}
+
+BTree.prototype.deleteTree = function(tree)
+{
+ if (tree != null)
+ {
+ if (!tree.isLeaf)
+ {
+ for (var i = 0; i <= tree.numKeys; i++)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.children[i].graphicID);
+ this.deleteTree(tree.children[i]);
+ tree.children[i] == null;
+ }
+ }
+ this.cmd("Delete", tree.graphicID);
+ }
+}
+
+
+BTree.prototype.changeDegree = function(degree)
+{
+ this.commands = new Array();
+ this.deleteTree(this.treeRoot);
+ this.treeRoot = null;
+ this.nextIndex = 3;
+ var newDegree = degree;
+ this.ignoreInputs = true;
+ //TODO: Check me!
+ this.maxDegreeRadioButtons[newDegree - MIN_MAX_DEGREE].checked = true;
+
+ this.ignoreInputs = false;
+ this.max_degree = newDegree;
+ this.max_keys = newDegree - 1;
+ this.min_keys = Math.floor((newDegree + 1) / 2) - 1;
+ this.split_index = Math.floor((newDegree - 1) / 2);
+ if (this.commands.length == 0)
+ {
+ this.cmd("Step");
+ }
+ if (newDegree % 2 != 0 && this.preemptiveSplit)
+ {
+ this.preemptiveSplit = false;
+ this.premptiveSplitBox.checked = false;
+ }
+ return this.commands;
+}
+
+
+BTree.prototype.findCallback = function(event)
+{
+ var findValue;
+ findValue = this.normalizeNumber(this.findField.value, 4);
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+BTree.prototype.findElement = function(findValue)
+{
+ this.commands = new Array();
+
+ this.cmd("SetText", this.messageID, "Finding " + findValue);
+ this.findInTree(this.treeRoot, findValue);
+
+ return this.commands;
+}
+
+BTree.prototype.findInTree = function(tree, val)
+{
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ var i;
+ for (i = 0; i < tree.numKeys && tree.keys[i] < val; i++);
+ if (i == tree.numKeys)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 0);
+ this.findInTree(tree.children[tree.numKeys], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetText", this.messageID, "Element " + val + " is not in the tree");
+ }
+ }
+ else if (tree.keys[i] > val)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 0);
+ this.findInTree(tree.children[i], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetText", this.messageID, "Element " + val + " is not in the tree");
+ }
+ }
+ else
+ {
+ this.cmd("SetTextColor", tree.graphicID, "#FF0000", i);
+ this.cmd("SetText", this.messageID, "Element " + val + " found");
+ this.cmd("Step");
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ this.cmd("Step");
+ }
+ }
+ else
+ {
+ this.cmd("SetText", this.messageID, "Element " + val + " is not in the tree");
+ }
+}
+
+
+BTree.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+
+ this.cmd("SetText", this.messageID, "Inserting " + insertedValue);
+ this.cmd("Step");
+
+ if (this.treeRoot == null)
+ {
+ this.treeRoot = new BTreeNode(this.nextIndex++, this.starting_x, STARTING_Y);
+ this.cmd("CreateBTreeNode",
+ this.treeRoot.graphicID,
+ WIDTH_PER_ELEM, NODE_HEIGHT,
+ 1,
+ this.starting_x,
+ STARTING_Y,
+ BACKGROUND_COLOR,
+ FOREGROUND_COLOR);
+ this.treeRoot.keys[0] = insertedValue;
+ this.cmd("SetText", this.treeRoot.graphicID, insertedValue, 0);
+ }
+ else
+ {
+ if (this.preemptiveSplit)
+ {
+ if (this.treeRoot.numKeys == this.max_keys)
+ {
+ this.split(this.treeRoot)
+ this.resizeTree();
+ this.cmd("Step");
+
+ }
+ this.insertNotFull(this.treeRoot, insertedValue);
+ }
+ else
+ {
+ this.insert(this.treeRoot, insertedValue);
+ }
+ if (!this.treeRoot.isLeaf)
+ {
+ this.resizeTree();
+ }
+ }
+
+ this.cmd("SetText", this.messageID, "");
+
+ return this.commands;
+
+}
+
+BTree.prototype.insertNotFull = function(tree, insertValue)
+{
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ if (tree.isLeaf)
+ {
+ this.cmd("SetText", this.messageID, "Inserting " + insertValue + ". Inserting into a leaf");
+ tree.numKeys++;
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ var insertIndex = tree.numKeys - 1;
+ while (insertIndex > 0 && tree.keys[insertIndex - 1] > insertValue)
+ {
+ tree.keys[insertIndex] = tree.keys[insertIndex - 1];
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ insertIndex--;
+ }
+ tree.keys[insertIndex] = insertValue;
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.resizeTree();
+ }
+ else
+ {
+ var findIndex = 0;
+ while (findIndex < tree.numKeys && tree.keys[findIndex] < insertValue)
+ {
+ findIndex++;
+ }
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[findIndex].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[findIndex].graphicID, 0);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.children[findIndex].numKeys == this.max_keys)
+ {
+ var newTree = this.split(tree.children[findIndex]);
+ this.resizeTree();
+ this.cmd("Step");
+ this.insertNotFull(newTree, insertValue);
+ }
+ else
+ {
+ this.insertNotFull(tree.children[findIndex], insertValue);
+ }
+ }
+}
+
+
+
+BTree.prototype.insert = function(tree, insertValue)
+{
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ if (tree.isLeaf)
+ {
+ this.cmd("SetText", this.messageID, "Inserting " + insertValue + ". Inserting into a leaf");
+ tree.numKeys++;
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ var insertIndex = tree.numKeys - 1;
+ while (insertIndex > 0 && tree.keys[insertIndex - 1] > insertValue)
+ {
+ tree.keys[insertIndex] = tree.keys[insertIndex - 1];
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ insertIndex--;
+ }
+ tree.keys[insertIndex] = insertValue;
+ this.cmd("SetText", tree.graphicID, tree.keys[insertIndex], insertIndex);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.resizeTree();
+ this.insertRepair(tree);
+ }
+ else
+ {
+ var findIndex = 0;
+ while (findIndex < tree.numKeys && tree.keys[findIndex] < insertValue)
+ {
+ findIndex++;
+ }
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[findIndex].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[findIndex].graphicID, 0);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.insert(tree.children[findIndex], insertValue);
+ }
+}
+
+BTree.prototype.insertRepair = function(tree)
+{
+ if (tree.numKeys <= this.max_keys)
+ {
+ return;
+ }
+ else if (tree.parent == null)
+ {
+ this.treeRoot = this.split(tree);
+ return;
+ }
+ else
+ {
+ var newNode = this.split(tree);
+ this.insertRepair(newNode);
+ }
+}
+
+BTree.prototype.split = function(tree)
+{
+ this.cmd("SetText", this.messageID, "Node now contains too many keys. Splittig ...");
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ var rightNode = new BTreeNode(this.nextIndex++, tree.x + 100, tree.y);
+ rightNode.numKeys = tree.numKeys - this.split_index - 1;
+ var risingNode = tree.keys[this.split_index];
+
+
+ if (tree.parent != null)
+ {
+ var currentParent = tree.parent;
+ for (var parentIndex = 0; parentIndex < currentParent.numKeys + 1 && currentParent.children[parentIndex] != tree; parentIndex++);
+ if (parentIndex == currentParent.numKeys + 1)
+ {
+ throw new Error("Couldn't find which child we were!");
+ }
+ this.cmd("SetNumElements", currentParent.graphicID, currentParent.numKeys + 1);
+ for (i = currentParent.numKeys; i > parentIndex; i--)
+ {
+ currentParent.children[i+1] = currentParent.children[i];
+ this.cmd("Disconnect", currentParent.graphicID, currentParent.children[i].graphicID);
+ this.cmd("Connect", currentParent.graphicID, currentParent.children[i].graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i+1);
+
+ currentParent.keys[i] = currentParent.keys[i-1];
+ this.cmd("SetText", currentParent.graphicID, currentParent.keys[i] ,i);
+ }
+ currentParent.numKeys++;
+ currentParent.keys[parentIndex] = risingNode;
+ this.cmd("SetText", currentParent.graphicID, "", parentIndex);
+ this.moveLabel1ID = this.nextIndex++;
+ this.cmd("CreateLabel", this.moveLabel1ID, risingNode, this.getLabelX(tree, this.split_index), tree.y)
+ this.cmd("SetForegroundColor", this.moveLabel1ID, FOREGROUND_COLOR);
+
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(currentParent, parentIndex), currentParent.y)
+
+
+
+
+ currentParent.children[parentIndex+1] = rightNode;
+ rightNode.parent = currentParent;
+
+ }
+
+
+ this.cmd("CreateBTreeNode",
+ rightNode.graphicID,
+ WIDTH_PER_ELEM, NODE_HEIGHT,
+ tree.numKeys - this.split_index - 1,
+ tree.x,
+ tree.y,
+ BACKGROUND_COLOR,
+ FOREGROUND_COLOR);
+
+ var i;
+ for (i = this.split_index + 1; i < tree.numKeys + 1; i++)
+ {
+ rightNode.children[i - this.split_index - 1] = tree.children[i];
+ if (tree.children[i] != null)
+ {
+ rightNode.isLeaf = false;
+ this.cmd("Disconnect", tree.graphicID, tree.children[i].graphicID);
+
+ this.cmd("Connect", rightNode.graphicID,
+ rightNode.children[i - this.split_index - 1].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i - this.split_index - 1);
+ if (tree.children[i] != null)
+ {
+ tree.children[i].parent = rightNode;
+ }
+ tree.children[i] = null;
+
+ }
+ }
+ for (i = this.split_index+1; i < tree.numKeys; i++)
+ {
+ rightNode.keys[i - this.split_index - 1] = tree.keys[i];
+ this.cmd("SetText", rightNode.graphicID, rightNode.keys[i - this.split_index - 1], i - this.split_index - 1);
+ }
+ var leftNode = tree;
+ leftNode.numKeys = this.split_index;
+ // TO MAKE UNDO WORK -- CAN REMOVE LATER VV
+ for (i = this.split_index; i < tree.numKeys; i++)
+ {
+ this.cmd("SetText", tree.graphicID, "", i);
+ }
+ // TO MAKE UNDO WORK -- CAN REMOVE LATER ^^
+ this.cmd("SetNumElements", tree.graphicID, this.split_index);
+
+ if (tree.parent != null)
+ {
+ this.cmd("Connect", currentParent.graphicID, rightNode.graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ parentIndex + 1);
+ this.resizeTree();
+ this.cmd("Step")
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", currentParent.graphicID, risingNode, parentIndex);
+ return tree.parent;
+ }
+ else // if (tree.parent == null)
+ {
+ this.treeRoot = new BTreeNode(this.nextIndex++, this.starting_x, STARTING_Y);
+ this.cmd("CreateBTreeNode",
+ this.treeRoot.graphicID,
+ WIDTH_PER_ELEM,
+ NODE_HEIGHT,
+ 1,
+ this.starting_x,
+ STARTING_Y,
+ BACKGROUND_COLOR,
+ FOREGROUND_COLOR);
+ this.treeRoot.keys[0] = risingNode;
+ this.cmd("SetText", this.treeRoot.graphicID, risingNode, 0);
+ this.treeRoot.children[0] = leftNode;
+ this.treeRoot.children[1] = rightNode;
+ leftNode.parent = this.treeRoot;
+ rightNode.parent = this.treeRoot;
+ this.cmd("Connect", this.treeRoot.graphicID, leftNode.graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ 0); // Connection Point
+ this.cmd("Connect", this.treeRoot.graphicID, rightNode.graphicID, FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ 1); // Connection Point
+ this.treeRoot.isLeaf = false;
+ return this.treeRoot;
+ }
+
+
+
+}
+
+BTree.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在刪除 "+deletedValue);
+ this.cmd("Step");
+ this.cmd("SetText", 0, "");
+ this.highlightID = this.nextIndex++;
+ this.cmd("SetText", 0, "");
+ if (this.preemptiveSplit)
+ {
+ this.doDeleteNotEmpty(this.treeRoot, deletedValue);
+ }
+ else
+ {
+ this.doDelete(this.treeRoot, deletedValue);
+
+ }
+ if (this.treeRoot.numKeys == 0)
+ {
+ this.cmd("Step");
+ this.cmd("Delete", this.treeRoot.graphicID);
+ this.treeRoot = this.treeRoot.children[0];
+ this.treeRoot.parent = null;
+ this.resizeTree();
+ }
+ return this.commands;
+}
+
+BTree.prototype.doDeleteNotEmpty = function(tree, val)
+{
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ var i;
+ for (i = 0; i < tree.numKeys && tree.keys[i] < val; i++);
+ if (i == tree.numKeys)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 0);
+
+ if (tree.children[tree.numKeys].numKeys == this.min_keys)
+ {
+ var nextNode;
+ if (tree.children[tree.numKeys - 1].numKeys > this.min_keys)
+ {
+ nextNode = this.stealFromLeft(tree.children[tree.numKeys], tree.numKeys)
+ this.doDeleteNotEmpty(nextNode, val);
+ }
+ else
+ {
+ nextNode = this.mergeRight(tree.children[tree.numKeys - 1])
+ this.doDeleteNotEmpty(nextNode, val);
+ }
+ }
+ else
+ {
+ this.doDeleteNotEmpty(tree.children[tree.numKeys], val);
+ }
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ }
+ else if (tree.keys[i] > val)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 0);
+
+ if (tree.children[i].numKeys > this.min_keys)
+ {
+ this.doDeleteNotEmpty(tree.children[i], val);
+ }
+ else
+ {
+ if (tree.children[i+1].numKeys > this.min_keys)
+ {
+ nextNode = this.stealFromRight(tree.children[i], i);
+ this.doDeleteNotEmpty(nextNode, val);
+ }
+ else
+ {
+ nextNode = this.mergeRight(tree.children[i]);
+ this.doDeleteNotEmpty(nextNode, val);
+ }
+
+ }
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ }
+ else
+ {
+ this.cmd("SetTextColor", tree.graphicID, "FF0000", i);
+ this.cmd("Step");
+ if (tree.isLeaf)
+ {
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ for (var j = i; j < tree.numKeys - 1; j++)
+ {
+ tree.keys[j] = tree.keys[j+1];
+ this.cmd("SetText", tree.graphicID, tree.keys[j], j);
+ }
+ tree.numKeys--;
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys);
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+
+
+ }
+ else
+ {
+ this.cmd("SetText", this.messageID, "Checking to see if tree to left of element to delete \nhas an extra key");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 1);
+
+
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 0);
+ var maxNode = tree.children[i];
+
+ if (tree.children[i].numKeys == this.min_keys)
+ {
+
+ this.cmd("SetText", this.messageID,
+ "Tree to left of element to delete does not have an extra key. \nLooking to the right ...");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i+1].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i + 1].graphicID, 0);
+ // Trees to left and right of node to delete don't have enough keys
+ // Do a merge, and then recursively delete the element
+ if (tree.children[i+1].numKeys == this.min_keys)
+ {
+ this.cmd("SetText", this.messageID,
+ "Neither subtree has extra nodes. Mergeing around the key to delete, \nand recursively deleting ...");
+ this.cmd("Step");
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ nextNode = this.mergeRight(tree.children[i]);
+ this.doDeleteNotEmpty(nextNode, val);
+ return;
+ }
+ else
+ {
+ this.cmd("SetText", this.messageID,
+ "Tree to right of element to delete does have an extra key. \nFinding the smallest key in that subtree ...");
+ this.cmd("Step");
+
+ var minNode = tree.children[i+1];
+ while (!minNode.isLeaf)
+ {
+
+ this.cmd("SetHighlight", minNode.graphicID, 1);
+ this.cmd("Step")
+ this.cmd("SetHighlight", minNode.graphicID, 0);
+ if (minNode.children[0].numKeys == this.min_keys)
+ {
+ if (minNode.children[1].numKeys == this.min_keys)
+ {
+ minNode = this.mergeRight(minNode.children[0]);
+ }
+ else
+ {
+ minNode = this.stealFromRight(minNode.children[0], 0);
+ }
+ }
+ else
+ {
+ minNode = minNode.children[0];
+ }
+ }
+
+ this.cmd("SetHighlight", minNode.graphicID, 1);
+ tree.keys[i] = minNode.keys[0];
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ this.cmd("SetText", tree.graphicID, "", i);
+ this.cmd("SetText", minNode.graphicID, "", 0);
+
+ this.cmd("CreateLabel", this.moveLabel1ID, minNode.keys[0], this.getLabelX(minNode, 0), minNode.y)
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(tree, i), tree.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", tree.graphicID, tree.keys[i], i);
+ for (i = 1; i < minNode.numKeys; i++)
+ {
+ minNode.keys[i-1] = minNode.keys[i]
+ this.cmd("SetText", minNode.graphicID, minNode.keys[i-1], i - 1);
+ }
+ this.cmd("SetText", minNode.graphicID, "",minNode.numKeys - 1);
+
+ minNode.numKeys--;
+ this.cmd("SetHighlight", minNode.graphicID, 0);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ this.cmd("SetNumElements", minNode.graphicID, minNode.numKeys);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+
+ }
+ }
+ else
+ {
+
+ this.cmd("SetText", this.messageID,
+ "Tree to left of element to delete does have \nan extra key. Finding the largest key in that subtree ...");
+ this.cmd("Step");
+ while (!maxNode.isLeaf)
+ {
+ this.cmd("SetHighlight", maxNode.graphicID, 1);
+ this.cmd("Step")
+ this.cmd("SetHighlight", maxNode.graphicID, 0);
+ if (maxNode.children[maxNode.numKeys].numKeys == this.min_keys)
+ {
+ if (maxNode.children[maxNode.numKeys - 1] > this.min_keys)
+ {
+ maxNode = this.stealFromLeft(maxNode.children[maxNode.numKeys], maxNode.numKeys);
+ }
+ else
+ {
+
+ } maxNode = this.mergeRight(maxNode.children[maxNode.numKeys-1]);
+ }
+ else
+ {
+ maxNode = maxNode.children[maxNode.numKeys];
+ }
+ }
+ this.cmd("SetHighlight", maxNode.graphicID, 1);
+ tree.keys[i] = maxNode.keys[maxNode.numKeys - 1];
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ this.cmd("SetText", tree.graphicID, "", i);
+ this.cmd("SetText", maxNode.graphicID, "", maxNode.numKeys - 1);
+ this.cmd("CreateLabel", this.moveLabel1ID, tree.keys[i], this.getLabelX(maxNode, maxNode.numKeys - 1), maxNode.y)
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(tree, i), tree.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", tree.graphicID, tree.keys[i], i);
+ maxNode.numKeys--;
+ this.cmd("SetHighlight", maxNode.graphicID, 0);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ this.cmd("SetNumElements", maxNode.graphicID, maxNode.numKeys);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+
+ }
+
+ }
+ }
+
+ }
+}
+
+
+BTree.prototype.doDelete = function(tree, val)
+{
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("Step");
+ var i;
+ for (i = 0; i < tree.numKeys && tree.keys[i] < val; i++);
+ if (i == tree.numKeys)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[tree.numKeys].graphicID, 0);
+ this.doDelete(tree.children[tree.numKeys], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ }
+ else if (tree.keys[i] > val)
+ {
+ if (!tree.isLeaf)
+ {
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetEdgeHighlight", tree.graphicID, tree.children[i].graphicID, 0);
+ this.doDelete(tree.children[i], val);
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ }
+ else
+ {
+ this.cmd("SetTextColor", tree.graphicID, "#FF0000", i);
+ this.cmd("Step");
+ if (tree.isLeaf)
+ {
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ for (var j = i; j < tree.numKeys - 1; j++)
+ {
+ tree.keys[j] = tree.keys[j+1];
+ this.cmd("SetText", tree.graphicID, tree.keys[j], j);
+ }
+ tree.numKeys--;
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys);
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.repairAfterDelete(tree);
+ }
+ else
+ {
+ var maxNode = tree.children[i];
+ while (!maxNode.isLeaf)
+ {
+ this.cmd("SetHighlight", maxNode.graphicID, 1);
+ this.cmd("Step")
+ this.cmd("SetHighlight", maxNode.graphicID, 0);
+ maxNode = maxNode.children[maxNode.numKeys];
+ }
+ this.cmd("SetHighlight", maxNode.graphicID, 1);
+ tree.keys[i] = maxNode.keys[maxNode.numKeys - 1];
+ this.cmd("SetTextColor", tree.graphicID, FOREGROUND_COLOR, i);
+ this.cmd("SetText", tree.graphicID, "", i);
+ this.cmd("SetText", maxNode.graphicID, "", maxNode.numKeys - 1);
+ this.cmd("CreateLabel", this.moveLabel1ID, tree.keys[i], this.getLabelX(maxNode, maxNode.numKeys - 1), maxNode.y)
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(tree, i), tree.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", tree.graphicID, tree.keys[i], i);
+ maxNode.numKeys--;
+ this.cmd("SetHighlight", maxNode.graphicID, 0);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ this.cmd("SetNumElements", maxNode.graphicID, maxNode.numKeys);
+ this.repairAfterDelete(maxNode);
+ }
+ }
+
+ }
+}
+
+
+
+BTree.prototype.mergeRight = function(tree)
+{
+ this.cmd("SetText", this.messageID, "Merging node");
+
+ var parentNode = tree.parent;
+ var parentIndex = 0;
+ for (parentIndex = 0; parentNode.children[parentIndex] != tree; parentIndex++);
+ var rightSib = parentNode.children[parentIndex+1];
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("SetHighlight", parentNode.graphicID, 1);
+ this.cmd("SetHighlight", rightSib.graphicID, 1);
+
+ this.cmd("Step");
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys + rightSib.numKeys + 1);
+ tree.x = (tree.x + rightSib.x) / 2
+ this.cmd("SetPosition", tree.graphicID, tree.x, tree.y);
+
+ tree.keys[tree.numKeys] = parentNode.keys[parentIndex];
+ var fromParentIndex = tree.numKeys;
+ //this.cmd("SetText", tree.graphicID, tree.keys[tree.numKeys], tree.numKeys);
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys);
+ this.cmd("CreateLabel", this.moveLabel1ID, parentNode.keys[parentIndex], this.getLabelX(parentNode, parentIndex), parentNode.y);
+
+
+ for (var i = 0; i < rightSib.numKeys; i++)
+ {
+ tree.keys[tree.numKeys + 1 + i] = rightSib.keys[i];
+ this.cmd("SetText", tree.graphicID, tree.keys[tree.numKeys + 1 + i], tree.numKeys + 1 + i);
+ this.cmd("SetText", rightSib.graphicID, "", i);
+ }
+ if (!tree.isLeaf)
+ {
+ for (i = 0; i <= rightSib.numKeys; i++)
+ {
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.children[i].graphicID);
+ tree.children[tree.numKeys + 1 + i] = rightSib.children[i];
+ tree.children[tree.numKeys + 1 + i].parent = tree;
+ this.cmd("Connect", tree.graphicID,
+ tree.children[tree.numKeys + 1 + i].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ tree.numKeys + 1 + i);
+ }
+ }
+ this.cmd("Disconnect", parentNode.graphicID, rightSib.graphicID);
+ for (i = parentIndex+1; i < parentNode.numKeys; i++)
+ {
+ this.cmd("Disconnect", parentNode.graphicID, parentNode.children[i+1].graphicID);
+ parentNode.children[i] = parentNode.children[i+1];
+ this.cmd("Connect", parentNode.graphicID,
+ parentNode.children[i].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i);
+ parentNode.keys[i-1] = parentNode.keys[i];
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[i-1], i-1);
+ }
+ this.cmd("SetText", parentNode.graphicID, "", parentNode.numKeys - 1);
+ parentNode.numKeys--;
+ this.cmd("SetNumElements", parentNode.graphicID, parentNode.numKeys);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetHighlight", parentNode.graphicID, 0);
+// this.cmd("SetHighlight", rightSib.graphicID, 0);
+
+// this.cmd("Step");
+ this.cmd("Delete", rightSib.graphicID);
+ tree.numKeys = tree.numKeys + rightSib.numKeys + 1;
+ this.cmd("Move", this.moveLabel1ID, this.getLabelX(tree, fromParentIndex), tree.y);
+
+ this.cmd("Step");
+ // resizeTree();
+ this.cmd("Delete", this.moveLabel1ID);
+ this.cmd("SetText", tree.graphicID, tree.keys[fromParentIndex], fromParentIndex);
+
+ this.cmd("SetText", this.messageID, "");
+ return tree;
+}
+
+
+BTree.prototype.stealFromRight = function(tree, parentIndex)
+{
+ // Steal from right sibling
+ var parentNode = tree.parent;
+
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys+1);
+
+ this.cmd("SetText", this.messageID, "Stealing from right sibling");
+
+ var rightSib = parentNode.children[parentIndex + 1];
+ tree.numKeys++;
+
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+
+
+
+
+
+
+
+ this.cmd("SetText", tree.graphicID, "", tree.numKeys - 1);
+ this.cmd("SetText", parentNode.graphicID, "", parentIndex);
+ this.cmd("SetText", rightSib.graphicID, "", 0);
+
+ var tmpLabel1 = this.nextIndex++;
+ var tmpLabel2 = this.nextIndex++;
+
+
+ this.cmd("CreateLabel", tmpLabel1, rightSib.keys[0], this.getLabelX(rightSib, 0), rightSib.y)
+ this.cmd("CreateLabel", tmpLabel2, parentNode.keys[parentIndex], this.getLabelX(parentNode, parentIndex), parentNode.y)
+ this.cmd("SetForegroundColor", tmpLabel1, FOREGROUND_COLOR);
+ this.cmd("SetForegroundColor", tmpLabel2, FOREGROUND_COLOR);
+
+ this.cmd("Move", tmpLabel1, this.getLabelX(parentNode, parentIndex), parentNode.y);
+ this.cmd("Move", tmpLabel2, this.getLabelX(tree, tree.numKeys - 1), tree.y);
+
+ this.cmd("Step")
+ this.cmd("Delete", tmpLabel1);
+ this.cmd("Delete", tmpLabel2);
+ tree.keys[tree.numKeys - 1] = parentNode.keys[parentIndex];
+ parentNode.keys[parentIndex] = rightSib.keys[0];
+
+
+
+ this.cmd("SetText", tree.graphicID, tree.keys[tree.numKeys - 1], tree.numKeys - 1);
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[parentIndex], parentIndex);
+ if (!tree.isLeaf)
+ {
+ tree.children[tree.numKeys] = rightSib.children[0];
+ tree.children[tree.numKeys].parent = tree;
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.children[0].graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.children[tree.numKeys].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ tree.numKeys);
+ // TODO::CHECKME!
+
+ for (var i = 1; i < rightSib.numKeys + 1; i++)
+ {
+ this.cmd("Disconnect", rightSib.graphicID, rightSib.children[i].graphicID);
+ rightSib.children[i-1] = rightSib.children[i];
+ this.cmd("Connect", rightSib.graphicID,
+ rightSib.children[i-1].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i-1);
+ }
+
+ }
+ for (i = 1; i < rightSib.numKeys; i++)
+ {
+ rightSib.keys[i-1] = rightSib.keys[i];
+ this.cmd("SetText", rightSib.graphicID, rightSib.keys[i-1], i-1);
+ }
+ this.cmd("SetText", rightSib.graphicID, "", rightSib.numKeys-1);
+ rightSib.numKeys--;
+ this.cmd("SetNumElements", rightSib.graphicID, rightSib.numKeys);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+ return tree;
+
+}
+
+
+BTree.prototype.stealFromLeft = function(tree, parentIndex)
+{
+ var parentNode = tree.parent;
+ // Steal from left sibling
+ tree.numKeys++;
+ this.cmd("SetNumElements", tree.graphicID, tree.numKeys);
+ this.cmd("SetText", this.messageID, "Node has too few keys. Stealing from left sibling.");
+
+ for (i = tree.numKeys - 1; i > 0; i--)
+ {
+ tree.keys[i] = tree.keys[i-1];
+ this.cmd("SetText", tree.graphicID, tree.keys[i], i);
+ }
+ var leftSib = parentNode.children[parentIndex -1];
+
+ this.cmd("SetText", tree.graphicID, "", 0);
+ this.cmd("SetText", parentNode.graphicID, "", parentIndex - 1);
+ this.cmd("SetText", leftSib.graphicID, "", leftSib.numKeys - 1);
+
+ var tmpLabel1 = this.nextIndex++;
+ var tmpLabel2 = this.nextIndex++;
+
+ this.cmd("CreateLabel", tmpLabel1, leftSib.keys[leftSib.numKeys - 1], this.getLabelX(leftSib, leftSib.numKeys - 1), leftSib.y)
+ this.cmd("CreateLabel", tmpLabel2, parentNode.keys[parentIndex - 1], this.getLabelX(parentNode, parentIndex - 1), parentNode.y)
+ this.cmd("SetForegroundColor", tmpLabel1, FOREGROUND_COLOR);
+ this.cmd("SetForegroundColor", tmpLabel2, FOREGROUND_COLOR);
+
+
+ this.cmd("Move", tmpLabel1, this.getLabelX(parentNode, parentIndex - 1), parentNode.y);
+ this.cmd("Move", tmpLabel2, this.getLabelX(tree, 0), tree.y);
+
+ this.cmd("Step")
+ this.cmd("Delete", tmpLabel1);
+ this.cmd("Delete", tmpLabel2);
+
+
+ if (!tree.isLeaf)
+ {
+ for (var i = tree.numKeys; i > 0; i--)
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.children[i-1].graphicID);
+ tree.children[i] =tree.children[i-1];
+ this.cmd("Connect", tree.graphicID,
+ tree.children[i].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ i);
+ }
+ tree.children[0] = leftSib.children[leftSib.numKeys];
+ this.cmd("Disconnect", leftSib.graphicID, leftSib.children[leftSib.numKeys].graphicID);
+ this.cmd("Connect", tree.graphicID,
+ tree.children[0].graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ "", // Label
+ 0);
+ leftSib.children[leftSib.numKeys] = null;
+ tree.children[0].parent = tree;
+
+ }
+
+ tree.keys[0] = parentNode.keys[parentIndex - 1];
+ this.cmd("SetText", tree.graphicID, tree.keys[0], 0);
+ parentNode.keys[parentIndex-1] = leftSib.keys[leftSib.numKeys - 1];
+ this.cmd("SetText", parentNode.graphicID, parentNode.keys[parentIndex - 1], parentIndex - 1);
+ this.cmd("SetText", leftSib.graphicID,"", leftSib.numKeys - 1);
+
+ leftSib.numKeys--;
+ this.cmd("SetNumElements", leftSib.graphicID, leftSib.numKeys);
+ this.resizeTree();
+ this.cmd("SetText", this.messageID, "");
+ return tree;
+}
+
+
+BTree.prototype.repairAfterDelete = function(tree)
+{
+ if (tree.numKeys < this.min_keys)
+ {
+ if (tree.parent == null)
+ {
+ if (tree.numKeys == 0)
+ {
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ this.treeRoot = tree.children[0];
+ if (this.treeRoot != null)
+ this.treeRoot.parent = null;
+ this.resizeTree();
+ }
+ }
+ else
+ {
+ var parentNode = tree.parent;
+ for (var parentIndex = 0; parentNode.children[parentIndex] != tree; parentIndex++);
+ if (parentIndex > 0 && parentNode.children[parentIndex - 1].numKeys > this.min_keys)
+ {
+ this.stealFromLeft(tree, parentIndex);
+
+ }
+ else if (parentIndex < parentNode.numKeys && parentNode.children[parentIndex + 1].numKeys > this.min_keys)
+ {
+ this.stealFromRight(tree,parentIndex);
+
+ }
+ else if (parentIndex == 0)
+ {
+ // Merge with right sibling
+ var nextNode = this.mergeRight(tree);
+ this.repairAfterDelete(nextNode.parent);
+ }
+ else
+ {
+ // Merge with left sibling
+ nextNode = this.mergeRight(parentNode.children[parentIndex-1]);
+ this.repairAfterDelete(nextNode.parent);
+
+ }
+
+
+ }
+ }
+}
+
+BTree.prototype.getLabelX = function(tree, index)
+{
+ return tree.x - WIDTH_PER_ELEM * tree.numKeys / 2 + WIDTH_PER_ELEM / 2 + index * WIDTH_PER_ELEM;
+}
+
+BTree.prototype.resizeTree = function()
+{
+ this.resizeWidths(this.treeRoot);
+ this.setNewPositions(this.treeRoot, this.starting_x, STARTING_Y);
+ this.animateNewPositions(this.treeRoot);
+}
+
+BTree.prototype.setNewPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ tree.x = xPosition;
+ if (!tree.isLeaf)
+ {
+ var leftEdge = xPosition - tree.width / 2;
+ var priorWidth = 0;
+ for (var i = 0; i < tree.numKeys+1; i++)
+ {
+ this.setNewPositions(tree.children[i], leftEdge + priorWidth + tree.widths[i] / 2, yPosition+HEIGHT_DELTA);
+ priorWidth += tree.widths[i];
+ }
+ }
+ }
+}
+
+BTree.prototype.animateNewPositions = function(tree)
+{
+ if (tree == null)
+ {
+ return;
+ }
+ var i;
+ for (i = 0; i < tree.numKeys + 1; i++)
+ {
+ this.animateNewPositions(tree.children[i]);
+ }
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+}
+
+BTree.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ if (tree.isLeaf)
+ {
+ for (var i = 0; i < tree.numKeys + 1; i++)
+ {
+ tree.widths[i] = 0;
+ }
+ tree.width = tree.numKeys * WIDTH_PER_ELEM + NODE_SPACING;
+ return tree.width;
+ }
+ else
+ {
+ var treeWidth = 0;
+ for (i = 0; i < tree.numKeys+1; i++)
+ {
+ tree.widths[i] = this.resizeWidths(tree.children[i]);
+ treeWidth = treeWidth + tree.widths[i];
+ }
+ treeWidth = Math.max(treeWidth, tree.numKeys * WIDTH_PER_ELEM + NODE_SPACING);
+ tree.width = treeWidth;
+ return treeWidth;
+ }
+}
+
+
+
+
+function BTreeNode(id, initialX, initialY)
+{
+ this.widths = [];
+ this.keys = [];
+ this.children = [];
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.numKeys = 1;
+ this.isLeaf = true;
+ this.parent = null;
+
+ this.leftWidth = 0;
+ this.rightWidth = 0;
+
+}
+
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new BTree(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BinomialQueue.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BinomialQueue.js
new file mode 100644
index 0000000..30fa7c1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BinomialQueue.js
@@ -0,0 +1,643 @@
+// 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 ``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 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 LINK_COLOR = "#007700";
+var HIGHLIGHT_CIRCLE_COLOR = "#007700";
+var MERGE_SEPARATING_LINE_COLOR = "#0000FF";
+var FOREGROUND_COLOR = "#007700";
+var BACKGROUND_COLOR = "#EEFFEE";
+var DEGREE_OFFSET_X = -20;
+var DEGREE_OFFSET_Y = -20;
+
+var DELETE_LAB_X = 30;
+var DELETE_LAB_Y = 50;
+
+
+var NODE_WIDTH = 60;
+var NODE_HEIGHT = 70
+
+var STARTING_X = 70;
+var STARTING_Y = 80;
+
+var INSERT_X = 30;
+var INSERT_Y = 25
+
+
+function BinomialQueue(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+BinomialQueue.prototype = new Algorithm();
+BinomialQueue.prototype.constructor = BinomialQueue;
+BinomialQueue.superclass = Algorithm.prototype;
+
+
+
+BinomialQueue.prototype.init = function(am, w, h)
+{
+ BinomialQueue.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.treeRoot = null;
+ this.currentLayer = 1;
+ this.animationManager.setAllLayers([0,this.currentLayer]);
+ this.nextIndex = 0;
+}
+
+
+BinomialQueue.prototype.addControls = function()
+{
+ this.controls = [];
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.controls.push(this.insertField);
+
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.controls.push(this.insertButton);
+
+ this.removeSmallestButton = addControlToAlgorithmBar("Button", "Remove Smallest");
+ this.removeSmallestButton.onclick = this.removeSmallestCallback.bind(this);
+ this.controls.push(this.removeSmallestButton);
+
+ this.clearHeapButton = addControlToAlgorithmBar("Button", "Clear Heap");
+ this.clearHeapButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearHeapButton);
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Logical Representation",
+ "Internal Representation",
+ ],
+ "BQueueRep");
+
+ radioButtonList[0].onclick = this.representationChangedHandler.bind(this, true);
+ radioButtonList[1].onclick = this.representationChangedHandler.bind(this, false);
+ radioButtonList[0].checked = true;
+
+}
+
+
+BinomialQueue.prototype.representationChangedHandler = function(logicalRep, event)
+{
+ if (logicalRep)
+ {
+ this.animationManager.setAllLayers([0,1]);
+ this.currentLayer = 1;
+ }
+ else
+ {
+ this.animationManager.setAllLayers([0,2]);
+ this.currentLayer = 2;
+ }
+}
+
+
+
+
+BinomialQueue.prototype.setPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ if (tree.degree == 0)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ return this.setPositions(tree.rightSib, xPosition + NODE_WIDTH, yPosition);
+ }
+ else if (tree.degree == 1)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ this.setPositions(tree.leftChild, xPosition, yPosition + NODE_HEIGHT);
+ return this.setPositions(tree.rightSib, xPosition + NODE_WIDTH, yPosition);
+ }
+ else
+ {
+ var treeWidth = Math.pow(2, tree.degree - 1);
+ tree.x = xPosition + (treeWidth - 1) * NODE_WIDTH;
+ tree.y = yPosition;
+ this.setPositions(tree.leftChild, xPosition, yPosition + NODE_HEIGHT);
+ return this.setPositions(tree.rightSib, xPosition + treeWidth * NODE_WIDTH, yPosition);
+ }
+ }
+ return xPosition;
+}
+
+BinomialQueue.prototype.moveTree = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.cmd("Move", tree.internalGraphicID, tree.x, tree.y);
+ this.cmd("Move", tree.degreeID, tree.x + DEGREE_OFFSET_X, tree.y + DEGREE_OFFSET_Y);
+
+ this.moveTree(tree.leftChild);
+ this.moveTree(tree.rightSib);
+ }
+}
+
+
+BinomialQueue.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+BinomialQueue.prototype.clearCallback = function(event)
+{
+ this.clear();
+}
+
+BinomialQueue.prototype.clear = function()
+{
+ this.commands = new Array();
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.actionHistory = new Array();
+}
+
+
+BinomialQueue.prototype.reset = function()
+{
+ this.treeRoot = null;
+ this.nextIndex = 0;
+}
+
+BinomialQueue.prototype.removeSmallestCallback = function(event)
+{
+ this.implementAction(this.removeSmallest.bind(this),"");
+}
+
+
+
+BinomialQueue.prototype.removeSmallest = function(dummy)
+{
+ this.commands = new Array();
+
+ if (this.treeRoot != null)
+ {
+ var tmp;
+ var prev;
+ var smallest = this.treeRoot;
+
+ this.cmd("SetHighlight", smallest.graphicID, 1);
+ this.cmd("SetHighlight", smallest.internalGraphicID, 1);
+
+ for (tmp = this.treeRoot.rightSib; tmp != null; tmp = tmp.rightSib)
+ {
+ this.cmd("SetHighlight", tmp.graphicID, 1);
+ this.cmd("SetHighlight", tmp.internalGraphicID, 1);
+ this.cmd("Step");
+ if (tmp.data < smallest.data)
+ {
+ this.cmd("SetHighlight", smallest.graphicID, 0);
+ this.cmd("SetHighlight", smallest.internalGraphicID, 0);
+ smallest = tmp;
+ }
+ else
+ {
+ this.cmd("SetHighlight", tmp.graphicID, 0);
+ this.cmd("SetHighlight", tmp.internalGraphicID, 0);
+ }
+ }
+
+ if (smallest == this.treeRoot) {
+ this.treeRoot = this.treeRoot.rightSib;
+ prev = null;
+ }
+ else
+ {
+ for (prev = this.treeRoot; prev.rightSib != smallest; prev = prev.rightSib) ;
+ prev.rightSib = prev.rightSib.rightSib;
+
+ }
+ var moveLabel = this.nextIndex++;
+ this.cmd("SetText", smallest.graphicID, "");
+ this.cmd("SetText", smallest.internalGraphicID, "");
+ this.cmd("CreateLabel", moveLabel, smallest.data, smallest.x, smallest.y);
+ this.cmd("Move", moveLabel, DELETE_LAB_X, DELETE_LAB_Y);
+ this.cmd("Step");
+ if (prev != null && prev.rightSib != null)
+ {
+ this.cmd("Connect", prev.internalGraphicID,
+ prev.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ }
+ this.cmd("Delete", smallest.graphicID);
+ this.cmd("Delete", smallest.internalGraphicID);
+ this.cmd("Delete", smallest.degreeID);
+
+ this.secondaryTreeRoot = this.reverse(smallest.leftChild);
+ for (tmp = this.secondaryTreeRoot; tmp != null; tmp = tmp.rightSib)
+ tmp.parent = null;
+ this.merge();
+ this.cmd("Delete", moveLabel);
+ }
+ return this.commands;
+}
+
+BinomialQueue.prototype.reverse = function(tree)
+{
+ var newTree = null;
+ var tmp;
+ while (tree != null)
+ {
+ if (tree.rightSib != null)
+ {
+ this.cmd("Disconnect", tree.internalGraphicID, tree.rightSib.internalGraphicID);
+ this.cmd("Connect", tree.rightSib.internalGraphicID,
+ tree.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ tmp = tree;
+ tree = tree.rightSib;
+ tmp.rightSib = newTree;
+ tmp.parent=null;
+ newTree = tmp;
+ }
+ return newTree;
+}
+
+
+BinomialQueue.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+
+ var insertNode = new BinomialNode(insertedValue, this.nextIndex++, INSERT_X, INSERT_Y);
+ insertNode.internalGraphicID = this.nextIndex++;
+ insertNode.degreeID= this.nextIndex++;
+ this.cmd("CreateCircle", insertNode.graphicID, insertedValue, INSERT_X, INSERT_Y);
+ this.cmd("SetForegroundColor", insertNode.graphicID, FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", insertNode.graphicID, BACKGROUND_COLOR);
+ this.cmd("SetLayer", insertNode.graphicID, 1);
+ this.cmd("CreateCircle", insertNode.internalGraphicID, insertedValue, INSERT_X, INSERT_Y);
+ this.cmd("SetForegroundColor", insertNode.internalGraphicID, FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", insertNode.internalGraphicID, BACKGROUND_COLOR);
+ this.cmd("SetLayer", insertNode.internalGraphicID, 2);
+ this.cmd("CreateLabel", insertNode.degreeID, insertNode.degree, insertNode.x + DEGREE_OFFSET_X, insertNode.y + DEGREE_OFFSET_Y);
+ this.cmd("SetTextColor", insertNode.degreeID, "#0000FF");
+ this.cmd("SetLayer", insertNode.degreeID, 2);
+ this.cmd("Step");
+
+ if (this.treeRoot == null)
+ {
+ this.treeRoot = insertNode;
+ this.setPositions(this.treeRoot, STARTING_X, STARTING_Y);
+ this.moveTree(this.treeRoot);
+ }
+ else
+ {
+ this.secondaryTreeRoot = insertNode;
+ this.merge();
+ }
+
+ return this.commands;
+}
+
+
+BinomialQueue.prototype.merge = function()
+{
+ if (this.treeRoot != null)
+ {
+ var leftSize = this.setPositions(this.treeRoot, STARTING_X, STARTING_Y);
+ this.setPositions(this.secondaryTreeRoot, leftSize + NODE_WIDTH, STARTING_Y);
+ this.moveTree(this.secondaryTreeRoot);
+ this.moveTree(this.treeRoot);
+ var lineID = this.nextIndex++;
+ this.cmd("CreateRectangle", lineID, "", 0, 200, leftSize, 50,"left","top");
+ this.cmd("SetForegroundColor", lineID, MERGE_SEPARATING_LINE_COLOR);
+ this.cmd("SetLayer", lineID, 0);
+ this.cmd("Step");
+ }
+ else
+ {
+ this.treeRoot = this.secondaryTreeRoot;
+ this.secondaryTreeRoot = null;
+ this.setPositions(this.treeRoot, NODE_WIDTH, STARTING_Y);
+ this.moveTree(this.treeRoot);
+ return;
+ }
+ while (this.secondaryTreeRoot != null)
+ {
+ var tmp = this.secondaryTreeRoot;
+ this.secondaryTreeRoot = this.secondaryTreeRoot.rightSib;
+ if (this.secondaryTreeRoot != null)
+ {
+ this.cmd("Disconnect", tmp.internalGraphicID, this.secondaryTreeRoot.internalGraphicID);
+ }
+ if (tmp.degree <= this.treeRoot.degree)
+ {
+ tmp.rightSib = this.treeRoot;
+ this.treeRoot = tmp;
+ this.cmd("Connect", this.treeRoot.internalGraphicID,
+ this.treeRoot.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ else
+ {
+ var tmp2 = this.treeRoot;
+ while (tmp2.rightSib != null && tmp2.rightSib.degree < tmp.degree)
+ {
+ tmp2 = tmp2. rightSib;
+ }
+ if (tmp2.rightSib != null)
+ {
+ this.cmd("Disconnect", tmp2.internalGraphicID, tmp2.rightSib.internalGraphicID);
+ this.cmd("Connect", tmp.internalGraphicID,
+ tmp2.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ tmp.rightSib= tmp2.rightSib;
+ tmp2.rightSib = tmp;
+ this.cmd("Connect", tmp2.internalGraphicID,
+ tmp.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ leftSize = this.setPositions(this.treeRoot, STARTING_X, STARTING_Y);
+ this.setPositions(this.secondaryTreeRoot, leftSize + NODE_WIDTH, STARTING_Y);
+ this.moveTree(this.secondaryTreeRoot);
+ this.moveTree(this.treeRoot);
+ this.cmd("Move", lineID, leftSize, 50);
+ this.cmd("Step");
+ }
+ this.cmd("Delete", lineID);
+ this.combineNodes();
+}
+
+
+BinomialQueue.prototype.combineNodes = function()
+{
+ var tmp;
+ var tmp2;
+ while ((this.treeRoot != null && this.treeRoot.rightSib != null && this.treeRoot.degree == this.treeRoot.rightSib.degree) &&
+ (this.treeRoot.rightSib.rightSib == null || this.treeRoot.rightSib.degree != this.treeRoot.rightSib.rightSib.degree))
+ {
+ this.cmd("Disconnect", this.treeRoot.internalGraphicID, this.treeRoot.rightSib.internalGraphicID);
+ if (this.treeRoot.rightSib.rightSib != null)
+ {
+ this.cmd("Disconnect", this.treeRoot.rightSib.internalGraphicID, this.treeRoot.rightSib.rightSib.internalGraphicID);
+ }
+ if (this.treeRoot.data < this.treeRoot.rightSib.data)
+ {
+ tmp = this.treeRoot.rightSib;
+ this.treeRoot.rightSib = tmp.rightSib;
+ tmp.rightSib = this.treeRoot.leftChild;
+ this.treeRoot.leftChild = tmp;
+ tmp.parent = this.treeRoot;
+ }
+ else
+ {
+ tmp = this.treeRoot;
+ this.treeRoot = this.treeRoot.rightSib;
+ tmp.rightSib = this.treeRoot.leftChild;
+ this.treeRoot.leftChild = tmp;
+ tmp.parent = this.treeRoot;
+ }
+ this.cmd("Connect", this.treeRoot.graphicID,
+ this.treeRoot.leftChild.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ ""); // Label
+
+
+ this.cmd("Connect", this.treeRoot.internalGraphicID,
+ this.treeRoot.leftChild.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", this.treeRoot.leftChild.internalGraphicID,
+ this.treeRoot.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ if (this.treeRoot.leftChild.rightSib != null)
+ {
+ this.cmd("Disconnect", this.treeRoot.internalGraphicID, this.treeRoot.leftChild.rightSib.internalGraphicID);
+ this.cmd("Connect", this.treeRoot.leftChild.internalGraphicID,
+ this.treeRoot.leftChild.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ if (this.treeRoot.rightSib != null)
+ {
+ this.cmd("Connect", this.treeRoot.internalGraphicID,
+ this.treeRoot.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+
+ this.treeRoot.degree++;
+
+ this.cmd("SetText", this.treeRoot.degreeID, this.treeRoot.degree);
+
+
+ this.setPositions(this.treeRoot, STARTING_X, STARTING_Y);
+ this.moveTree(this.treeRoot);
+ this.cmd("Step");
+ }
+
+ tmp2 = this.treeRoot;
+ while (tmp2 != null && tmp2.rightSib != null && tmp2.rightSib.rightSib != null)
+ {
+ if (tmp2.rightSib.degree != tmp2.rightSib.rightSib.degree)
+ {
+ tmp2 = tmp2.rightSib;
+ } else if ((tmp2.rightSib.rightSib.rightSib != null) &&
+ (tmp2.rightSib.rightSib.degree == tmp2.rightSib.rightSib.rightSib.degree))
+ {
+ tmp2 = tmp2.rightSib;
+ }
+ else
+ {
+ this.cmd("Disconnect", tmp2.rightSib.internalGraphicID, tmp2.rightSib.rightSib.internalGraphicID);
+ this.cmd("Disconnect", tmp2.internalGraphicID, tmp2.rightSib.internalGraphicID);
+ if (tmp2.rightSib.rightSib.rightSib != null)
+ {
+ this.cmd("Disconnect", tmp2.rightSib.rightSib.internalGraphicID, tmp2.rightSib.rightSib.rightSib.internalGraphicID);
+ }
+
+ var tempRoot;
+ if (tmp2.rightSib.data < tmp2.rightSib.rightSib.data)
+ {
+ tmp = tmp2.rightSib.rightSib;
+ tmp2.rightSib.rightSib = tmp.rightSib;
+
+ tmp.rightSib = tmp2.rightSib.leftChild;
+ tmp2.rightSib.leftChild = tmp;
+ tmp.parent = tmp2.rightSib;
+ tmp2.rightSib.degree++;
+ this.cmd("SetText", tmp2.rightSib.degreeID, tmp2.rightSib.degree);
+ tempRoot = tmp2.rightSib;
+
+ }
+ else
+ {
+ tmp = tmp2.rightSib;
+ tmp2.rightSib = tmp2.rightSib.rightSib;
+ tmp.rightSib = tmp2.rightSib.leftChild;
+ tmp2.rightSib.leftChild = tmp;
+ tmp.parent = tmp2.rightSib;
+ tmp2.rightSib.degree++;
+ this.cmd("SetText", tmp2.rightSib.degreeID, tmp2.rightSib.degree);
+ tempRoot = tmp2.rightSib;
+ }
+ this.cmd("Connect", tempRoot.graphicID,
+ tempRoot.leftChild.graphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ ""); // Label
+
+ this.cmd("Connect", tempRoot.internalGraphicID,
+ tempRoot.leftChild.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", tempRoot.leftChild.internalGraphicID,
+ tempRoot.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", tmp2.internalGraphicID,
+ tempRoot.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ if (tempRoot.leftChild.rightSib != null)
+ {
+ this.cmd("Disconnect",tempRoot.internalGraphicID, tempRoot.leftChild.rightSib.internalGraphicID);
+ this.cmd("Connect",tempRoot.leftChild.internalGraphicID,
+ tempRoot.leftChild.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label);
+ }
+ if (tempRoot.rightSib != null)
+ {
+ this.cmd("Connect",tempRoot.internalGraphicID,
+ tempRoot.rightSib.internalGraphicID,
+ FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label);
+ }
+
+
+
+
+ this.setPositions(this.treeRoot, STARTING_X, STARTING_Y);
+ this.moveTree(this.treeRoot);
+ this.cmd("Step");
+ }
+ }
+}
+
+
+BinomialQueue.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+BinomialQueue.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new BinomialQueue(animManag, canvas.width, canvas.height);
+}
+
+
+
+
+function BinomialNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.degree = 0;
+ this.leftChild = null;
+ this.rightSib = null;
+ this.parent = null;
+ this.internalGraphicID = -1;
+ this.degreeID = -1;
+}
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BucketSort.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BucketSort.js
new file mode 100644
index 0000000..d3e30cb
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/BucketSort.js
@@ -0,0 +1,349 @@
+// 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 ``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 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
+
+
+
+function BucketSort(am, w, h)
+{
+ this.init(am,w,h);
+
+}
+
+
+var ARRAY_ELEM_WIDTH_SMALL = 30;
+var ARRAY_ELEM_HEIGHT_SMALL = 30;
+var ARRAY_ELEM_START_X_SMALL = 20;
+
+var ARRAY_ELEMENT_Y_SMALL = 150;
+
+var POINTER_ARRAY_ELEM_WIDTH_SMALL = 30;
+var POINTER_ARRAY_ELEM_HEIGHT_SMALL = 30;
+var POINTER_ARRAY_ELEM_START_X_SMALL = 20;
+
+var LINKED_ITEM_HEIGHT_SMALL = 30;
+var LINKED_ITEM_WIDTH_SMALL = 24;
+
+var LINKED_ITEM_Y_DELTA_SMALL = 50;
+var LINKED_ITEM_POINTER_PERCENT_SMALL = 0.25;
+
+var MAX_DATA_VALUE = 999;
+
+var ARRAY_SIZE_SMALL = 30;
+
+var ARRAY_Y_POS = 350;
+
+
+BucketSort.prototype = new Algorithm();
+BucketSort.prototype.constructor = BucketSort;
+BucketSort.superclass = Algorithm.prototype;
+
+BucketSort.prototype.init = function(am, w, h)
+{
+ var sc = BucketSort.superclass;
+ var fn = sc.init;
+ fn.call(this,am, w, h);
+ this.addControls();
+ this.pointer_array_elem_y_small = h - 50;
+
+ this.nextIndex = 0;
+ this.setup();
+}
+
+
+
+BucketSort.prototype.addControls = function()
+{
+ this.resetButton = addControlToAlgorithmBar("Button", "Randomize List");
+ this.resetButton.onclick = this.resetCallback.bind(this);
+
+ this.bucketSortButton = addControlToAlgorithmBar("Button", "Bucket Sort");
+ this.bucketSortButton.onclick = this.bucketSortCallback.bind(this);
+
+}
+
+
+BucketSort.prototype.setup = function()
+{
+ this.arrayData = new Array(ARRAY_SIZE_SMALL);
+ this.arrayRects= new Array(ARRAY_SIZE_SMALL);
+ this.linkedListRects = new Array(ARRAY_SIZE_SMALL);
+ this.linkedListData = new Array(ARRAY_SIZE_SMALL);
+ this.upperIndices = new Array(ARRAY_SIZE_SMALL);
+ this.lowerIndices = new Array(ARRAY_SIZE_SMALL);
+ this.commands = new Array();
+ this.oldData = new Array(ARRAY_SIZE_SMALL);
+
+ for (var i = 0; i < ARRAY_SIZE_SMALL; i++)
+ {
+ var nextID = this.nextIndex++;
+ this.arrayData[i] = Math.floor(Math.random()*MAX_DATA_VALUE);
+ this.oldData[i] = this.arrayData[i];
+ this.cmd("CreateRectangle", nextID, this.arrayData[i], ARRAY_ELEM_WIDTH_SMALL, ARRAY_ELEM_HEIGHT_SMALL, ARRAY_ELEM_START_X_SMALL + i *ARRAY_ELEM_WIDTH_SMALL, ARRAY_ELEMENT_Y_SMALL)
+ this.arrayRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this.cmd("CreateRectangle", nextID, "", POINTER_ARRAY_ELEM_WIDTH_SMALL, POINTER_ARRAY_ELEM_HEIGHT_SMALL, POINTER_ARRAY_ELEM_START_X_SMALL + i *POINTER_ARRAY_ELEM_WIDTH_SMALL, this.pointer_array_elem_y_small)
+ this.linkedListRects[i] = nextID;
+ this.cmd("SetNull", this.linkedListRects[i], 1);
+ nextID = this.nextIndex++;
+ this.upperIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, ARRAY_ELEM_START_X_SMALL + i *ARRAY_ELEM_WIDTH_SMALL, ARRAY_ELEMENT_Y_SMALL + ARRAY_ELEM_HEIGHT_SMALL);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+
+ nextID = this.nextIndex++;
+ this.lowerIndices[i] = nextID;
+ this.cmd("CreateLabel", nextID, i, POINTER_ARRAY_ELEM_START_X_SMALL + i *POINTER_ARRAY_ELEM_WIDTH_SMALL, this.pointer_array_elem_y_small + POINTER_ARRAY_ELEM_HEIGHT_SMALL);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+BucketSort.prototype.bucketSortCallback = function(event)
+{
+ var savedIndex = this.nextIndex;
+ this.commands = new Array();
+ linkedListData = new Array(ARRAY_SIZE_SMALL);
+ var i;
+ for (i= 0; i < ARRAY_SIZE_SMALL; i++)
+ {
+ var labelID = this.nextIndex++;
+ var label2ID = this.nextIndex++;
+ var label3ID = this.nextIndex++;
+ var label4ID = this.nextIndex++;
+ var node = new LinkedListNode(this.arrayData[i],this.nextIndex++, 100, 75);
+ this.cmd("CreateLinkedList", node.graphicID, "", LINKED_ITEM_WIDTH_SMALL, LINKED_ITEM_HEIGHT_SMALL, 100, 75);
+ this.cmd("SetNull", node.graphicID, 1);
+
+ this.cmd("CreateLabel", labelID, this.arrayData[i], ARRAY_ELEM_START_X_SMALL + i *ARRAY_ELEM_WIDTH_SMALL, ARRAY_ELEMENT_Y_SMALL);
+ this.cmd("SetText", node.graphicID, "")
+ this.cmd("SetText", this.arrayRects[i], "")
+ this.cmd("Move", labelID, 100,75);
+ this.cmd("Step");
+ this.cmd("SetText", node.graphicID, this.arrayData[i]);
+ this.cmd("Delete", labelID);
+ var index = Math.floor((this.arrayData[i] * ARRAY_SIZE_SMALL) / (MAX_DATA_VALUE + 1));
+
+ this.cmd("CreateLabel", labelID, "Linked List Array index = " , 300, 20, 0);
+ this.cmd("CreateLabel", label2ID, "Value * NUMBER_OF_ELEMENTS / (MAXIMUM_ARRAY_VALUE + 1)) = ", 300, 40, 0);
+ this.cmd("CreateLabel", label3ID, "("+ String(this.arrayData[i]) + " * " + String(ARRAY_SIZE_SMALL) + ") / " + String(MAX_DATA_VALUE+1) + " = " , 300, 60, 0);
+ this.cmd("CreateLabel", label4ID, index, 305, 85);
+ this.cmd("SetForegroundColor", labelID, "#000000");
+ this.cmd("SetForegroundColor", label2ID, "#000000");
+ this.cmd("SetForegroundColor", label3ID, "#000000");
+ this.cmd("SetForegroundColor", label4ID, "#0000FF");
+
+
+ var highlightCircle = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", highlightCircle, "#0000FF", 305, 100);
+ this.cmd("Move", highlightCircle, POINTER_ARRAY_ELEM_START_X_SMALL + index *POINTER_ARRAY_ELEM_WIDTH_SMALL, this.pointer_array_elem_y_small + POINTER_ARRAY_ELEM_HEIGHT_SMALL);
+ this.cmd("Step");
+ this.cmd("Delete", labelID);
+ this.cmd("Delete", label2ID);
+ this.cmd("Delete", label3ID);
+ this.cmd("Delete", label4ID);
+ this.cmd("Delete", highlightCircle);
+
+
+
+ if (linkedListData[index] == null)
+ {
+ linkedListData[index] = node;
+ this.cmd("Connect", this.linkedListRects[index], node.graphicID);
+ this.cmd("SetNull",this.linkedListRects[index], 0);
+
+ node.x = POINTER_ARRAY_ELEM_START_X_SMALL + index *POINTER_ARRAY_ELEM_WIDTH_SMALL;
+ node.y = this.pointer_array_elem_y_small - LINKED_ITEM_Y_DELTA_SMALL;
+ this.cmd("Move", node.graphicID, node.x, node.y);
+ }
+ else
+ {
+ var tmp = linkedListData[index];
+ this.cmd("SetHighlight", tmp.graphicID, 1);
+ this.cmd("SetHighlight", node.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tmp.graphicID, 0);
+ this.cmd("SetHighlight", node.graphicID, 0);
+
+ if (Number(tmp.data) >= Number(node.data))
+ {
+ this.cmd("Disconnect", this.linkedListRects[index], linkedListData[index].graphicID);
+ node.next = tmp;
+ this.cmd("Connect", this.linkedListRects[index], node.graphicID);
+ this.cmd("Connect", node.graphicID, tmp.graphicID);
+ this.cmd("SetNull",node.graphicID, 0);
+ linkedListData[index] = node;
+ this.cmd("Connect", this.linkedListRects[index], node.graphicID);
+
+ }
+ else
+ {
+ if (tmp.next != null)
+ {
+ this.cmd("SetHighlight", tmp.next.graphicID, 1);
+ this.cmd("SetHighlight", node.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tmp.next.graphicID, 0);
+ this.cmd("SetHighlight", node.graphicID, 0);
+ }
+
+ while (tmp.next != null && tmp.next.data < node.data)
+ {
+ tmp = tmp.next;
+ if (tmp.next != null)
+ {
+ this.cmd("SetHighlight", tmp.next.graphicID, 1);
+ this.cmd("SetHighlight", node.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tmp.next.graphicID, 0);
+ this.cmd("SetHighlight", node.graphicID, 0);
+ }
+ }
+ if (tmp.next != null)
+ {
+ this.cmd("Disconnect", tmp.graphicID, tmp.next.graphicID);
+ this.cmd("Connect", node.graphicID, tmp.next.graphicID);
+ this.cmd("SetNull",node.graphicID, 0);
+ }
+ else
+ {
+ this.cmd("SetNull",tmp.graphicID, 0);
+ }
+ node.next = tmp.next;
+ tmp.next = node;
+ this.cmd("Connect", tmp.graphicID, node.graphicID);
+ }
+ tmp = linkedListData[index];
+ var startX = POINTER_ARRAY_ELEM_START_X_SMALL + index *POINTER_ARRAY_ELEM_WIDTH_SMALL;
+ var startY = this.pointer_array_elem_y_small - LINKED_ITEM_Y_DELTA_SMALL;
+ while (tmp != null)
+ {
+ tmp.x = startX;
+ tmp.y = startY;
+ this.cmd("Move", tmp.graphicID, tmp.x, tmp.y);
+ startY = startY - LINKED_ITEM_Y_DELTA_SMALL;
+ tmp = tmp.next;
+ }
+ }
+ this.cmd("Step");
+ }
+ var insertIndex = 0;
+ for (i = 0; i < ARRAY_SIZE_SMALL; i++)
+ {
+ for (tmp = linkedListData[i]; tmp != null; tmp = tmp.next)
+ {
+ var moveLabelID = this.nextIndex++;
+ this.cmd("SetText", tmp.graphicID, "");
+ this.cmd("SetText", this.arrayRects[insertIndex], "");
+ this.cmd("CreateLabel", moveLabelID, tmp.data, tmp.x, tmp.y);
+ this.cmd("Move", moveLabelID, ARRAY_ELEM_START_X_SMALL + insertIndex *ARRAY_ELEM_WIDTH_SMALL, ARRAY_ELEMENT_Y_SMALL);
+ this.cmd("Step");
+ this.cmd("Delete", moveLabelID);
+ this.cmd("SetText", this.arrayRects[insertIndex], tmp.data);
+ this.cmd("Delete", tmp.graphicID);
+ if (tmp.next != null)
+ {
+ this.cmd("Connect", this.linkedListRects[i], tmp.next.graphicID);
+ }
+ else
+ {
+ this.cmd("SetNull", this.linkedListRects[i], 1);
+ }
+ this.arrayData[insertIndex] = tmp.data;
+ insertIndex++;
+ }
+
+
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ insertIndex = savedIndex;
+}
+
+BucketSort.prototype.randomizeArray = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < ARRAY_SIZE_SMALL; i++)
+ {
+ this.arrayData[i] = Math.floor(1 + Math.random()*MAX_DATA_VALUE);
+ this.oldData[i] = this.arrayData[i];
+ this.cmd("SetText", this.arrayRects[i], this.arrayData[i]);
+ }
+
+
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+
+// We want to (mostly) ignore resets, since we are disallowing undoing
+BucketSort.prototype.reset = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < ARRAY_SIZE_SMALL; i++)
+ {
+ this.arrayData[i] = this.oldData[i];
+ }
+}
+
+
+BucketSort.prototype.resetCallback = function(event)
+{
+ this.randomizeArray();
+}
+
+
+
+BucketSort.prototype.disableUI = function(event)
+{
+ this.resetButton.disabled = true;
+ this.bucketSortButton.disabled = true;
+}
+BucketSort.prototype.enableUI = function(event)
+{
+ this.resetButton.disabled = false;
+ this.bucketSortButton.disabled = false;
+}
+
+function LinkedListNode(label, id, x, y)
+{
+ this.data = label;
+ this.graphicID = id;
+ this.x = x;
+ this.y = y;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new BucketSort(animManag, canvas.width, canvas.height);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ChangingCoordinate2D.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ChangingCoordinate2D.js
new file mode 100644
index 0000000..ab12702
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ChangingCoordinate2D.js
@@ -0,0 +1,1666 @@
+// 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
+
+
+
+function ChangeCoordinate2D(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+ChangeCoordinate2D.prototype = new Algorithm();
+ChangeCoordinate2D.prototype.constructor = ChangeCoordinate2D;
+ChangeCoordinate2D.superclass = Algorithm.prototype;
+
+ChangeCoordinate2D.XAxisYPos = 300;
+ChangeCoordinate2D.XAxisStart = 100;
+ChangeCoordinate2D.XAxisEnd = 700;
+
+ChangeCoordinate2D.MATRIX_ELEM_WIDTH = 50;
+ChangeCoordinate2D.MATRIX_ELEM_HEIGHT = 15;
+
+
+ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING = 10;
+ChangeCoordinate2D.EQUALS_SPACING = 30;
+
+ChangeCoordinate2D.ROBOT_MATRIX_START_X = 10 + 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING;
+ChangeCoordinate2D.ROBOT_MATRIX_START_Y = 30;
+
+ChangeCoordinate2D.HAND_MATRIX_START_X = 10 +2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING;
+ChangeCoordinate2D.HAND_MATRIX_START_Y = 10 + 25 + 20 + 3*ChangeCoordinate2D.MATRIX_ELEM_HEIGHT;
+
+
+ChangeCoordinate2D.ROBOT_POSITION_START_X = ChangeCoordinate2D.ROBOT_MATRIX_START_X + 4*ChangeCoordinate2D.MATRIX_ELEM_WIDTH + 100;
+ChangeCoordinate2D.HAND_POSITION_START_X = ChangeCoordinate2D.HAND_MATRIX_START_X + 4*ChangeCoordinate2D.MATRIX_ELEM_WIDTH + 100;
+
+
+ChangeCoordinate2D.ROBOT_POSITION_START_Y = ChangeCoordinate2D.ROBOT_MATRIX_START_Y;
+ChangeCoordinate2D.HAND_POSITION_START_Y = ChangeCoordinate2D.HAND_MATRIX_START_Y;
+
+
+ChangeCoordinate2D.YAxisXPos = 400;
+ChangeCoordinate2D.YAxisStart = 100;
+ChangeCoordinate2D.YAxisEnd = 500;
+
+ChangeCoordinate2D.ROBOT_POINTS = [[-15,100],[15,100],[15,80],[30,80],[30,-10],[15,-10], [15, -100], [0,-100],[0,-30],[0,-100], [-15, -100],
+ [-15, -10], [-30, -10], [-30, 80],[-15, 80]];
+
+
+ChangeCoordinate2D.HAND_POINTS = [[0,0],[-10,0],[-10,10], [-6, 10], [-6, 6], [6, 6], [6, 10], [10, 10], [10, 0]];
+
+ChangeCoordinate2D.ROBOT_HAND_ATTACH_POINT = [0, 40];
+
+
+
+ChangeCoordinate2D.ROBOT_MATRIX_VALUES = [[[Math.cos(Math.PI / 8), Math.sin(Math.PI / 8)],[-Math.sin(Math.PI / 8), Math.cos(Math.PI / 8)]],
+ [[Math.cos(Math.PI / 4), Math.sin(Math.PI / 4)],[-Math.sin(Math.PI / 4), Math.cos(Math.PI / 4)]],
+ [[Math.cos(0), Math.sin(0)],[-Math.sin(0), Math.cos(0)]],
+ [[Math.cos(3*Math.PI / 4), Math.sin(3*Math.PI/4)],[-Math.sin(3*Math.PI/4), Math.cos(3*Math.PI/4)]]];
+
+
+ChangeCoordinate2D.ROBOT_POSITION_VALUES = [[75, 50], [200,100],[100,100], [100, 200]];
+
+
+ChangeCoordinate2D.HAND_MATRIX_VALUES = [[[Math.cos(-Math.PI / 6), Math.sin(-Math.PI / 6)],[-Math.sin(-Math.PI / 6), Math.cos(-Math.PI / 6)]],
+ [[Math.cos(Math.PI / 4), Math.sin(Math.PI / 4)],[-Math.sin(Math.PI / 4), Math.cos(-Math.PI / 4)]],
+ [[Math.cos(0), Math.sin(0)],[-Math.sin(0), Math.cos(0)]],
+ [[Math.cos(Math.PI/2), Math.sin(Math.PI/2)],[-Math.sin(Math.PI/2), Math.cos(Math.PI/2)]]];
+
+
+ChangeCoordinate2D.HAND_POSITION_VALUES = [[80,30],[30,90],[100,100],[-50, -20]];
+
+
+//ChangeCoordinate2D.ROBOT_POINTS = [[-20, 40], [20,40],[
+
+
+
+ChangeCoordinate2D.AXIS_CENTER = [[750,470],[750,150],[100, 550]];
+
+ChangeCoordinate2D.AXIS_COLOR_0 = "#990000"
+ChangeCoordinate2D.AXIS_COLOR_1 = "#009900"
+ChangeCoordinate2D.AXIS_COLOR_2 = "#000099"
+
+ChangeCoordinate2D.LOCAL_VERTEX_FOREGORUND_COLOR = "#000000";
+ChangeCoordinate2D.LOCAL_VERTEX_BACKGROUND_COLOR = ChangeCoordinate2D.LOCAL_VERTEX_FOREGORUND_COLOR;
+ChangeCoordinate2D.LOCAL_EDGE_COLOR = "#000000";
+
+ChangeCoordinate2D.GLOBAL_VERTEX_FOREGORUND_COLOR = "#00FF00";
+ChangeCoordinate2D.GLOBAL_VERTEX_BACKGROUND_COLOR = ChangeCoordinate2D.GLOBAL_VERTEX_FOREGORUND_COLOR;
+ChangeCoordinate2D.GLOBAL_EDGE_COLOR = "#00FF00";
+
+
+
+ChangeCoordinate2D.TRANSFORMED_VERTEX_FOREGORUND_COLOR = "#66FF66";
+ChangeCoordinate2D.TRANSFORMED_VERTEX_BACKGROUND_COLOR = ChangeCoordinate2D.VERTEX_FOREGORUND_COLOR;
+ChangeCoordinate2D.TRANSFORMED_EDGE_COLOR = "#66FF66";
+
+
+ChangeCoordinate2D.TRANSFORMED_POINT_COLORS = ["#990000", "#009900", "#000099"]
+
+
+ChangeCoordinate2D.VECTOR_COLOR = "#FF0000";
+
+ChangeCoordinate2D.VERTEX_WIDTH = 3;
+ChangeCoordinate2D.VERTEX_HEIGHT = ChangeCoordinate2D.VERTEX_WIDTH;
+
+ChangeCoordinate2D.prototype.init = function(am, w, h)
+{
+ var sc = ChangeCoordinate2D.superclass.init.call(this, am, w, h);
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.addControls();
+ this.currentShape = 0;
+
+ this.commands = [];
+ this.nextIndex = 0;
+
+ this.PositionIndex = 0;
+
+ this.RobotPositionValues = ChangeCoordinate2D.ROBOT_POSITION_VALUES[this.PositionIndex];
+ this.RobotMatrixValues = ChangeCoordinate2D.ROBOT_MATRIX_VALUES[this.PositionIndex];
+ this.HandPositionValues = ChangeCoordinate2D.HAND_POSITION_VALUES[this.PositionIndex];
+ this.HandMatrixValues = ChangeCoordinate2D.HAND_MATRIX_VALUES[this.PositionIndex];
+
+ this.setupAxis();
+
+ this.robotLabel1ID = this.nextIndex++;
+ this.handLabel1ID = this.nextIndex++;
+ this.robotLabel2ID = this.nextIndex++;
+ this.handLabel2ID = this.nextIndex++;
+
+ this.cmd("CreateLabel", this.robotLabel1ID, "Robot Space to World Space\n(Orientation)", ChangeCoordinate2D.ROBOT_MATRIX_START_X, ChangeCoordinate2D.ROBOT_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.robotLabel1ID, "#0000FF");
+
+ this.cmd("CreateLabel", this.robotLabel2ID, "Robot Space to World Space\n(Position)", ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.robotLabel2ID, "#0000FF");
+
+
+
+ this.RobotMatrix = this.createMatrix(this.RobotMatrixValues, ChangeCoordinate2D.ROBOT_MATRIX_START_X, ChangeCoordinate2D.ROBOT_MATRIX_START_Y);
+ this.resetMatrixLabels(this.RobotMatrix);
+ this.HandMatrix = this.createMatrix(this.HandMatrixValues, ChangeCoordinate2D.HAND_MATRIX_START_X, ChangeCoordinate2D.HAND_MATRIX_START_Y);
+ this.resetMatrixLabels(this.HandMatrix);
+
+ this.cmd("CreateLabel", this.handLabel1ID, "Hand Space to Robot Space\n(Orientation)", ChangeCoordinate2D.HAND_MATRIX_START_X, ChangeCoordinate2D.HAND_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.handLabel1ID, "#0000FF");
+
+ this.cmd("CreateLabel", this.handLabel2ID, "Hand Space to Robot Space\n(Position)", ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.handLabel2ID, "#0000FF");
+
+
+
+ this.RobotPosition = this.createMatrix([this.RobotPositionValues], ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y);
+ this.resetMatrixLabels(this.RobotMatrix);
+ this.HandPosition = this.createMatrix([this.HandPositionValues], ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y);
+ this.resetMatrixLabels(this.HandMatrix);
+
+
+ var i;
+ this.RobotPointWorldIDs = new Array(ChangeCoordinate2D.ROBOT_POINTS.length);
+ this.RobotPointRobotIDs = new Array(ChangeCoordinate2D.ROBOT_POINTS.length);
+ this.HandPointWorldIDs = new Array(ChangeCoordinate2D.HAND_POINTS.length);
+ this.HandPointRobotIDs = new Array(ChangeCoordinate2D.HAND_POINTS.length);
+ this.HandPointHandIDs = new Array(ChangeCoordinate2D.HAND_POINTS.length);
+ this.RobotHandAttachRobotID = this.nextIndex++;
+ this.RobotHandAttachWorldID = this.nextIndex++;
+ for (i = 0; i < ChangeCoordinate2D.ROBOT_POINTS.length; i++)
+ {
+ this.RobotPointWorldIDs[i] = this.nextIndex++;
+ this.RobotPointRobotIDs[i] = this.nextIndex++;
+ }
+ for (i = 0; i < ChangeCoordinate2D.HAND_POINTS.length; i++)
+ {
+ this.HandPointWorldIDs[i] = this.nextIndex++;
+ this.HandPointRobotIDs[i] = this.nextIndex++;
+ this.HandPointHandIDs[i] = this.nextIndex++;
+ }
+
+ this.savedNextIndex = this.nextIndex;
+ this.setupObjects();
+ this.setupObjectGraphic();
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.clearHistory();
+ this.animationManager.setAllLayers([0, 1]);
+ this.lastLocalToGlobal = true;
+ this.oldIDs = [];
+
+
+}
+
+ChangeCoordinate2D.prototype.addAxis = function(origin, x1, x2, y1, y2, color)
+{
+ var idArray = [];
+ var originID = this.nextIndex++;
+ idArray.push(originID);
+ this.cmd("CreateRectangle", originID, "", 0, 0, origin[0], origin[1]);
+ this.cmd("SetAlpha", originID, 0);
+
+ var axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, x1[0], x1[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, x2[0], x2[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, y1[0], y1[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, y2[0], y2[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+
+ var labelID = this.nextIndex++;
+ this.cmd("CreateLabel", labelID, "+y", y2[0] - 10, y2[1] + 10);
+ this.cmd("SetForegroundColor", labelID, color);
+ idArray.push(labelID);
+
+
+ labelID = this.nextIndex++;
+ this.cmd("CreateLabel", labelID, "+x", x2[0] - 10, x2[1] + 10);
+ this.cmd("SetForegroundColor", labelID, color);
+ idArray.push(labelID);
+ return idArray;
+}
+
+
+ChangeCoordinate2D.prototype.transformPoint = function(point, matrix, position)
+{
+ return this.add(this.multiply([point], matrix), [position])[0];
+}
+
+
+ChangeCoordinate2D.prototype.setupExtraAxes = function()
+{
+ var robotOrigin = this.RobotPositionValues;
+ var x1 = this.transformPoint([-150, 0], this.RobotMatrixValues, this.RobotPositionValues);
+ var x2 = this.transformPoint([150, 0], this.RobotMatrixValues, this.RobotPositionValues);
+ var y1 = this.transformPoint([0, -150], this.RobotMatrixValues, this.RobotPositionValues);
+ var y2 = this.transformPoint([0, 150], this.RobotMatrixValues, this.RobotPositionValues);
+
+ this.otherAxes = [];
+
+ var tmpAxis = this.addAxis(this.worldToScreenSpace(robotOrigin, 2),
+ this.worldToScreenSpace(x1, 2),
+ this.worldToScreenSpace(x2, 2),
+ this.worldToScreenSpace(y1, 2),
+ this.worldToScreenSpace(y2, 2),
+ ChangeCoordinate2D.AXIS_COLOR_1);
+
+ this.otherAxes.push(tmpAxis);
+
+ for (var i = 0; i < tmpAxis.length; i++)
+ {
+ this.cmd("SetLayer", tmpAxis[i], 1);
+ }
+ this.setAxisAlpha(tmpAxis, 0.5);
+
+
+ var handOrigin = this.HandPositionValues;
+ x1 = this.transformPoint([-150, 0], this.HandMatrixValues, this.HandPositionValues);
+ x2 = this.transformPoint([150, 0], this.HandMatrixValues, this.HandPositionValues);
+ y1 = this.transformPoint([0, -150], this.HandMatrixValues, this.HandPositionValues);
+ y2 = this.transformPoint([0, 150], this.HandMatrixValues, this.HandPositionValues);
+
+
+ tmpAxis = this.addAxis(this.worldToScreenSpace(handOrigin, 1),
+ this.worldToScreenSpace(x1, 1),
+ this.worldToScreenSpace(x2, 1),
+ this.worldToScreenSpace(y1, 1),
+ this.worldToScreenSpace(y2, 1),
+ ChangeCoordinate2D.AXIS_COLOR_0);
+
+ for (var i = 0; i < tmpAxis.length; i++)
+ {
+ this.cmd("SetLayer", tmpAxis[i], 1);
+ }
+ this.setAxisAlpha(tmpAxis, 0.5);
+
+
+ this.otherAxes.push(tmpAxis);
+
+
+ handOrigin = this.transformPoint(handOrigin, this.RobotMatrixValues, this.RobotPositionValues);
+ x1 = this.transformPoint(x1, this.RobotMatrixValues, this.RobotPositionValues);
+ x2 = this.transformPoint(x2, this.RobotMatrixValues, this.RobotPositionValues);
+ y1 = this.transformPoint(y1, this.RobotMatrixValues, this.RobotPositionValues);
+ y2 = this.transformPoint(y2, this.RobotMatrixValues, this.RobotPositionValues);
+
+
+ tmpAxis = this.addAxis(this.worldToScreenSpace(handOrigin, 2),
+ this.worldToScreenSpace(x1, 2),
+ this.worldToScreenSpace(x2, 2),
+ this.worldToScreenSpace(y1, 2),
+ this.worldToScreenSpace(y2, 2),
+ ChangeCoordinate2D.AXIS_COLOR_0);
+ for (var i = 0; i < tmpAxis.length; i++)
+ {
+ this.cmd("SetLayer", tmpAxis[i], 1);
+ }
+
+ this.setAxisAlpha(tmpAxis, 0.5);
+
+ this.otherAxes.push(tmpAxis);
+
+}
+
+
+ChangeCoordinate2D.prototype.setupAxis = function()
+{
+
+ this.axisHand = this.addAxis(this.worldToScreenSpace([0,0], 0),
+ this.worldToScreenSpace([-150, 0], 0),
+ this.worldToScreenSpace([150,0], 0),
+ this.worldToScreenSpace([0, -150], 0),
+ this.worldToScreenSpace([0, 150], 0),
+ ChangeCoordinate2D.AXIS_COLOR_0);
+ this.setAxisAlpha(this.axisHand, 0.5);
+
+ this.axisRobot = this.addAxis(this.worldToScreenSpace([0,0], 1),
+ this.worldToScreenSpace([-150, 0], 1),
+ this.worldToScreenSpace([150,0], 1),
+ this.worldToScreenSpace([0, -150], 1),
+ this.worldToScreenSpace([0, 150], 1),
+ ChangeCoordinate2D.AXIS_COLOR_1);
+ this.setAxisAlpha(this.axisRobot, 0.5);
+
+ this.axisWorld = this.addAxis(this.worldToScreenSpace([0,0], 2),
+ this.worldToScreenSpace([-50, 0], 2),
+ this.worldToScreenSpace([400,0], 2),
+ this.worldToScreenSpace([0, -50], 2),
+ this.worldToScreenSpace([0, 400], 2),
+ ChangeCoordinate2D.AXIS_COLOR_2);
+ this.setAxisAlpha(this.axisWorld, 0.5);
+
+ this.setupExtraAxes();
+
+
+
+
+
+}
+
+
+ChangeCoordinate2D.prototype.setAxisAlpha = function(axisList, newAlpha)
+{
+ for (var i = 0; i < axisList.length; i++)
+ {
+ this.cmd("SetAlpha", axisList[i], newAlpha);
+ if (i > 0)
+ {
+ this.cmd("SetEdgeAlpha", axisList[0], axisList[i], newAlpha);
+ }
+ }
+
+}
+
+ChangeCoordinate2D.prototype.setupObjects = function()
+{
+
+ var i;
+ for (i = 0; i < ChangeCoordinate2D.ROBOT_POINTS.length; i++)
+ {
+
+
+ var point = this.worldToScreenSpace(ChangeCoordinate2D.ROBOT_POINTS[i], 1);
+ this.cmd("CreateRectangle", this.RobotPointRobotIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.RobotPointRobotIDs[i-1], this.RobotPointRobotIDs[i], "#000000", 0, 0);
+ }
+
+ point = this.transformPoint(ChangeCoordinate2D.ROBOT_POINTS[i], this.RobotMatrixValues, this.RobotPositionValues);
+ point = this.worldToScreenSpace(point, 2);
+
+ this.cmd("CreateRectangle", this.RobotPointWorldIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.RobotPointWorldIDs[i-1], this.RobotPointWorldIDs[i], "#000000", 0, 0);
+ }
+ }
+ this.cmd("Connect", this.RobotPointRobotIDs[this.RobotPointRobotIDs.length - 1], this.RobotPointRobotIDs[0], "#000000", 0, 0);
+ this.cmd("Connect", this.RobotPointWorldIDs[this.RobotPointWorldIDs.length - 1], this.RobotPointWorldIDs[0], "#000000", 0, 0);
+
+
+ for (i = 0; i < ChangeCoordinate2D.HAND_POINTS.length; i++)
+ {
+
+
+ var point = this.worldToScreenSpace(ChangeCoordinate2D.HAND_POINTS[i], 0);
+ this.cmd("CreateRectangle", this.HandPointHandIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.HandPointHandIDs[i-1], this.HandPointHandIDs[i], "#000000", 0, 0);
+ }
+
+ point = this.transformPoint(ChangeCoordinate2D.HAND_POINTS[i], this.HandMatrixValues, this.HandPositionValues);
+ var point2 = this.worldToScreenSpace(point, 1);
+
+ this.cmd("CreateRectangle", this.HandPointRobotIDs[i], "", 0, 0, point2[0], point2[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.HandPointRobotIDs[i-1], this.HandPointRobotIDs[i], "#000000", 0, 0);
+ }
+
+ point = this.transformPoint(point, this.RobotMatrixValues, this.RobotPositionValues);
+ point = this.worldToScreenSpace(point,2);
+
+ this.cmd("CreateRectangle", this.HandPointWorldIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.HandPointWorldIDs[i-1], this.HandPointWorldIDs[i], "#000000", 0, 0);
+ }
+
+
+ }
+ this.cmd("Connect", this.HandPointHandIDs[this.HandPointHandIDs.length - 1], this.HandPointHandIDs[0], "#000000", 0, 0);
+ this.cmd("Connect", this.HandPointRobotIDs[this.HandPointRobotIDs.length - 1], this.HandPointRobotIDs[0], "#000000", 0, 0);
+ this.cmd("Connect", this.HandPointWorldIDs[this.HandPointWorldIDs.length - 1], this.HandPointWorldIDs[0], "#000000", 0, 0);
+
+
+ point = this.worldToScreenSpace(ChangeCoordinate2D.ROBOT_HAND_ATTACH_POINT, 1);
+ this.cmd("CreateRectangle", this.RobotHandAttachRobotID, "", 0, 0, point[0], point[1]);
+ this.cmd("Connect", this.RobotHandAttachRobotID, this.HandPointRobotIDs[0], "#000000", 0, 0);
+
+ point = this.transformPoint(ChangeCoordinate2D.ROBOT_HAND_ATTACH_POINT, this.RobotMatrixValues, this.RobotPositionValues);
+ point = this.worldToScreenSpace(point, 2);
+ this.cmd("CreateRectangle", this.RobotHandAttachWorldID, "", 0, 0, point[0], point[1]);
+ this.cmd("Connect", this.RobotHandAttachWorldID, this.HandPointWorldIDs[0], "#000000", 0, 0);
+}
+
+
+ChangeCoordinate2D.prototype.worldToScreenSpace = function(point, space)
+{
+ var transformedPoint = new Array(2);
+
+ return [point[0] + ChangeCoordinate2D.AXIS_CENTER[space][0],
+ -point[1] + ChangeCoordinate2D.AXIS_CENTER[space][1]];
+}
+
+
+
+
+ChangeCoordinate2D.prototype.removeOldIDs = function()
+{
+ var i;
+ for (i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs = [];
+}
+
+
+
+ChangeCoordinate2D.prototype.setupObjectGraphic = function()
+{
+ var i;
+
+
+
+
+}
+
+ChangeCoordinate2D.prototype.addControls = function()
+{
+ this.controls = [];
+
+ addLabelToAlgorithmBar("x");
+
+ this.xField = addControlToAlgorithmBar("Text", "");
+ this.xField.onkeydown = this.returnSubmitFloat(this.xField, this.transformPointCallback.bind(this), 4, true);
+ this.controls.push(this.xField);
+
+ addLabelToAlgorithmBar("y");
+
+ this.yField = addControlToAlgorithmBar("Text", "");
+ this.yField.onkeydown = this.returnSubmitFloat(this.yField, this.transformPointCallback.bind(this), 4, true);
+ this.controls.push(this.yField);
+
+ var transformButton = addControlToAlgorithmBar("Button", "Transform Point");
+ transformButton.onclick = this.transformPointCallback.bind(this);
+ this.controls.push(transformButton);
+
+
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Hand Space -> World Space",
+ "World Space -> Hand Space",
+ ],
+ "Transform Type");
+ this.handToWorldButton = radioButtonList[0];
+ this.handToWorldButton.onclick = this.transformTypeChangedCallback.bind(this, false);
+ this.controls.push(this.handToWorldButton);
+
+
+ this.worldToHandButton = radioButtonList[1];
+ this.worldToHandButton.onclick = this.transformTypeChangedCallback.bind(this, true);
+ this.controls.push(this.worldToHandButton);
+
+ this.worldToHandButton.checked = this.lastLocalToGlobal;
+ this.handToWorldButton.checked = !this.lastLocalToGlobal;
+
+
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Row Major",
+ "Column Major",
+ ],
+ "RankType");
+ this.rowMajorButton = radioButtonList[0];
+ this.rowMajorButton.onclick = this.changeRowColMajorCallback.bind(this, true);
+ this.controls.push(this.rowMajorButton);
+
+ this.colMajorButton = radioButtonList[1];
+ this.colMajorButton.onclick = this.changeRowColMajorCallback.bind(this, false);
+ this.controls.push(this.colMajorButton);
+
+ this.rowMajorButton.checked = this.rowMajor;
+ this.colMajorButton.checked = !this.rowMajor;
+
+
+ this.showAxisBox = addCheckboxToAlgorithmBar("Show all axes");
+ this.showAxisBox.onclick = this.showAllAxesCallback.bind(this);
+ this.showAxisBox.checked = true;
+
+ //this.controls.push(this.showAxisBox);
+
+
+
+ var moveObjectsButton = addControlToAlgorithmBar("Button", "Move Objects");
+ moveObjectsButton.onclick = this.moveObjectsCallback.bind(this);
+
+ this.controls.push(moveObjectsButton);
+
+}
+
+
+
+ChangeCoordinate2D.prototype.showAllAxesCallback = function()
+{
+ if (this.showAxisBox.checked)
+ {
+ this.animationManager.setAllLayers([0,1]);
+ }
+ else
+ {
+ this.animationManager.setAllLayers([0]);
+ }
+
+
+}
+
+
+ChangeCoordinate2D.prototype.reset = function()
+{
+ this.rowMajor = true;
+ this.rowMajorButton.checked = this.rowMajor;
+ this.nextIndex = this.savedNextIndex;
+}
+
+
+ChangeCoordinate2D.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+ChangeCoordinate2D.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+ChangeCoordinate2D.prototype.transformTypeChangedCallback = function(globalToLocal)
+{
+ if (this.lastLocalToGlobal == globalToLocal)
+ {
+ this.implementAction(this.changeTransformType.bind(this,globalToLocal));
+ }
+}
+
+
+
+
+ChangeCoordinate2D.prototype.changeRowColMajorCallback = function(rowMajor)
+{
+ if (this.rowMajor != rowMajor)
+ {
+ this.implementAction(this.changeRowCol.bind(this), rowMajor);
+ }
+}
+
+ChangeCoordinate2D.prototype.transposeVisual = function(matrix)
+{
+ if (matrix.data.length == matrix.data[0].length)
+ {
+ var matrixSize = matrix.data.length;
+ var i, j, tmp, moveLabel1, moveLabel2;
+ var moveLabels = [];
+ for (i = 1; i < matrixSize; i++)
+ {
+ for (j = 0; j <= i; j++)
+ {
+ this.cmd("SetText", matrix.dataID[i][j], "");
+ this.cmd("SetText", matrix.dataID[j][i], "");
+ moveLabel1 = this.nextIndex++;
+ moveLabel2 = this.nextIndex++;
+ moveLabels.push(moveLabel1);
+ moveLabels.push(moveLabel2);
+ this.cmd("CreateLabel", moveLabel1,
+ matrix.data[i][j], matrix.x + ChangeCoordinate2D.MATRIX_ELEM_WIDTH / 2+ i * ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2+ j * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT);
+ this.cmd("CreateLabel", moveLabel2,
+ matrix.data[j][i], matrix.x + ChangeCoordinate2D.MATRIX_ELEM_WIDTH / 2+ j * ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2 + i * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT);
+ this.cmd("Move", moveLabel1, matrix.x + ChangeCoordinate2D.MATRIX_ELEM_WIDTH / 2+ j * ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2 + i * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT);
+ this.cmd("Move", moveLabel2, matrix.x + ChangeCoordinate2D.MATRIX_ELEM_WIDTH / 2+ i * ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2 + j * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT);
+ tmp = matrix.data[i][j];
+ matrix.data[i][j] = matrix.data[j][i];
+ matrix.data[j][i] = tmp;
+ }
+ }
+ this.cmd("Step");
+ for (i = 0; i < moveLabels.length; i++)
+ {
+ this.cmd("Delete", moveLabels[i]);
+ }
+ this.resetMatrixLabels(matrix);
+ return matrix;
+ }
+ else
+ {
+ var savedData = matrix.data;
+ var newData = new Array(savedData[0].length);
+ var i,j;
+ for (i = 0; i < savedData[0].length; i++)
+ {
+ newData[i] = [];
+ }
+ for (i = 0; i < savedData.length; i++)
+ {
+ for (j = 0; j < savedData[0].length; j++)
+ {
+ newData[j][i] = savedData[i][j];
+ }
+
+ }
+ var newMatrix = this.createMatrix(newData, matrix.x, matrix.y);
+ this.deleteMatrix(matrix);
+ return newMatrix;
+ }
+}
+
+ChangeCoordinate2D.prototype.changeRowCol = function(rowMajor)
+{
+ this.commands = new Array();
+ this.rowMajor= rowMajor;
+ if (this.rowMajorButton.checked != this.rowMajor)
+ {
+ this.rowMajorButton.checked = this.rowMajor;
+ }
+ if (this.colMajorButton.checked == this.rowMajor)
+ {
+ this.colMajorButton.checked = !this.rowMajor;
+ }
+ this.removeOldIDs();
+ this.RobotMatrix = this.transposeVisual(this.RobotMatrix);
+ this.RobotPosition = this.transposeVisual(this.RobotPosition);
+ this.HandMatrix = this.transposeVisual(this.HandMatrix);
+ this.HandPosition = this.transposeVisual(this.HandPosition);
+
+
+ return this.commands;
+}
+
+
+ChangeCoordinate2D.prototype.fixNumber = function(value, defaultVal)
+{
+ if (value == "" || value == "-" || value == "." || value == "-." || isNaN(parseFloat(value)))
+ {
+ value = defaultVal;
+ }
+ else
+ {
+ value = String(parseFloat(value));
+ }
+ return value
+}
+
+ChangeCoordinate2D.prototype.transformPointCallback = function()
+{
+
+
+ this.xField.value = this.fixNumber(this.xField.value, "0");
+ this.yField.value = this.fixNumber(this.yField.value, "0");
+ this.implementAction(this.doPointTransform.bind(this), this.xField.value + ";" + this.yField.value);
+
+}
+
+
+ChangeCoordinate2D.prototype.doPointTransform = function(params)
+{
+ if (this.lastLocalToGlobal)
+ {
+ return this.localToGlobal(params);
+ }
+ else
+ {
+ return this.globalToLocal(params);
+ }
+}
+
+
+
+
+
+ChangeCoordinate2D.prototype.rotatePoint = function(point, matrix, xPos, yPos, fromSpace, toSpace)
+{
+ var logicalPoint;
+ var descriptLabel = this.nextIndex++;
+ // this.oldIDs.push(descriptLabel);
+ this.cmd("CreateLabel", descriptLabel, "", xPos + 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING,
+ yPos + 2*ChangeCoordinate2D.MATRIX_ELEM_HEIGHT + 3, 0);
+
+ var inertialPositionMatrix;
+
+ if (this.rowMajor)
+ {
+ inertialPositionMatrix = this.createMatrix([["", ""]], xPos + 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING,
+ yPos);
+ }
+ else
+ {
+ inertialPositionMatrix = this.createMatrix([[""], [""]],
+ xPos + 3 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING,
+ yPos);
+
+ }
+ var equalLabel1 = this.nextIndex++;
+ this.oldIDs.push(equalLabel1);
+ if (this.rowMajor)
+ {
+ opX = xPos + 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING / 2;
+ opY = yPos + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2;
+ }
+ else
+ {
+ opX = xPos + 3 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING / 2 + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING;
+ opY = yPos + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT;
+
+
+ }
+
+ this.cmd("CreateLabel", equalLabel1, "=", opX , opY);
+ if (this.rowMajor)
+ {
+ this.multiplyMatrix(point, matrix, inertialPositionMatrix, descriptLabel);
+
+ }
+ else
+ {
+ this.multiplyMatrix(matrix, point, inertialPositionMatrix, descriptLabel);
+
+ }
+ this.addMatrixIDsToList(inertialPositionMatrix, this.oldIDs);
+ this.cmd("Delete", descriptLabel);
+ var inertialPositionID = this.nextIndex++;
+ if (this.rowMajor)
+ {
+ logicalPoint = inertialPositionMatrix.data[0].slice(0);
+
+ }
+ else
+ {
+ logicalPoint = [inertialPositionMatrix.data[0][0], inertialPositionMatrix.data[1][0]];
+ }
+ screenPoint = this.worldToScreenSpace(logicalPoint, fromSpace);
+
+
+ this.cmd("CreateCircle", inertialPositionID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", inertialPositionID, ChangeCoordinate2D.VERTEX_WIDTH);
+
+ var originID = this.nextIndex++;
+ this.oldIDs.push(originID);
+ var origin = this.worldToScreenSpace([0,0], fromSpace);
+
+
+ this.cmd("CreateRectangle", originID, "", 0, 0, origin[0], origin[1]);
+
+ this.cmd("Connect", originID, inertialPositionID, ChangeCoordinate2D.TRANSFORMED_POINT_COLORS[toSpace], 0, 1, "");
+
+
+ return [inertialPositionMatrix, inertialPositionID, originID];
+}
+
+ChangeCoordinate2D.prototype.translatePoint = function(point, transVector, xPos, yPos, fromSpace, toSpace, pointID)
+{
+ var logicalPoint = new Array(2);
+ var robotPositionMatrix;
+ if (this.rowMajor)
+ {
+ logicalPoint[0] = point.data[0][0] + transVector.data[0][0];
+ logicalPoint[1] = point.data[0][1] + transVector.data[0][1];
+ robotPositionMatrix = this.createMatrix([["", ""]], xPos + 2*ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING,
+ yPos);
+ }
+ else
+ {
+ logicalPoint[0] = point.data[0][0] + transVector.data[0][0];
+ logicalPoint[1] = point.data[1][0] + transVector.data[1][0];
+ robotPositionMatrix = this.createMatrix([[""],[""]], xPos + ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING,
+ yPos);
+
+ }
+
+ var addLabel1 = this.nextIndex++;
+ var equalLabel3 = this.nextIndex++;
+ this.oldIDs.push(addLabel1);
+ this.oldIDs.push(equalLabel3);
+ var op2X, op2Y;
+ if (this.rowMajor)
+ {
+ opX = xPos + 2*ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING / 2;
+ opY = yPos + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2;
+ op2X = xPos - ChangeCoordinate2D.EQUALS_SPACING / 2;
+ op2Y = yPos + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2;
+
+ }
+ else
+ {
+ opX = xPos + ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.EQUALS_SPACING / 2;
+ opY = yPos + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT;
+ op2X = xPos - ChangeCoordinate2D.EQUALS_SPACING / 2;
+ op2Y = yPos + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT;
+
+
+ }
+ this.cmd("CreateLabel", equalLabel3, "=",opX , opY);
+ this.cmd("CreateLabel", addLabel1, "+",op2X , op2Y);
+
+
+
+
+ this.addMatrix(point, transVector, robotPositionMatrix);
+ this.addMatrixIDsToList(robotPositionMatrix, this.oldIDs);
+
+ var screenPoint = this.worldToScreenSpace(logicalPoint, fromSpace);
+
+ var robotPositionID = this.nextIndex++;
+
+ this.cmd("CreateCircle", robotPositionID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", robotPositionID, ChangeCoordinate2D.VERTEX_WIDTH);
+
+
+ this.cmd("Connect",pointID, robotPositionID, ChangeCoordinate2D.TRANSFORMED_POINT_COLORS[toSpace], 0, 1, "");
+ this.cmd("Step")
+
+
+
+ var originID = this.nextIndex++;
+ this.oldIDs.push(originID);
+ var origin = this.worldToScreenSpace([0,0], fromSpace);
+
+ this.cmd("CreateCircle", originID, "", origin[0], origin[1]);
+ this.cmd("SetWidth", originID, 0);
+ this.cmd("SetAlpha", originID, 0);
+
+ this.cmd("Connect",originID, robotPositionID, ChangeCoordinate2D.TRANSFORMED_POINT_COLORS[toSpace], 0, 1, "");
+
+ return [robotPositionMatrix, robotPositionID, originID];
+
+
+}
+
+
+ChangeCoordinate2D.prototype.addMultiply = function(position, transVector, rotMatrix, transX, transY, rotX, rotY, initialPointID, fromSpace, toSpace)
+{
+
+ var posMatrixAndPointID = this.translatePoint(position, transVector, transX, transY, fromSpace, toSpace, initialPointID);
+ var newPosition = posMatrixAndPointID[0];
+ var pointID = posMatrixAndPointID[1];
+ var originID = posMatrixAndPointID[2];
+
+ this.cmd("Step");
+
+ this.cmd("Disconnect", initialPointID, pointID);
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(newPosition, rotX - 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH - ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING,transY)
+ }
+ else
+ {
+ this.moveMatrix(newPosition, rotX + 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING, transY)
+ }
+
+
+ var posMatrixAndPointID = this.rotatePoint(newPosition, rotMatrix, rotX, rotY, fromSpace, toSpace);
+ this.cmd("Delete", pointID);
+ this.cmd("Step");
+
+ var robotPositionMatrix = posMatrixAndPointID[0];
+ var robotPositionID = posMatrixAndPointID[1];
+ var movingOriginID = posMatrixAndPointID[2];
+
+ var origin = this.worldToScreenSpace([0,0], toSpace);
+ this.cmd("Move", movingOriginID, origin[0], origin[1]);
+
+
+ var logicalPoint;
+ if (this.rowMajor)
+ {
+ logicalPoint = robotPositionMatrix.data[0].slice(0);
+
+ }
+ else
+ {
+ logicalPoint = [robotPositionMatrix.data[0][0], robotPositionMatrix.data[1][0]];
+ }
+
+
+
+
+ var screenPoint = this.worldToScreenSpace(logicalPoint, toSpace);
+ this.cmd("Move", robotPositionID, screenPoint[0], screenPoint[1]);
+
+ this.cmd("Step");
+
+
+ this.oldIDs.push(robotPositionID);
+
+
+ return [robotPositionMatrix, robotPositionID ];
+}
+
+
+ChangeCoordinate2D.prototype.multiplyAdd = function(position, rotMatrix, transVector, rotX, rotY, transX, transY, fromSpace, toSpace)
+{
+ var posMatrixAndPointID = this.rotatePoint(position, rotMatrix, rotX, rotY, fromSpace, toSpace);
+ var inertialPositionMatrix = posMatrixAndPointID[0];
+ var inertialPositionID = posMatrixAndPointID[1];
+
+
+ this.cmd("Step");
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(inertialPositionMatrix, transX - 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH - ChangeCoordinate2D.EQUALS_SPACING,transY)
+ }
+ else
+ {
+ this.moveMatrix(inertialPositionMatrix, transX - ChangeCoordinate2D.MATRIX_ELEM_WIDTH - ChangeCoordinate2D.EQUALS_SPACING, transY)
+ }
+
+
+ posMatrixAndPointID = this.translatePoint(inertialPositionMatrix, transVector, transX, transY, fromSpace, toSpace, inertialPositionID);
+ var robotPositionMatrix = posMatrixAndPointID[0];
+ var robotPositionID = posMatrixAndPointID[1];
+ var movingOriginID = posMatrixAndPointID[2];
+
+ this.oldIDs.push(robotPositionID);
+
+ var logicalPoint;
+ if (this.rowMajor)
+ {
+ logicalPoint = robotPositionMatrix.data[0].slice(0);
+
+ }
+ else
+ {
+ logicalPoint = [robotPositionMatrix.data[0][0], robotPositionMatrix.data[1][0]];
+ }
+
+
+ this.cmd("Step");
+
+ this.cmd("Delete", inertialPositionID);
+ origin = this.worldToScreenSpace([0,0], toSpace);
+ this.cmd("Move", movingOriginID, origin[0], origin[1]);
+ screenPoint = this.worldToScreenSpace(logicalPoint, toSpace);
+ this.cmd("Move", robotPositionID, screenPoint[0], screenPoint[1]);
+
+ this.cmd("Step");
+ return robotPositionMatrix;
+
+}
+
+ChangeCoordinate2D.prototype.localToGlobal = function (params)
+{
+ this.commands = [];
+ this.removeOldIDs();
+
+
+ var paramList = params.split(";");
+ var x = parseFloat(paramList[0]);
+ var y = parseFloat(paramList[1]);
+
+ var opX, opY;
+
+
+ var screenPoint = this.worldToScreenSpace([x,y], 0);
+ var logicalPoint;
+
+ var pointInHandSpaceID = this.nextIndex++;
+ this.oldIDs.push(pointInHandSpaceID);
+
+ this.cmd("CreateCircle", pointInHandSpaceID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", pointInHandSpaceID, ChangeCoordinate2D.VERTEX_WIDTH);
+
+ this.cmd("Connect", this.axisHand[0], pointInHandSpaceID, ChangeCoordinate2D.TRANSFORMED_POINT_COLORS[0], 0, 1, "");
+
+ var initialPointMatrix;
+ if (this.rowMajor)
+ {
+ initialPointMatrix = this.createMatrix([[x, y]], ChangeCoordinate2D.HAND_MATRIX_START_X - 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH - ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate2D.HAND_MATRIX_START_Y);
+ }
+ else
+ {
+ initialPointMatrix = this.createMatrix([[x], [y]], ChangeCoordinate2D.HAND_MATRIX_START_X + 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate2D.HAND_MATRIX_START_Y);
+
+ }
+ this.addMatrixIDsToList(initialPointMatrix, this.oldIDs);
+ this.cmd("Step");
+
+ var robotPositionMatrix = this.multiplyAdd(initialPointMatrix, this.HandMatrix, this.HandPosition,
+ ChangeCoordinate2D.HAND_MATRIX_START_X, ChangeCoordinate2D.HAND_MATRIX_START_Y,
+ ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y,
+ 0, 1);
+
+
+
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate2D.ROBOT_MATRIX_START_X - 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH - ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate2D.ROBOT_MATRIX_START_Y);
+ }
+ else
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate2D.ROBOT_MATRIX_START_X + 2* ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate2D.ROBOT_MATRIX_START_Y);
+
+ }
+
+
+ this.multiplyAdd(robotPositionMatrix, this.RobotMatrix, this.RobotPosition,
+ ChangeCoordinate2D.ROBOT_MATRIX_START_X, ChangeCoordinate2D.ROBOT_MATRIX_START_Y,
+ ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y,
+ 1, 2);
+
+
+
+
+
+ return this.commands;
+}
+
+ChangeCoordinate2D.prototype.changeTransformType = function(globalToLocal)
+{
+ this.commands = [];
+ this.lastLocalToGlobal = !globalToLocal;
+ this.removeOldIDs();
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.robotLabel1ID, "World Space to Robot Space\n(Orientation)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.robotLabel1ID, "Robot Space to World Space\n(Orientation)");
+ }
+ this.cmd("Step");
+ this.RobotMatrix = this.transposeVisual(this.RobotMatrix)
+
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.robotLabel2ID, "World Space to Robot Space\n(Position)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.robotLabel2ID, "Robot Space to World Space\n(Position)");
+ }
+ this.cmd("Step");
+ this.negateMatrixVisual(this.RobotPosition);
+ this.cmd("Step");
+
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.handLabel1ID, "Robot Space to Hand Space\n(Orientation)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.handLabel1ID, "Hand Space to Robot Space\n(Orientation)");
+ }
+
+ this.cmd("Step");
+ this.HandMatrix = this.transposeVisual(this.HandMatrix)
+
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.handLabel2ID, "Robot Space to Hand Space\n(Position)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.handLabel2ID, "Hand Space to Robot Space\n(Position)");
+ }
+ this.cmd("Step");
+ this.negateMatrixVisual(this.HandPosition);
+ this.cmd("Step");
+
+ if (globalToLocal)
+ {
+ this.cmd("Move", this.robotLabel1ID, ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y - 25);
+ this.moveMatrix(this.RobotMatrix, ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y)
+
+ this.cmd("Move", this.robotLabel2ID, ChangeCoordinate2D.ROBOT_MATRIX_START_X+ ChangeCoordinate2D.EQUALS_SPACING, ChangeCoordinate2D.ROBOT_MATRIX_START_Y - 25);
+ this.moveMatrix(this.RobotPosition, ChangeCoordinate2D.ROBOT_MATRIX_START_X+ ChangeCoordinate2D.EQUALS_SPACING, ChangeCoordinate2D.ROBOT_MATRIX_START_Y)
+
+ this.cmd("Move", this.handLabel1ID, ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y - 25);
+ this.moveMatrix(this.HandMatrix, ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y);
+
+
+ this.cmd("Move", this.handLabel2ID, ChangeCoordinate2D.HAND_MATRIX_START_X+ ChangeCoordinate2D.EQUALS_SPACING, ChangeCoordinate2D.HAND_MATRIX_START_Y - 25);
+ this.moveMatrix(this.HandPosition, ChangeCoordinate2D.HAND_MATRIX_START_X+ ChangeCoordinate2D.EQUALS_SPACING, ChangeCoordinate2D.HAND_MATRIX_START_Y);
+ }
+ else
+ {
+ this.cmd("Move", this.robotLabel1ID, ChangeCoordinate2D.ROBOT_MATRIX_START_X, ChangeCoordinate2D.ROBOT_MATRIX_START_Y - 25);
+ this.moveMatrix(this.RobotMatrix, ChangeCoordinate2D.ROBOT_MATRIX_START_X, ChangeCoordinate2D.ROBOT_MATRIX_START_Y)
+
+ this.cmd("Move", this.robotLabel2ID, ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y - 25);
+ this.moveMatrix(this.RobotPosition, ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y)
+
+ this.cmd("Move", this.handLabel1ID, ChangeCoordinate2D.HAND_MATRIX_START_X, ChangeCoordinate2D.HAND_MATRIX_START_Y - 25);
+ this.moveMatrix(this.HandMatrix, ChangeCoordinate2D.HAND_MATRIX_START_X, ChangeCoordinate2D.HAND_MATRIX_START_Y);
+
+ this.cmd("Move", this.handLabel2ID, ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y - 25);
+ this.moveMatrix(this.HandPosition, ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y);
+
+ }
+ return this.commands;
+}
+
+
+ChangeCoordinate2D.prototype.negateMatrixVisual = function(matrix)
+{
+ var i,j
+ for (i = 0; i < matrix.data.length; i++)
+ {
+ for (j = 0; j < matrix.data[i].length; j++)
+ {
+ matrix.data[i][j] = -matrix.data[i][j]
+ }
+ }
+ this.resetMatrixLabels(matrix);
+}
+
+
+ChangeCoordinate2D.prototype.globalToLocal = function(params)
+{
+ this.commands = [];
+ this.removeOldIDs();
+
+
+ var paramList = params.split(";");
+ var x = parseFloat(paramList[0]);
+ var y = parseFloat(paramList[1]);
+
+ var opX, opY;
+
+
+ var screenPoint = this.worldToScreenSpace([x,y], 2);
+ var logicalPoint;
+
+ var pointInWorldSpaceID = this.nextIndex++;
+ this.oldIDs.push(pointInWorldSpaceID);
+ this.cmd("CreateCircle", pointInWorldSpaceID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", pointInWorldSpaceID, ChangeCoordinate2D.VERTEX_WIDTH);
+ this.cmd("Connect", this.axisWorld[0], pointInWorldSpaceID, ChangeCoordinate2D.TRANSFORMED_POINT_COLORS[2], 0, 1, "");
+
+ var initialPointMatrix;
+ if (this.rowMajor)
+ {
+ initialPointMatrix = this.createMatrix([[x, y]], ChangeCoordinate2D.ROBOT_MATRIX_START_X - 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate2D.ROBOT_MATRIX_START_Y);
+ }
+ else
+ {
+ initialPointMatrix = this.createMatrix([[x], [y]], ChangeCoordinate2D.ROBOT_MATRIX_START_X - ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate2D.ROBOT_MATRIX_START_Y);
+
+ }
+ this.addMatrixIDsToList(initialPointMatrix, this.oldIDs);
+ this.cmd("Step");
+
+ var positionAndID = this.addMultiply(initialPointMatrix, this.RobotPosition, this.RobotMatrix,
+ ChangeCoordinate2D.ROBOT_MATRIX_START_X + ChangeCoordinate2D.EQUALS_SPACING, ChangeCoordinate2D.ROBOT_MATRIX_START_Y,
+ ChangeCoordinate2D.ROBOT_POSITION_START_X, ChangeCoordinate2D.ROBOT_POSITION_START_Y,
+ pointInWorldSpaceID,
+ 2, 1);
+
+ var robotPositionMatrix = positionAndID[0];
+ var newPositionID = positionAndID[1];
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate2D.HAND_MATRIX_START_X - 2 * ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate2D.HAND_MATRIX_START_Y);
+ }
+ else
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate2D.HAND_MATRIX_START_X - ChangeCoordinate2D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate2D.HAND_MATRIX_START_Y);
+
+ }
+
+
+ this.addMultiply(robotPositionMatrix, this.HandPosition, this.HandMatrix,
+ ChangeCoordinate2D.HAND_MATRIX_START_X + ChangeCoordinate2D.EQUALS_SPACING, ChangeCoordinate2D.HAND_MATRIX_START_Y,
+ ChangeCoordinate2D.HAND_POSITION_START_X, ChangeCoordinate2D.HAND_POSITION_START_Y,
+ newPositionID,
+ 1, 0);
+
+
+
+ return this.commands;
+}
+
+ChangeCoordinate2D.prototype.moveObjectsCallback = function()
+{
+ this.implementAction(this.moveObjects.bind(this), 0);
+}
+
+ChangeCoordinate2D.prototype.moveObjects = function()
+{
+ this.commands = [];
+ this.removeOldIDs();
+ var i, j;
+
+ for (i = 0; i < this.otherAxes.length; i++)
+ {
+ for (j = 0; j < this.otherAxes[i].length; j++)
+ {
+ this.cmd("Delete", this.otherAxes[i][j]);
+ }
+ }
+
+
+ var i;
+ for (i = 0; i < ChangeCoordinate2D.ROBOT_POINTS.length; i++)
+ {
+
+ this.cmd("Delete", this.RobotPointRobotIDs[i]);
+ this.cmd("Delete", this.RobotPointWorldIDs[i]);
+ }
+ for (i = 0; i < ChangeCoordinate2D.HAND_POINTS.length; i++)
+ {
+ this.cmd("Delete", this.HandPointHandIDs[i]);
+ this.cmd("Delete", this.HandPointRobotIDs[i]);
+ this.cmd("Delete", this.HandPointWorldIDs[i]);
+ }
+ this.cmd("Delete", this.RobotHandAttachRobotID);
+ this.cmd("Delete", this.RobotHandAttachWorldID);
+ this.PositionIndex+= 1;
+ if (this.PositionIndex >= ChangeCoordinate2D.ROBOT_POSITION_VALUES.length)
+ {
+ this.PositionIndex = 0;
+ }
+
+ this.RobotPositionValues = ChangeCoordinate2D.ROBOT_POSITION_VALUES[this.PositionIndex];
+ this.RobotMatrixValues = ChangeCoordinate2D.ROBOT_MATRIX_VALUES[this.PositionIndex];
+ this.HandPositionValues = ChangeCoordinate2D.HAND_POSITION_VALUES[this.PositionIndex];
+ this.HandMatrixValues = ChangeCoordinate2D.HAND_MATRIX_VALUES[this.PositionIndex];
+
+ this.setupExtraAxes();
+ this.setupObjects();
+
+
+ this.RobotPosition.data = [this.RobotPositionValues];
+ this.RobotMatrix.data = this.RobotMatrixValues;
+ this.HandPosition.data = [this.HandPositionValues];
+ this.HandMatrix.data =this.HandMatrixValues;
+ if (!this.rowMajor)
+ {
+ this.RobotPosition.transpose();
+ this.RobotMatrix.transpose();
+ this.HandPosition.transpose();
+ this.HandMatrix.transpose();
+ }
+ this.resetMatrixLabels(this.RobotMatrix);
+ this.resetMatrixLabels(this.RobotPosition);
+ this.resetMatrixLabels(this.HandMatrix);
+ this.resetMatrixLabels(this.HandPosition);
+
+
+ return this.commands;
+}
+
+
+function toRadians(degrees)
+{
+ return (degrees * 2 * Math.PI) / 360.0;
+}
+
+
+ChangeCoordinate2D.prototype.addMatrix = function(mat1, mat2, mat3)
+{
+ var i;
+ var j;
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat1.data[i].length; j++)
+ {
+ explainText = "";
+ var value = 0;
+ this.cmd("SetHighlight", mat1.dataID[i][j], 1);
+ this.cmd("SetHighlight", mat2.dataID[i][j], 1);
+ this.cmd("Step");
+ mat3.data[i][j] = this.standardize(mat1.data[i][j] + mat2.data[i][j]);
+ this.cmd("SetHighlight", mat1.dataID[i][j], 0);
+ this.cmd("SetHighlight", mat2.dataID[i][j], 0);
+ this.cmd("SetText", mat3.dataID[i][j], mat3.data[i][j]);
+ this.cmd("Step");
+ }
+ }
+}
+
+
+
+
+ChangeCoordinate2D.prototype.multiplyMatrix = function(mat1, mat2, mat3, explainID)
+{
+ var i;
+ var j;
+ var explainText = "";
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat2.data[0].length; j++)
+ {
+ var explainText = "";
+ var value = 0;
+ for (k = 0; k < mat2.data.length; k++)
+ {
+ this.cmd("SetHighlight", mat1.dataID[i][k], 1);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 1);
+ if (explainText != "")
+ {
+ explainText = explainText + " + ";
+ }
+ value = value + mat1.data[i][k] * mat2.data[k][j];
+ explainText = explainText + String(mat1.data[i][k]) + " * " + String(mat2.data[k][j]);
+ this.cmd("SetText", explainID, explainText);
+ this.cmd("Step");
+ this.cmd("SetHighlight", mat1.dataID[i][k], 0);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 0);
+ }
+ value = this.standardize(value);
+ explainText += " = " + String(value);
+ this.cmd("SetText", explainID, explainText);
+ mat3.data[i][j] = value;
+ this.cmd("SetText", mat3.dataID[i][j], value);
+ this.cmd("Step");
+ }
+ }
+ this.cmd("SetText", explainID, "");
+
+
+}
+
+ChangeCoordinate2D.prototype.standardize = function(lab)
+{
+ var newLab = Math.round(lab * 1000) / 1000;
+ if (isNaN(newLab))
+ {
+ return lab;
+ }
+ else
+ {
+ return newLab;
+ }
+}
+
+
+ChangeCoordinate2D.prototype.resetMatrixLabels = function(mat)
+{
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.data[i][j] = this.standardize(mat.data[i][j]);
+ this.cmd("SetText", mat.dataID[i][j], mat.data[i][j]);
+ }
+ }
+}
+
+
+
+ChangeCoordinate2D.prototype.moveMatrix = function(mat, x, y)
+{
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ }
+
+
+ this.cmd("Move", mat.leftBrack1, x, y);
+ this.cmd("Move", mat.leftBrack2, x, y);
+ this.cmd("Move", mat.leftBrack3, x, y + height * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT);
+
+ this.cmd("Move", mat.rightBrack1, x + width * ChangeCoordinate2D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack2, x + width * ChangeCoordinate2D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack3, x+ width * ChangeCoordinate2D.MATRIX_ELEM_WIDTH, y + height * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT);
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Move", mat.dataID[i][j],
+ x + j*ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_ELEM_WIDTH / 2,
+ y + i*ChangeCoordinate2D.MATRIX_ELEM_HEIGHT + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ mat.x = x;
+ mat.y = y;
+}
+
+
+
+
+ChangeCoordinate2D.prototype.addMatrixIDsToList = function(mat, list)
+{
+ list.push(mat.leftBrack1);
+ list.push(mat.leftBrack2);
+ list.push(mat.leftBrack3);
+ list.push(mat.rightBrack1);
+ list.push(mat.rightBrack2);
+ list.push(mat.rightBrack3);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ list.push(mat.dataID[i][j]);
+ }
+
+ }
+}
+
+ChangeCoordinate2D.prototype.deleteMatrix = function(mat)
+{
+ var IDList = [];
+ this.addMatrixIDsToList(mat, IDList);
+ var i;
+ for (i = 0; i < IDList.length; i++)
+ {
+ this.cmd("Delete", IDList[i]);
+ }
+}
+
+
+
+
+ChangeCoordinate2D.prototype.aplyFunctionToMatrixElems = function(mat, command, value)
+{
+ this.cmd(command, mat.leftBrack1, value);
+ this.cmd(command, mat.leftBrack2, value);
+ this.cmd(command, mat.leftBrack3, value);
+ this.cmd(command, mat.rightBrack1, value);
+ this.cmd(command, mat.rightBrack2, value);
+ this.cmd(command, mat.rightBrack3, value);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd(command, mat.dataID[i][j], value);
+ }
+ }
+}
+
+
+
+// Multiply two (data only!) matrices (not complete matrix object with graphics, just
+// the data
+ChangeCoordinate2D.prototype.multiply = function(lhs, rhs)
+{
+ var resultMat = new Array(lhs.length);
+ var i, j, k;
+
+ for (i = 0; i < lhs.length; i++)
+ {
+ resultMat[i] = new Array(rhs[0].length);
+ }
+ for (i = 0; i < lhs.length; i++)
+ {
+ for (j = 0; j < rhs[0].length; j++)
+ {
+ var value = 0;
+ for (k = 0; k < rhs.length; k++)
+ {
+ value = value + lhs[i][k] * rhs[k][j];
+ }
+ resultMat[i][j] = value;
+ }
+ }
+ return resultMat;
+}
+
+// Add two (data only!) matrices (not complete matrix object with graphics, just
+// the data)
+ChangeCoordinate2D.prototype.add = function(lhs, rhs)
+{
+ var resultMat = new Array(lhs.length);
+ var i,j;
+
+ for (i = 0; i < lhs.length; i++)
+ {
+ resultMat[i] = new Array(lhs[i].length);
+ for (j = 0; j < lhs[i].length; j++)
+ {
+ resultMat[i][j] = lhs[i][j] + rhs[i][j];
+
+ }
+ }
+ return resultMat;
+}
+
+
+ChangeCoordinate2D.prototype.createMatrix = function(contents, x, y)
+{
+ var mat = new Matrix(contents, x, y);
+ mat.leftBrack1 = this.nextIndex++;
+ mat.leftBrack2 = this.nextIndex++;
+ mat.leftBrack3 = this.nextIndex++;
+ mat.rightBrack1 = this.nextIndex++;
+ mat.rightBrack2 = this.nextIndex++;
+ mat.rightBrack3 = this.nextIndex++;
+
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ mat.dataID = new Array(mat.data.length);
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ mat.dataID[i] = new Array(mat.data[i].length);
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.dataID[i][j] = this.nextIndex++;
+ }
+ }
+
+ this.cmd("CreateRectangle", mat.leftBrack1, "", 5, 1, x, y, "left","center");
+ this.cmd("CreateRectangle", mat.leftBrack2, "", 1, height * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT, x, y, "center","top");
+ this.cmd("CreateRectangle", mat.leftBrack3, "", 5, 1, x, y + height * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT , "left","center");
+
+ this.cmd("CreateRectangle", mat.rightBrack1, "", 5, 1, x + width * ChangeCoordinate2D.MATRIX_ELEM_WIDTH, y, "right","center");
+ this.cmd("CreateRectangle", mat.rightBrack2, "", 1, height * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT, x + width * ChangeCoordinate2D.MATRIX_ELEM_WIDTH, y, "center","top");
+ this.cmd("CreateRectangle", mat.rightBrack3, "", 5, 1, x+ width * ChangeCoordinate2D.MATRIX_ELEM_WIDTH, y + height * ChangeCoordinate2D.MATRIX_ELEM_HEIGHT , "right","center");
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("CreateLabel", mat.dataID[i][j], mat.data[i][j],
+ x + j*ChangeCoordinate2D.MATRIX_ELEM_WIDTH + ChangeCoordinate2D.MATRIX_ELEM_WIDTH / 2,
+ y + i*ChangeCoordinate2D.MATRIX_ELEM_HEIGHT + ChangeCoordinate2D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ return mat;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ChangeCoordinate2D(animManag, canvas.width, canvas.height);
+}
+
+function Matrix(contents, x, y)
+{
+ this.data = contents;
+ this.x = x;
+ this.y = y;
+}
+
+Matrix.prototype.transpose = function()
+{
+ var newData = new Array(this.data[0].length);
+ var i,j;
+ for (i = 0; i < this.data[0].length; i++)
+ {
+ newData[i] = new Array(this.data.length);
+ }
+ for (i = 0; i < this.data.length; i++)
+ {
+ for (j = 0; j < this.data[i].length; j++)
+ {
+ newData[j][i] = this.data[i][j];
+ }
+ }
+ this.data = newData;
+}
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ChangingCoordinate3D.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ChangingCoordinate3D.js
new file mode 100644
index 0000000..89c7226
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ChangingCoordinate3D.js
@@ -0,0 +1,1772 @@
+// 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
+
+
+
+function ChangeCoordinate3D(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+ChangeCoordinate3D.prototype = new Algorithm();
+ChangeCoordinate3D.prototype.constructor = ChangeCoordinate3D;
+ChangeCoordinate3D.superclass = Algorithm.prototype;
+
+ChangeCoordinate3D.XAxisYPos = 300;
+ChangeCoordinate3D.XAxisStart = 100;
+ChangeCoordinate3D.XAxisEnd = 700;
+
+ChangeCoordinate3D.MATRIX_ELEM_WIDTH = 40;
+ChangeCoordinate3D.MATRIX_ELEM_HEIGHT = 15;
+
+
+ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING = 5;
+ChangeCoordinate3D.EQUALS_SPACING = 20;
+
+ChangeCoordinate3D.ROBOT_MATRIX_START_X = 10 + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING;
+ChangeCoordinate3D.ROBOT_MATRIX_START_Y = 30;
+
+ChangeCoordinate3D.HAND_MATRIX_START_X = 10 +3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING;
+ChangeCoordinate3D.HAND_MATRIX_START_Y = 10 + 25 + 20 + 20 + 3*ChangeCoordinate3D.MATRIX_ELEM_HEIGHT;
+
+
+ChangeCoordinate3D.ROBOT_POSITION_START_X = ChangeCoordinate3D.ROBOT_MATRIX_START_X + 5*ChangeCoordinate3D.MATRIX_ELEM_WIDTH + 100;
+ChangeCoordinate3D.HAND_POSITION_START_X = ChangeCoordinate3D.HAND_MATRIX_START_X + 5*ChangeCoordinate3D.MATRIX_ELEM_WIDTH + 100;
+
+
+ChangeCoordinate3D.ROBOT_POSITION_START_Y = ChangeCoordinate3D.ROBOT_MATRIX_START_Y;
+ChangeCoordinate3D.HAND_POSITION_START_Y = ChangeCoordinate3D.HAND_MATRIX_START_Y;
+
+
+ChangeCoordinate3D.YAxisXPos = 400;
+ChangeCoordinate3D.YAxisStart = 100;
+ChangeCoordinate3D.YAxisEnd = 500;
+
+ChangeCoordinate3D.ROBOT_POINTS = [[-15,5,100],[15,5,100],[15, 5,80],[30,5,80],[30,5,-10],[15,5,-10], [15,5, -100], [0,5,-100],[0,5,-30],[0,5,-100], [-15,5, -100],
+ [-15,5,-10], [-30, 5,-10], [-30, 5, 80],[-15, 5, 80], [-15, 5, 100],
+
+ [-15,-5,100],[15,-5,100],[15, -5,80],[30,-5,80],[30,-5,-10],[15,-5,-10], [15,-5, -100], [0,-5,-100],[0,-5,-30],[0,-5,-100], [-15,-5, -100],
+ [-15,-5,-10], [-30, -5,-10], [-30, -5, 80],[-15, -5, 80], [-15, -5, 100]];
+
+ChangeCoordinate3D.ROBOT_EXTRA_CONNECTIONS = [[0, 16], [1, 17], [2, 18], [3, 19], [4, 20], [5, 21], [6, 22], [7, 23], [8, 24], [9, 25],
+ [10, 26], [11, 27], [12, 28], [13, 29], [14, 30], [15, 31]];
+
+
+
+ChangeCoordinate3D.HAND_POINTS = [[0,3, 0],[-10,3, 0],[-10,3, 10], [-6, 3,10], [-6, 3,6], [6, 3,6], [6, 3, 10], [10, 3, 10], [10, 3, 0],[0,3,0],
+ [0,-3, 0],[-10,-3, 0],[-10,-3, 10], [-6, -3,10], [-6, -3,6], [6, -3,6], [6, -3, 10], [10, -3, 10], [10, -3, 0],[0,-3,0]];
+
+
+
+ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS = [[0, 10], [1, 11], [2, 12], [3, 13], [4, 14], [5, 15], [6, 16], [7, 17], [8, 18], [9, 19]];
+
+
+ChangeCoordinate3D.ROBOT_HAND_ATTACH_POINT = [0, 0,40];
+
+
+ChangeCoordinate3D.M1 = [[Math.cos(3*Math.PI / 4), Math.sin(3*Math.PI/4), 0],[-Math.sin(3*Math.PI/4), Math.cos(3*Math.PI/4), 0],[0,0,1]];
+ChangeCoordinate3D.M2 = [[Math.cos(3*Math.PI / 4), 0, Math.sin(3*Math.PI/4)],[0,1,0], [-Math.sin(3*Math.PI/4), 0, Math.cos(3*Math.PI/4)]];
+ChangeCoordinate3D.M3 = [[1,0,0], [0, Math.cos(3*Math.PI / 4), Math.sin(3*Math.PI/4)],[0, -Math.sin(3*Math.PI/4), Math.cos(3*Math.PI/4)]];
+
+
+
+ChangeCoordinate3D.ROBOT_MATRIX_VALUES = [
+ [[1,0,0],[0, Math.cos(Math.PI / 6), Math.sin(Math.PI / 6)],[0, -Math.sin(Math.PI / 6), Math.cos(Math.PI / 6)]],
+ [[Math.cos(Math.PI / 4), Math.sin(Math.PI / 4), 0],[-Math.sin(Math.PI / 4), Math.cos(Math.PI / 4), 0], [0,0,1]],
+ [[Math.cos(0), Math.sin(0), 0],[-Math.sin(0), Math.cos(0), 0], [0, 0, 1]],
+ [[Math.cos(3*Math.PI / 4), Math.sin(3*Math.PI/4), 0],[-Math.sin(3*Math.PI/4), Math.cos(3*Math.PI/4), 0],[0,0,1]],
+ multiply(ChangeCoordinate3D.M2, ChangeCoordinate3D.M3)
+
+ ];
+
+
+ChangeCoordinate3D.ROBOT_POSITION_VALUES = [[75,0, 40], [200,100, 30],[100,100, 0], [100, 200, 0], [40,50,50]];
+
+
+ChangeCoordinate3D.HAND_MATRIX_VALUES = [
+ [[Math.cos(-Math.PI / 4),0, Math.sin(-Math.PI / 4)],[0,1,0],[-Math.sin(-Math.PI / 4), 0, Math.cos(-Math.PI / 4)]],
+ [[Math.cos(Math.PI / 4), Math.sin(Math.PI / 4), 0],[-Math.sin(Math.PI / 4), Math.cos(-Math.PI / 4), 0], [0,0,1]],
+ [[Math.cos(0), Math.sin(0), 0],[-Math.sin(0), Math.cos(0), 0], [0,0,1]],
+ [[Math.cos(Math.PI/2), Math.sin(Math.PI/2), 0],[-Math.sin(Math.PI/2), Math.cos(Math.PI/2), 0], [0,0,1]],
+ multiply(ChangeCoordinate3D.M1, ChangeCoordinate3D.M2)
+ ];
+
+
+ChangeCoordinate3D.HAND_POSITION_VALUES = [[80,0, 20],[30,90, 0],[100,100, 0],[-50, -20, 0], [50,10,20]];
+
+
+//ChangeCoordinate3D.ROBOT_POINTS = [[-20, 40], [20,40],[
+
+
+ChangeCoordinate3D.CAMERA_TRANS_ANGLE = toRadians(30);
+ChangeCoordinate3D.L = 0.5;
+
+ChangeCoordinate3D.CAMERA_TRANSFORM = [[1, 0, 0],
+ [ChangeCoordinate3D.L * Math.cos(ChangeCoordinate3D.CAMERA_TRANS_ANGLE), 0, ChangeCoordinate3D.L * Math.sin(ChangeCoordinate3D.CAMERA_TRANS_ANGLE)],
+ [0, 0, 1]];
+
+
+ChangeCoordinate3D.AXIS_CENTER = [[750,470],[750,150],[100, 550]];
+
+ChangeCoordinate3D.AXIS_COLOR_0 = "#990000"
+ChangeCoordinate3D.AXIS_COLOR_1 = "#009900"
+ChangeCoordinate3D.AXIS_COLOR_2 = "#000099"
+
+ChangeCoordinate3D.LOCAL_VERTEX_FOREGORUND_COLOR = "#000000";
+ChangeCoordinate3D.LOCAL_VERTEX_BACKGROUND_COLOR = ChangeCoordinate3D.LOCAL_VERTEX_FOREGORUND_COLOR;
+ChangeCoordinate3D.LOCAL_EDGE_COLOR = "#000000";
+
+ChangeCoordinate3D.GLOBAL_VERTEX_FOREGORUND_COLOR = "#00FF00";
+ChangeCoordinate3D.GLOBAL_VERTEX_BACKGROUND_COLOR = ChangeCoordinate3D.GLOBAL_VERTEX_FOREGORUND_COLOR;
+ChangeCoordinate3D.GLOBAL_EDGE_COLOR = "#00FF00";
+
+
+
+ChangeCoordinate3D.TRANSFORMED_VERTEX_FOREGORUND_COLOR = "#66FF66";
+ChangeCoordinate3D.TRANSFORMED_VERTEX_BACKGROUND_COLOR = ChangeCoordinate3D.VERTEX_FOREGORUND_COLOR;
+ChangeCoordinate3D.TRANSFORMED_EDGE_COLOR = "#66FF66";
+
+
+ChangeCoordinate3D.TRANSFORMED_POINT_COLORS = ["#990000", "#009900", "#000099"]
+
+
+ChangeCoordinate3D.VECTOR_COLOR = "#FF0000";
+
+ChangeCoordinate3D.VERTEX_WIDTH = 3;
+ChangeCoordinate3D.VERTEX_HEIGHT = ChangeCoordinate3D.VERTEX_WIDTH;
+
+ChangeCoordinate3D.prototype.init = function(am, w, h)
+{
+ var sc = ChangeCoordinate3D.superclass.init.call(this, am, w, h);
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.addControls();
+ this.currentShape = 0;
+
+ this.cameraTransform = ChangeCoordinate3D.CAMERA_TRANSFORM;
+
+ this.commands = [];
+ this.nextIndex = 0;
+
+ this.PositionIndex = 0;
+
+ this.RobotPositionValues = ChangeCoordinate3D.ROBOT_POSITION_VALUES[this.PositionIndex];
+ this.RobotMatrixValues = ChangeCoordinate3D.ROBOT_MATRIX_VALUES[this.PositionIndex];
+ this.HandPositionValues = ChangeCoordinate3D.HAND_POSITION_VALUES[this.PositionIndex];
+ this.HandMatrixValues = ChangeCoordinate3D.HAND_MATRIX_VALUES[this.PositionIndex];
+
+ this.setupAxis();
+
+ this.robotLabel1ID = this.nextIndex++;
+ this.handLabel1ID = this.nextIndex++;
+ this.robotLabel2ID = this.nextIndex++;
+ this.handLabel2ID = this.nextIndex++;
+
+ this.cmd("CreateLabel", this.robotLabel1ID, "Robot Space to World Space\n(Orientation)", ChangeCoordinate3D.ROBOT_MATRIX_START_X, ChangeCoordinate3D.ROBOT_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.robotLabel1ID, "#0000FF");
+
+ this.cmd("CreateLabel", this.robotLabel2ID, "Robot Space to World Space\n(Position)", ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.robotLabel2ID, "#0000FF");
+
+
+
+ this.RobotMatrix = this.createMatrix(this.RobotMatrixValues, ChangeCoordinate3D.ROBOT_MATRIX_START_X, ChangeCoordinate3D.ROBOT_MATRIX_START_Y);
+ this.resetMatrixLabels(this.RobotMatrix);
+ this.HandMatrix = this.createMatrix(this.HandMatrixValues, ChangeCoordinate3D.HAND_MATRIX_START_X, ChangeCoordinate3D.HAND_MATRIX_START_Y);
+ this.resetMatrixLabels(this.HandMatrix);
+
+ this.cmd("CreateLabel", this.handLabel1ID, "Hand Space to Robot Space\n(Orientation)", ChangeCoordinate3D.HAND_MATRIX_START_X, ChangeCoordinate3D.HAND_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.handLabel1ID, "#0000FF");
+
+ this.cmd("CreateLabel", this.handLabel2ID, "Hand Space to Robot Space\n(Position)", ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_MATRIX_START_Y - 25, 0);
+ this.cmd("SetForegroundColor", this.handLabel2ID, "#0000FF");
+
+
+
+ this.RobotPosition = this.createMatrix([this.RobotPositionValues], ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y);
+ this.resetMatrixLabels(this.RobotMatrix);
+ this.HandPosition = this.createMatrix([this.HandPositionValues], ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y);
+ this.resetMatrixLabels(this.HandMatrix);
+
+
+ var i;
+ this.RobotPointWorldIDs = new Array(ChangeCoordinate3D.ROBOT_POINTS.length);
+ this.RobotPointRobotIDs = new Array(ChangeCoordinate3D.ROBOT_POINTS.length);
+ this.HandPointWorldIDs = new Array(ChangeCoordinate3D.HAND_POINTS.length);
+ this.HandPointRobotIDs = new Array(ChangeCoordinate3D.HAND_POINTS.length);
+ this.HandPointHandIDs = new Array(ChangeCoordinate3D.HAND_POINTS.length);
+ this.RobotHandAttachRobotID = this.nextIndex++;
+ this.RobotHandAttachWorldID = this.nextIndex++;
+ for (i = 0; i < ChangeCoordinate3D.ROBOT_POINTS.length; i++)
+ {
+ this.RobotPointWorldIDs[i] = this.nextIndex++;
+ this.RobotPointRobotIDs[i] = this.nextIndex++;
+ }
+ for (i = 0; i < ChangeCoordinate3D.HAND_POINTS.length; i++)
+ {
+ this.HandPointWorldIDs[i] = this.nextIndex++;
+ this.HandPointRobotIDs[i] = this.nextIndex++;
+ this.HandPointHandIDs[i] = this.nextIndex++;
+ }
+
+ this.savedNextIndex = this.nextIndex;
+ this.setupObjects();
+ this.setupObjectGraphic();
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.clearHistory();
+ this.animationManager.setAllLayers([0, 1]);
+ this.lastLocalToGlobal = true;
+ this.oldIDs = [];
+
+
+}
+
+ChangeCoordinate3D.prototype.addAxis = function(origin, x1, x2, y1, y2, z1, z2, color)
+{
+ var idArray = [];
+ var originID = this.nextIndex++;
+ idArray.push(originID);
+ this.cmd("CreateRectangle", originID, "", 0, 0, origin[0], origin[1]);
+ this.cmd("SetAlpha", originID, 0);
+
+ var axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, x1[0], x1[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, x2[0], x2[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, y1[0], y1[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, y2[0], y2[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, z1[0], z1[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+ axisID = this.nextIndex++;
+ this.cmd("CreateRectangle", axisID, "", 0, 0, z2[0], z2[1]);
+ this.cmd("SetAlpha", axisID, 0);
+ this.cmd("Connect", originID, axisID, color, 0, 1, "");
+ idArray.push(axisID);
+
+
+
+ var labelID = this.nextIndex++;
+ this.cmd("CreateLabel", labelID, "+y", y2[0] - 10, y2[1] + 10);
+ this.cmd("SetForegroundColor", labelID, color);
+ idArray.push(labelID);
+
+
+ labelID = this.nextIndex++;
+ this.cmd("CreateLabel", labelID, "+x", x2[0] - 10, x2[1] + 10);
+ this.cmd("SetForegroundColor", labelID, color);
+ idArray.push(labelID);
+
+
+ labelID = this.nextIndex++;
+ this.cmd("CreateLabel", labelID, "+z", z2[0] - 10, z2[1] + 10);
+ this.cmd("SetForegroundColor", labelID, color);
+ idArray.push(labelID);
+
+
+ return idArray;
+}
+
+
+ChangeCoordinate3D.prototype.transformPoint = function(point, matrix, position)
+{
+ return this.add(multiply([point], matrix), [position])[0];
+}
+
+
+ChangeCoordinate3D.prototype.setupExtraAxes = function()
+{
+ var robotOrigin = this.RobotPositionValues;
+ var x1 = this.transformPoint([-150, 0, 0], this.RobotMatrixValues, this.RobotPositionValues);
+ var x2 = this.transformPoint([150, 0, 0], this.RobotMatrixValues, this.RobotPositionValues);
+ var y1 = this.transformPoint([0, -150, 0], this.RobotMatrixValues, this.RobotPositionValues);
+ var y2 = this.transformPoint([0, 150, 0], this.RobotMatrixValues, this.RobotPositionValues);
+ var z1 = this.transformPoint([0, 0, -150], this.RobotMatrixValues, this.RobotPositionValues);
+ var z2 = this.transformPoint([0, 0, 150], this.RobotMatrixValues, this.RobotPositionValues);
+
+ this.otherAxes = [];
+
+ var tmpAxis = this.addAxis(this.worldToScreenSpace(robotOrigin, 2),
+ this.worldToScreenSpace(x1, 2),
+ this.worldToScreenSpace(x2, 2),
+ this.worldToScreenSpace(y1, 2),
+ this.worldToScreenSpace(y2, 2),
+ this.worldToScreenSpace(z1, 2),
+ this.worldToScreenSpace(z2, 2),
+ ChangeCoordinate3D.AXIS_COLOR_1);
+
+ this.otherAxes.push(tmpAxis);
+
+ for (var i = 0; i < tmpAxis.length; i++)
+ {
+ this.cmd("SetLayer", tmpAxis[i], 1);
+ }
+ this.setAxisAlpha(tmpAxis, 0.5);
+
+
+ var handOrigin = this.HandPositionValues;
+ x1 = this.transformPoint([-150, 0, 0], this.HandMatrixValues, this.HandPositionValues);
+ x2 = this.transformPoint([150, 0, 0], this.HandMatrixValues, this.HandPositionValues);
+ y1 = this.transformPoint([0, -150, 0], this.HandMatrixValues, this.HandPositionValues);
+ y2 = this.transformPoint([0, 150, 0], this.HandMatrixValues, this.HandPositionValues);
+ z1 = this.transformPoint([0, 0, -150], this.HandMatrixValues, this.HandPositionValues);
+ z2 = this.transformPoint([0, 0, 150], this.HandMatrixValues, this.HandPositionValues);
+
+
+ tmpAxis = this.addAxis(this.worldToScreenSpace(handOrigin, 1),
+ this.worldToScreenSpace(x1, 1),
+ this.worldToScreenSpace(x2, 1),
+ this.worldToScreenSpace(y1, 1),
+ this.worldToScreenSpace(y2, 1),
+ this.worldToScreenSpace(z1, 1),
+ this.worldToScreenSpace(z2, 1),
+ ChangeCoordinate3D.AXIS_COLOR_0);
+
+ for (var i = 0; i < tmpAxis.length; i++)
+ {
+ this.cmd("SetLayer", tmpAxis[i], 1);
+ }
+ this.setAxisAlpha(tmpAxis, 0.5);
+
+
+ this.otherAxes.push(tmpAxis);
+
+
+ handOrigin = this.transformPoint(handOrigin, this.RobotMatrixValues, this.RobotPositionValues);
+ x1 = this.transformPoint(x1, this.RobotMatrixValues, this.RobotPositionValues);
+ x2 = this.transformPoint(x2, this.RobotMatrixValues, this.RobotPositionValues);
+ y1 = this.transformPoint(y1, this.RobotMatrixValues, this.RobotPositionValues);
+ y2 = this.transformPoint(y2, this.RobotMatrixValues, this.RobotPositionValues);
+ z1 = this.transformPoint(z1, this.RobotMatrixValues, this.RobotPositionValues);
+ z2 = this.transformPoint(z2, this.RobotMatrixValues, this.RobotPositionValues);
+
+
+ tmpAxis = this.addAxis(this.worldToScreenSpace(handOrigin, 2),
+ this.worldToScreenSpace(x1, 2),
+ this.worldToScreenSpace(x2, 2),
+ this.worldToScreenSpace(y1, 2),
+ this.worldToScreenSpace(y2, 2),
+ this.worldToScreenSpace(z1, 2),
+ this.worldToScreenSpace(z2, 2),
+ ChangeCoordinate3D.AXIS_COLOR_0);
+ for (var i = 0; i < tmpAxis.length; i++)
+ {
+ this.cmd("SetLayer", tmpAxis[i], 1);
+ }
+
+ this.setAxisAlpha(tmpAxis, 0.5);
+
+ this.otherAxes.push(tmpAxis);
+
+}
+
+
+ChangeCoordinate3D.prototype.setupAxis = function()
+{
+
+ this.axisHand = this.addAxis(this.worldToScreenSpace([0,0,0], 0),
+ this.worldToScreenSpace([-150, 0, 0], 0),
+ this.worldToScreenSpace([150,0, 0], 0),
+ this.worldToScreenSpace([0, -150, 0], 0),
+ this.worldToScreenSpace([0, 150, 0], 0),
+ this.worldToScreenSpace([0, 0, -150], 0),
+ this.worldToScreenSpace([0, 0, 150], 0),
+ ChangeCoordinate3D.AXIS_COLOR_0);
+ this.setAxisAlpha(this.axisHand, 0.5);
+
+ this.axisRobot = this.addAxis(this.worldToScreenSpace([0,0, 0], 1),
+ this.worldToScreenSpace([-150, 0, 0], 1),
+ this.worldToScreenSpace([150,0, 0], 1),
+ this.worldToScreenSpace([0, -150, 0], 1),
+ this.worldToScreenSpace([0, 150, 0], 1),
+ this.worldToScreenSpace([0, 0, -150], 1),
+ this.worldToScreenSpace([0, 0, 150], 1),
+ ChangeCoordinate3D.AXIS_COLOR_1);
+ this.setAxisAlpha(this.axisRobot, 0.5);
+
+ this.axisWorld = this.addAxis(this.worldToScreenSpace([0,0, 0], 2),
+ this.worldToScreenSpace([-50, 0, 0], 2),
+ this.worldToScreenSpace([400,0, 0], 2),
+ this.worldToScreenSpace([0, -50, 0], 2),
+ this.worldToScreenSpace([0, 400, 0], 2),
+ this.worldToScreenSpace([0, 0, -50], 2),
+ this.worldToScreenSpace([0, 0, 400], 2),
+ ChangeCoordinate3D.AXIS_COLOR_2);
+ this.setAxisAlpha(this.axisWorld, 0.5);
+
+ this.setupExtraAxes();
+
+
+
+
+
+}
+
+
+ChangeCoordinate3D.prototype.setAxisAlpha = function(axisList, newAlpha)
+{
+ for (var i = 0; i < axisList.length; i++)
+ {
+ this.cmd("SetAlpha", axisList[i], newAlpha);
+ if (i > 0)
+ {
+ this.cmd("SetEdgeAlpha", axisList[0], axisList[i], newAlpha);
+ }
+ }
+
+}
+
+ChangeCoordinate3D.prototype.setupObjects = function()
+{
+
+ var i;
+ for (i = 0; i < ChangeCoordinate3D.ROBOT_POINTS.length; i++)
+ {
+
+
+ var point = this.worldToScreenSpace(ChangeCoordinate3D.ROBOT_POINTS[i], 1);
+ this.cmd("CreateRectangle", this.RobotPointRobotIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.RobotPointRobotIDs[i-1], this.RobotPointRobotIDs[i], "#000000", 0, 0);
+ }
+
+ point = this.transformPoint(ChangeCoordinate3D.ROBOT_POINTS[i], this.RobotMatrixValues, this.RobotPositionValues);
+ point = this.worldToScreenSpace(point, 2);
+
+ this.cmd("CreateRectangle", this.RobotPointWorldIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.RobotPointWorldIDs[i-1], this.RobotPointWorldIDs[i], "#000000", 0, 0);
+ }
+ }
+
+ for (var i = 0; i < ChangeCoordinate3D.ROBOT_EXTRA_CONNECTIONS.length; i++)
+ {
+ this.cmd("Connect", this.RobotPointRobotIDs[ChangeCoordinate3D.ROBOT_EXTRA_CONNECTIONS[i][0]], this.RobotPointRobotIDs[ChangeCoordinate3D.ROBOT_EXTRA_CONNECTIONS[i][1]], "#000000", 0, 0, "");
+ this.cmd("Connect", this.RobotPointWorldIDs[ChangeCoordinate3D.ROBOT_EXTRA_CONNECTIONS[i][0]], this.RobotPointWorldIDs[ChangeCoordinate3D.ROBOT_EXTRA_CONNECTIONS[i][1]], "#000000", 0, 0, "");
+ }
+
+
+
+ for (i = 0; i < ChangeCoordinate3D.HAND_POINTS.length; i++)
+ {
+
+
+ var point = this.worldToScreenSpace(ChangeCoordinate3D.HAND_POINTS[i], 0);
+ this.cmd("CreateRectangle", this.HandPointHandIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.HandPointHandIDs[i-1], this.HandPointHandIDs[i], "#000000", 0, 0);
+ }
+
+ point = this.transformPoint(ChangeCoordinate3D.HAND_POINTS[i], this.HandMatrixValues, this.HandPositionValues);
+ var point2 = this.worldToScreenSpace(point, 1);
+
+ this.cmd("CreateRectangle", this.HandPointRobotIDs[i], "", 0, 0, point2[0], point2[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.HandPointRobotIDs[i-1], this.HandPointRobotIDs[i], "#000000", 0, 0);
+ }
+
+ point = this.transformPoint(point, this.RobotMatrixValues, this.RobotPositionValues);
+ point = this.worldToScreenSpace(point,2);
+
+ this.cmd("CreateRectangle", this.HandPointWorldIDs[i], "", 0, 0, point[0], point[1]);
+ if (i > 0)
+ {
+ this.cmd("Connect", this.HandPointWorldIDs[i-1], this.HandPointWorldIDs[i], "#000000", 0, 0);
+ }
+ }
+ for (var i = 0; i < ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS.length; i++)
+ {
+ this.cmd("Connect", this.HandPointHandIDs[ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS[i][0]], this.HandPointHandIDs[ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS[i][1]], "#000000", 0, 0, "");
+ this.cmd("Connect", this.HandPointRobotIDs[ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS[i][0]], this.HandPointRobotIDs[ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS[i][1]], "#000000", 0, 0, "");
+ this.cmd("Connect", this.HandPointWorldIDs[ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS[i][0]], this.HandPointWorldIDs[ChangeCoordinate3D.HAND_EXTRA_CONNECTIONS[i][1]], "#000000", 0, 0, "");
+ }
+
+
+
+ point = this.worldToScreenSpace(ChangeCoordinate3D.ROBOT_HAND_ATTACH_POINT, 1);
+ this.cmd("CreateRectangle", this.RobotHandAttachRobotID, "", 0, 0, point[0], point[1]);
+ this.cmd("Connect", this.RobotHandAttachRobotID, this.HandPointRobotIDs[0], "#000000", 0, 0);
+
+ point = this.transformPoint(ChangeCoordinate3D.ROBOT_HAND_ATTACH_POINT, this.RobotMatrixValues, this.RobotPositionValues);
+ point = this.worldToScreenSpace(point, 2);
+ this.cmd("CreateRectangle", this.RobotHandAttachWorldID, "", 0, 0, point[0], point[1]);
+ this.cmd("Connect", this.RobotHandAttachWorldID, this.HandPointWorldIDs[0], "#000000", 0, 0);
+}
+
+
+
+ChangeCoordinate3D.prototype.worldToScreenSpace = function(point, space)
+{
+ var transformedPoint = multiply([point], this.cameraTransform)[0];
+ var worldSpace = new Array(2);
+ worldSpace[0] = transformedPoint[0] + ChangeCoordinate3D.AXIS_CENTER[space][0];
+ worldSpace[1] = ChangeCoordinate3D.AXIS_CENTER[space][1] - transformedPoint[2];
+
+ return worldSpace;
+}
+
+
+
+
+ChangeCoordinate3D.prototype.removeOldIDs = function()
+{
+ var i;
+ for (i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs = [];
+}
+
+
+
+ChangeCoordinate3D.prototype.setupObjectGraphic = function()
+{
+ var i;
+
+
+
+
+}
+
+ChangeCoordinate3D.prototype.addControls = function()
+{
+ this.controls = [];
+
+ addLabelToAlgorithmBar("x");
+
+ this.xField = addControlToAlgorithmBar("Text", "");
+ this.xField.onkeydown = this.returnSubmitFloat(this.xField, this.transformPointCallback.bind(this), 4, true);
+ this.controls.push(this.xField);
+
+ addLabelToAlgorithmBar("y");
+
+ this.yField = addControlToAlgorithmBar("Text", "");
+ this.yField.onkeydown = this.returnSubmitFloat(this.yField, this.transformPointCallback.bind(this), 4, true);
+ this.controls.push(this.yField);
+
+
+ addLabelToAlgorithmBar("z");
+
+ this.zField = addControlToAlgorithmBar("Text", "");
+ this.zField.onkeydown = this.returnSubmitFloat(this.zField, this.transformPointCallback.bind(this), 4, true);
+ this.controls.push(this.zField);
+
+
+ var transformButton = addControlToAlgorithmBar("Button", "Transform Point");
+ transformButton.onclick = this.transformPointCallback.bind(this);
+ this.controls.push(transformButton);
+
+
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Hand Space -> World Space",
+ "World Space -> Hand Space",
+ ],
+ "Transform Type");
+ this.handToWorldButton = radioButtonList[0];
+ this.handToWorldButton.onclick = this.transformTypeChangedCallback.bind(this, false);
+ this.controls.push(this.handToWorldButton);
+
+
+ this.worldToHandButton = radioButtonList[1];
+ this.worldToHandButton.onclick = this.transformTypeChangedCallback.bind(this, true);
+ this.controls.push(this.worldToHandButton);
+
+ this.worldToHandButton.checked = this.lastLocalToGlobal;
+ this.handToWorldButton.checked = !this.lastLocalToGlobal;
+
+
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Row Major",
+ "Column Major",
+ ],
+ "RankType");
+ this.rowMajorButton = radioButtonList[0];
+ this.rowMajorButton.onclick = this.changeRowColMajorCallback.bind(this, true);
+ this.controls.push(this.rowMajorButton);
+
+ this.colMajorButton = radioButtonList[1];
+ this.colMajorButton.onclick = this.changeRowColMajorCallback.bind(this, false);
+ this.controls.push(this.colMajorButton);
+
+ this.rowMajorButton.checked = this.rowMajor;
+ this.colMajorButton.checked = !this.rowMajor;
+
+
+ this.showAxisBox = addCheckboxToAlgorithmBar("Show all axes");
+ this.showAxisBox.onclick = this.showAllAxesCallback.bind(this);
+ this.showAxisBox.checked = true;
+
+ //this.controls.push(this.showAxisBox);
+
+
+
+ var moveObjectsButton = addControlToAlgorithmBar("Button", "Move Objects");
+ moveObjectsButton.onclick = this.moveObjectsCallback.bind(this);
+
+ this.controls.push(moveObjectsButton);
+
+}
+
+
+
+ChangeCoordinate3D.prototype.showAllAxesCallback = function()
+{
+ if (this.showAxisBox.checked)
+ {
+ this.animationManager.setAllLayers([0,1]);
+ }
+ else
+ {
+ this.animationManager.setAllLayers([0]);
+ }
+
+
+}
+
+
+ChangeCoordinate3D.prototype.reset = function()
+{
+ this.rowMajor = true;
+ this.rowMajorButton.checked = this.rowMajor;
+ this.nextIndex = this.savedNextIndex;
+}
+
+
+ChangeCoordinate3D.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+ChangeCoordinate3D.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+ChangeCoordinate3D.prototype.transformTypeChangedCallback = function(globalToLocal)
+{
+ if (this.lastLocalToGlobal == globalToLocal)
+ {
+ this.implementAction(this.changeTransformType.bind(this,globalToLocal));
+ }
+}
+
+
+
+
+ChangeCoordinate3D.prototype.changeRowColMajorCallback = function(rowMajor)
+{
+ if (this.rowMajor != rowMajor)
+ {
+ this.implementAction(this.changeRowCol.bind(this), rowMajor);
+ }
+}
+
+ChangeCoordinate3D.prototype.transposeVisual = function(matrix)
+{
+ if (matrix.data.length == matrix.data[0].length)
+ {
+ var matrixSize = matrix.data.length;
+ var i, j, tmp, moveLabel1, moveLabel2;
+ var moveLabels = [];
+ for (i = 1; i < matrixSize; i++)
+ {
+ for (j = 0; j <= i; j++)
+ {
+ this.cmd("SetText", matrix.dataID[i][j], "");
+ this.cmd("SetText", matrix.dataID[j][i], "");
+ moveLabel1 = this.nextIndex++;
+ moveLabel2 = this.nextIndex++;
+ moveLabels.push(moveLabel1);
+ moveLabels.push(moveLabel2);
+ this.cmd("CreateLabel", moveLabel1,
+ this.standardize(matrix.data[i][j]), matrix.x + ChangeCoordinate3D.MATRIX_ELEM_WIDTH / 2+ i * ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2+ j * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT);
+ this.cmd("CreateLabel", moveLabel2,
+ this.standardize(matrix.data[j][i]), matrix.x + ChangeCoordinate3D.MATRIX_ELEM_WIDTH / 2+ j * ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2 + i * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT);
+ this.cmd("Move", moveLabel1, matrix.x + ChangeCoordinate3D.MATRIX_ELEM_WIDTH / 2+ j * ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2 + i * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT);
+ this.cmd("Move", moveLabel2, matrix.x + ChangeCoordinate3D.MATRIX_ELEM_WIDTH / 2+ i * ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ matrix.y + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2 + j * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT);
+ tmp = matrix.data[i][j];
+ matrix.data[i][j] = matrix.data[j][i];
+ matrix.data[j][i] = tmp;
+ }
+ }
+ this.cmd("Step");
+ for (i = 0; i < moveLabels.length; i++)
+ {
+ this.cmd("Delete", moveLabels[i]);
+ }
+ this.resetMatrixLabels(matrix);
+ return matrix;
+ }
+ else
+ {
+ var savedData = matrix.data;
+ var newData = new Array(savedData[0].length);
+ var i,j;
+ for (i = 0; i < savedData[0].length; i++)
+ {
+ newData[i] = [];
+ }
+ for (i = 0; i < savedData.length; i++)
+ {
+ for (j = 0; j < savedData[0].length; j++)
+ {
+ newData[j][i] = savedData[i][j];
+ }
+
+ }
+ var newMatrix = this.createMatrix(newData, matrix.x, matrix.y);
+ this.deleteMatrix(matrix);
+ return newMatrix;
+ }
+}
+
+ChangeCoordinate3D.prototype.changeRowCol = function(rowMajor)
+{
+ this.commands = new Array();
+ this.rowMajor= rowMajor;
+ if (this.rowMajorButton.checked != this.rowMajor)
+ {
+ this.rowMajorButton.checked = this.rowMajor;
+ }
+ if (this.colMajorButton.checked == this.rowMajor)
+ {
+ this.colMajorButton.checked = !this.rowMajor;
+ }
+ this.removeOldIDs();
+ this.RobotMatrix = this.transposeVisual(this.RobotMatrix);
+ this.RobotPosition = this.transposeVisual(this.RobotPosition);
+ this.HandMatrix = this.transposeVisual(this.HandMatrix);
+ this.HandPosition = this.transposeVisual(this.HandPosition);
+
+
+ return this.commands;
+}
+
+
+ChangeCoordinate3D.prototype.fixNumber = function(value, defaultVal)
+{
+ if (value == "" || value == "-" || value == "." || value == "-." || isNaN(parseFloat(value)))
+ {
+ value = defaultVal;
+ }
+ else
+ {
+ value = String(parseFloat(value));
+ }
+ return value
+}
+
+ChangeCoordinate3D.prototype.transformPointCallback = function()
+{
+
+
+ this.xField.value = this.fixNumber(this.xField.value, "0");
+ this.yField.value = this.fixNumber(this.yField.value, "0");
+ this.zField.value = this.fixNumber(this.zField.value, "0");
+ this.implementAction(this.doPointTransform.bind(this), this.xField.value + ";" + this.yField.value + ";" + this.zField.value);
+
+}
+
+
+ChangeCoordinate3D.prototype.doPointTransform = function(params)
+{
+ if (this.lastLocalToGlobal)
+ {
+ return this.localToGlobal(params);
+ }
+ else
+ {
+ return this.globalToLocal(params);
+ }
+}
+
+
+
+
+
+ChangeCoordinate3D.prototype.rotatePoint = function(point, matrix, xPos, yPos, fromSpace, toSpace)
+{
+ var logicalPoint;
+ var descriptLabel = this.nextIndex++;
+ // this.oldIDs.push(descriptLabel);
+ if (this.rowMajor)
+ {
+ this.cmd("CreateLabel", descriptLabel, "", xPos + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING,
+ yPos + 2*ChangeCoordinate3D.MATRIX_ELEM_HEIGHT + 3, 0);
+ }
+ else
+ {
+ this.cmd("CreateLabel", descriptLabel, "", xPos + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING,
+ yPos + 3*ChangeCoordinate3D.MATRIX_ELEM_HEIGHT + 3, 0);
+
+ }
+
+ var inertialPositionMatrix;
+
+ if (this.rowMajor)
+ {
+ inertialPositionMatrix = this.createMatrix([["", "", ""]], xPos + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING,
+ yPos);
+ }
+ else
+ {
+ inertialPositionMatrix = this.createMatrix([[""], [""], [""]],
+ xPos + 4 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING,
+ yPos);
+
+ }
+ var equalLabel1 = this.nextIndex++;
+ this.oldIDs.push(equalLabel1);
+ if (this.rowMajor)
+ {
+ opX = xPos + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING / 2;
+ opY = yPos + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2;
+ }
+ else
+ {
+ opX = xPos + 4 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING / 2 + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING;
+ opY = yPos + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT;
+
+
+ }
+
+ this.cmd("CreateLabel", equalLabel1, "=", opX , opY);
+ if (this.rowMajor)
+ {
+ this.multiplyMatrix(point, matrix, inertialPositionMatrix, descriptLabel, 2);
+
+ }
+ else
+ {
+ this.multiplyMatrix(matrix, point, inertialPositionMatrix, descriptLabel, 2);
+
+ }
+ this.addMatrixIDsToList(inertialPositionMatrix, this.oldIDs);
+ this.cmd("Delete", descriptLabel);
+ var inertialPositionID = this.nextIndex++;
+ if (this.rowMajor)
+ {
+ logicalPoint = inertialPositionMatrix.data[0].slice(0);
+
+ }
+ else
+ {
+ logicalPoint = [inertialPositionMatrix.data[0][0], inertialPositionMatrix.data[1][0], inertialPositionMatrix.data[2][0]];
+ }
+ screenPoint = this.worldToScreenSpace(logicalPoint, fromSpace);
+
+
+ this.cmd("CreateCircle", inertialPositionID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", inertialPositionID, ChangeCoordinate3D.VERTEX_WIDTH);
+
+ var originID = this.nextIndex++;
+ this.oldIDs.push(originID);
+ var origin = this.worldToScreenSpace([0,0,0], fromSpace);
+
+
+ this.cmd("CreateRectangle", originID, "", 0, 0, origin[0], origin[1]);
+
+ this.cmd("Connect", originID, inertialPositionID, ChangeCoordinate3D.TRANSFORMED_POINT_COLORS[toSpace], 0, 1, "");
+
+
+ return [inertialPositionMatrix, inertialPositionID, originID];
+}
+
+ChangeCoordinate3D.prototype.translatePoint = function(point, transVector, xPos, yPos, fromSpace, toSpace, pointID)
+{
+ var logicalPoint = new Array(2);
+ var robotPositionMatrix;
+ if (this.rowMajor)
+ {
+ logicalPoint[0] = point.data[0][0] + transVector.data[0][0];
+ logicalPoint[1] = point.data[0][1] + transVector.data[0][1];
+ logicalPoint[2] = point.data[0][2] + transVector.data[0][2];
+ robotPositionMatrix = this.createMatrix([["", "", ""]], xPos + 3*ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING,
+ yPos);
+ }
+ else
+ {
+ logicalPoint[0] = point.data[0][0] + transVector.data[0][0];
+ logicalPoint[1] = point.data[1][0] + transVector.data[1][0];
+ logicalPoint[2] = point.data[2][0] + transVector.data[2][0];
+ robotPositionMatrix = this.createMatrix([[""],[""], [""]], xPos + ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING,
+ yPos);
+
+ }
+
+ var addLabel1 = this.nextIndex++;
+ var equalLabel3 = this.nextIndex++;
+ this.oldIDs.push(addLabel1);
+ this.oldIDs.push(equalLabel3);
+ var op2X, op2Y;
+ if (this.rowMajor)
+ {
+ opX = xPos + 3*ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING / 2;
+ opY = yPos + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2;
+ op2X = xPos - ChangeCoordinate3D.EQUALS_SPACING / 2;
+ op2Y = yPos + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2;
+
+ }
+ else
+ {
+ opX = xPos + ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.EQUALS_SPACING / 2;
+ opY = yPos + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT;
+ op2X = xPos - ChangeCoordinate3D.EQUALS_SPACING / 2;
+ op2Y = yPos + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT;
+
+
+ }
+ this.cmd("CreateLabel", equalLabel3, "=",opX , opY);
+ this.cmd("CreateLabel", addLabel1, "+",op2X , op2Y);
+
+
+
+
+ this.addMatrix(point, transVector, robotPositionMatrix, 2);
+ this.addMatrixIDsToList(robotPositionMatrix, this.oldIDs);
+
+ var screenPoint = this.worldToScreenSpace(logicalPoint, fromSpace);
+
+ var robotPositionID = this.nextIndex++;
+
+ this.cmd("CreateCircle", robotPositionID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", robotPositionID, ChangeCoordinate3D.VERTEX_WIDTH);
+
+
+ this.cmd("Connect",pointID, robotPositionID, ChangeCoordinate3D.TRANSFORMED_POINT_COLORS[toSpace], 0, 1, "");
+ this.cmd("Step")
+
+
+
+ var originID = this.nextIndex++;
+ this.oldIDs.push(originID);
+ var origin = this.worldToScreenSpace([0,0, 0], fromSpace);
+
+ this.cmd("CreateCircle", originID, "", origin[0], origin[1]);
+ this.cmd("SetWidth", originID, 0);
+ this.cmd("SetAlpha", originID, 0);
+
+ this.cmd("Connect",originID, robotPositionID, ChangeCoordinate3D.TRANSFORMED_POINT_COLORS[toSpace], 0, 1, "");
+
+ return [robotPositionMatrix, robotPositionID, originID];
+
+
+}
+
+
+ChangeCoordinate3D.prototype.addMultiply = function(position, transVector, rotMatrix, transX, transY, rotX, rotY, initialPointID, fromSpace, toSpace)
+{
+
+ var posMatrixAndPointID = this.translatePoint(position, transVector, transX, transY, fromSpace, toSpace, initialPointID);
+ var newPosition = posMatrixAndPointID[0];
+ var pointID = posMatrixAndPointID[1];
+ var originID = posMatrixAndPointID[2];
+
+ this.cmd("Step");
+
+ this.cmd("Disconnect", initialPointID, pointID);
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(newPosition, rotX - 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH - ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING,transY)
+ }
+ else
+ {
+ this.moveMatrix(newPosition, rotX + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING, transY)
+ }
+
+
+ var posMatrixAndPointID = this.rotatePoint(newPosition, rotMatrix, rotX, rotY, fromSpace, toSpace);
+ this.cmd("Delete", pointID);
+ this.cmd("Step");
+
+ var robotPositionMatrix = posMatrixAndPointID[0];
+ var robotPositionID = posMatrixAndPointID[1];
+ var movingOriginID = posMatrixAndPointID[2];
+
+ var origin = this.worldToScreenSpace([0,0, 0], toSpace);
+ this.cmd("Move", movingOriginID, origin[0], origin[1]);
+
+
+ var logicalPoint;
+ if (this.rowMajor)
+ {
+ logicalPoint = robotPositionMatrix.data[0].slice(0);
+
+ }
+ else
+ {
+ logicalPoint = [robotPositionMatrix.data[0][0], robotPositionMatrix.data[1][0], robotPositionMatrix.data[2][0]];
+ }
+
+
+
+
+ var screenPoint = this.worldToScreenSpace(logicalPoint, toSpace);
+ this.cmd("Move", robotPositionID, screenPoint[0], screenPoint[1]);
+
+ this.cmd("Step");
+
+
+ this.oldIDs.push(robotPositionID);
+
+
+ return [robotPositionMatrix, robotPositionID ];
+}
+
+
+ChangeCoordinate3D.prototype.multiplyAdd = function(position, rotMatrix, transVector, rotX, rotY, transX, transY, fromSpace, toSpace)
+{
+ var posMatrixAndPointID = this.rotatePoint(position, rotMatrix, rotX, rotY, fromSpace, toSpace);
+ var inertialPositionMatrix = posMatrixAndPointID[0];
+ var inertialPositionID = posMatrixAndPointID[1];
+
+
+ this.cmd("Step");
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(inertialPositionMatrix, transX - 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH - ChangeCoordinate3D.EQUALS_SPACING,transY)
+ }
+ else
+ {
+ this.moveMatrix(inertialPositionMatrix, transX - ChangeCoordinate3D.MATRIX_ELEM_WIDTH - ChangeCoordinate3D.EQUALS_SPACING, transY)
+ }
+
+
+ posMatrixAndPointID = this.translatePoint(inertialPositionMatrix, transVector, transX, transY, fromSpace, toSpace, inertialPositionID);
+ var robotPositionMatrix = posMatrixAndPointID[0];
+ var robotPositionID = posMatrixAndPointID[1];
+ var movingOriginID = posMatrixAndPointID[2];
+
+ this.oldIDs.push(robotPositionID);
+
+ var logicalPoint;
+ if (this.rowMajor)
+ {
+ logicalPoint = robotPositionMatrix.data[0].slice(0);
+
+ }
+ else
+ {
+ logicalPoint = [robotPositionMatrix.data[0][0], robotPositionMatrix.data[1][0], robotPositionMatrix.data[2][0]];
+ }
+
+
+ this.cmd("Step");
+
+ this.cmd("Delete", inertialPositionID);
+ origin = this.worldToScreenSpace([0,0, 0], toSpace);
+ this.cmd("Move", movingOriginID, origin[0], origin[1]);
+ screenPoint = this.worldToScreenSpace(logicalPoint, toSpace);
+ this.cmd("Move", robotPositionID, screenPoint[0], screenPoint[1]);
+
+ this.cmd("Step");
+ return robotPositionMatrix;
+
+}
+
+ChangeCoordinate3D.prototype.localToGlobal = function (params)
+{
+ this.commands = [];
+ this.removeOldIDs();
+
+
+ var paramList = params.split(";");
+ var x = parseFloat(paramList[0]);
+ var y = parseFloat(paramList[1]);
+ var z = parseFloat(paramList[2]);
+
+ var opX, opY;
+
+
+ var screenPoint = this.worldToScreenSpace([x,y,z], 0);
+ var logicalPoint;
+
+ var pointInHandSpaceID = this.nextIndex++;
+ this.oldIDs.push(pointInHandSpaceID);
+
+ this.cmd("CreateCircle", pointInHandSpaceID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", pointInHandSpaceID, ChangeCoordinate3D.VERTEX_WIDTH);
+
+ this.cmd("Connect", this.axisHand[0], pointInHandSpaceID, ChangeCoordinate3D.TRANSFORMED_POINT_COLORS[0], 0, 1, "");
+
+ var initialPointMatrix;
+ if (this.rowMajor)
+ {
+ initialPointMatrix = this.createMatrix([[x, y, z]], ChangeCoordinate3D.HAND_MATRIX_START_X - 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH - ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate3D.HAND_MATRIX_START_Y);
+ }
+ else
+ {
+ initialPointMatrix = this.createMatrix([[x], [y], [z]], ChangeCoordinate3D.HAND_MATRIX_START_X + 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate3D.HAND_MATRIX_START_Y);
+
+ }
+ this.addMatrixIDsToList(initialPointMatrix, this.oldIDs);
+ this.cmd("Step");
+
+ var robotPositionMatrix = this.multiplyAdd(initialPointMatrix, this.HandMatrix, this.HandPosition,
+ ChangeCoordinate3D.HAND_MATRIX_START_X, ChangeCoordinate3D.HAND_MATRIX_START_Y,
+ ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y,
+ 0, 1);
+
+
+
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate3D.ROBOT_MATRIX_START_X - 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH - ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate3D.ROBOT_MATRIX_START_Y);
+ }
+ else
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate3D.ROBOT_MATRIX_START_X + 3* ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_MULTIPLY_SPACING,
+ ChangeCoordinate3D.ROBOT_MATRIX_START_Y);
+
+ }
+
+
+ this.multiplyAdd(robotPositionMatrix, this.RobotMatrix, this.RobotPosition,
+ ChangeCoordinate3D.ROBOT_MATRIX_START_X, ChangeCoordinate3D.ROBOT_MATRIX_START_Y,
+ ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y,
+ 1, 2);
+
+
+
+
+
+ return this.commands;
+}
+
+ChangeCoordinate3D.prototype.changeTransformType = function(globalToLocal)
+{
+ this.commands = [];
+ this.lastLocalToGlobal = !globalToLocal;
+ this.removeOldIDs();
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.robotLabel1ID, "World Space to Robot Space\n(Orientation)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.robotLabel1ID, "Robot Space to World Space\n(Orientation)");
+ }
+ this.cmd("Step");
+ this.RobotMatrix = this.transposeVisual(this.RobotMatrix)
+
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.robotLabel2ID, "World Space to Robot Space\n(Position)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.robotLabel2ID, "Robot Space to World Space\n(Position)");
+ }
+ this.cmd("Step");
+ this.negateMatrixVisual(this.RobotPosition);
+ this.cmd("Step");
+
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.handLabel1ID, "Robot Space to Hand Space\n(Orientation)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.handLabel1ID, "Hand Space to Robot Space\n(Orientation)");
+ }
+
+ this.cmd("Step");
+ this.HandMatrix = this.transposeVisual(this.HandMatrix)
+
+ if (globalToLocal)
+ {
+ this.cmd("SetText", this.handLabel2ID, "Robot Space to Hand Space\n(Position)");
+
+ }
+ else
+ {
+ this.cmd("SetText", this.handLabel2ID, "Hand Space to Robot Space\n(Position)");
+ }
+ this.cmd("Step");
+ this.negateMatrixVisual(this.HandPosition);
+ this.cmd("Step");
+
+ if (globalToLocal)
+ {
+ this.cmd("Move", this.robotLabel1ID, ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y - 25);
+ this.moveMatrix(this.RobotMatrix, ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y)
+
+ this.cmd("Move", this.robotLabel2ID, ChangeCoordinate3D.ROBOT_MATRIX_START_X+ ChangeCoordinate3D.EQUALS_SPACING, ChangeCoordinate3D.ROBOT_MATRIX_START_Y - 25);
+ this.moveMatrix(this.RobotPosition, ChangeCoordinate3D.ROBOT_MATRIX_START_X+ ChangeCoordinate3D.EQUALS_SPACING, ChangeCoordinate3D.ROBOT_MATRIX_START_Y)
+
+ this.cmd("Move", this.handLabel1ID, ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y - 25);
+ this.moveMatrix(this.HandMatrix, ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y);
+
+
+ this.cmd("Move", this.handLabel2ID, ChangeCoordinate3D.HAND_MATRIX_START_X+ ChangeCoordinate3D.EQUALS_SPACING, ChangeCoordinate3D.HAND_MATRIX_START_Y - 25);
+ this.moveMatrix(this.HandPosition, ChangeCoordinate3D.HAND_MATRIX_START_X+ ChangeCoordinate3D.EQUALS_SPACING, ChangeCoordinate3D.HAND_MATRIX_START_Y);
+ }
+ else
+ {
+ this.cmd("Move", this.robotLabel1ID, ChangeCoordinate3D.ROBOT_MATRIX_START_X, ChangeCoordinate3D.ROBOT_MATRIX_START_Y - 25);
+ this.moveMatrix(this.RobotMatrix, ChangeCoordinate3D.ROBOT_MATRIX_START_X, ChangeCoordinate3D.ROBOT_MATRIX_START_Y)
+
+ this.cmd("Move", this.robotLabel2ID, ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y - 25);
+ this.moveMatrix(this.RobotPosition, ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y)
+
+ this.cmd("Move", this.handLabel1ID, ChangeCoordinate3D.HAND_MATRIX_START_X, ChangeCoordinate3D.HAND_MATRIX_START_Y - 25);
+ this.moveMatrix(this.HandMatrix, ChangeCoordinate3D.HAND_MATRIX_START_X, ChangeCoordinate3D.HAND_MATRIX_START_Y);
+
+ this.cmd("Move", this.handLabel2ID, ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y - 25);
+ this.moveMatrix(this.HandPosition, ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y);
+
+ }
+ return this.commands;
+}
+
+
+ChangeCoordinate3D.prototype.negateMatrixVisual = function(matrix)
+{
+ var i,j
+ for (i = 0; i < matrix.data.length; i++)
+ {
+ for (j = 0; j < matrix.data[i].length; j++)
+ {
+ matrix.data[i][j] = -matrix.data[i][j]
+ }
+ }
+ this.resetMatrixLabels(matrix);
+}
+
+
+ChangeCoordinate3D.prototype.globalToLocal = function(params)
+{
+ this.commands = [];
+ this.removeOldIDs();
+
+
+ var paramList = params.split(";");
+ var x = parseFloat(paramList[0]);
+ var y = parseFloat(paramList[1]);
+ var z = parseFloat(paramList[2]);
+
+ var opX, opY;
+
+
+ var screenPoint = this.worldToScreenSpace([x,y, z], 2);
+ var logicalPoint;
+
+ var pointInWorldSpaceID = this.nextIndex++;
+ this.oldIDs.push(pointInWorldSpaceID);
+ this.cmd("CreateCircle", pointInWorldSpaceID, "", screenPoint[0], screenPoint[1]);
+ this.cmd("SetWidth", pointInWorldSpaceID, ChangeCoordinate3D.VERTEX_WIDTH);
+ this.cmd("Connect", this.axisWorld[0], pointInWorldSpaceID, ChangeCoordinate3D.TRANSFORMED_POINT_COLORS[2], 0, 1, "");
+
+ var initialPointMatrix;
+ if (this.rowMajor)
+ {
+ initialPointMatrix = this.createMatrix([[x, y, z]], ChangeCoordinate3D.ROBOT_MATRIX_START_X - 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate3D.ROBOT_MATRIX_START_Y);
+ }
+ else
+ {
+ initialPointMatrix = this.createMatrix([[x], [y], [z]], ChangeCoordinate3D.ROBOT_MATRIX_START_X - ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate3D.ROBOT_MATRIX_START_Y);
+
+ }
+ this.addMatrixIDsToList(initialPointMatrix, this.oldIDs);
+ this.cmd("Step");
+
+ var positionAndID = this.addMultiply(initialPointMatrix, this.RobotPosition, this.RobotMatrix,
+ ChangeCoordinate3D.ROBOT_MATRIX_START_X + ChangeCoordinate3D.EQUALS_SPACING, ChangeCoordinate3D.ROBOT_MATRIX_START_Y,
+ ChangeCoordinate3D.ROBOT_POSITION_START_X, ChangeCoordinate3D.ROBOT_POSITION_START_Y,
+ pointInWorldSpaceID,
+ 2, 1);
+
+ var robotPositionMatrix = positionAndID[0];
+ var newPositionID = positionAndID[1];
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate3D.HAND_MATRIX_START_X - 3 * ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate3D.HAND_MATRIX_START_Y);
+ }
+ else
+ {
+ this.moveMatrix(robotPositionMatrix, ChangeCoordinate3D.HAND_MATRIX_START_X - ChangeCoordinate3D.MATRIX_ELEM_WIDTH,
+ ChangeCoordinate3D.HAND_MATRIX_START_Y);
+
+ }
+
+
+ this.addMultiply(robotPositionMatrix, this.HandPosition, this.HandMatrix,
+ ChangeCoordinate3D.HAND_MATRIX_START_X + ChangeCoordinate3D.EQUALS_SPACING, ChangeCoordinate3D.HAND_MATRIX_START_Y,
+ ChangeCoordinate3D.HAND_POSITION_START_X, ChangeCoordinate3D.HAND_POSITION_START_Y,
+ newPositionID,
+ 1, 0);
+
+
+
+ return this.commands;
+}
+
+ChangeCoordinate3D.prototype.moveObjectsCallback = function()
+{
+ this.implementAction(this.moveObjects.bind(this), 0);
+}
+
+ChangeCoordinate3D.prototype.moveObjects = function()
+{
+ this.commands = [];
+ this.removeOldIDs();
+ var i, j;
+
+ for (i = 0; i < this.otherAxes.length; i++)
+ {
+ for (j = 0; j < this.otherAxes[i].length; j++)
+ {
+ this.cmd("Delete", this.otherAxes[i][j]);
+ }
+ }
+
+
+ var i;
+ for (i = 0; i < ChangeCoordinate3D.ROBOT_POINTS.length; i++)
+ {
+
+ this.cmd("Delete", this.RobotPointRobotIDs[i]);
+ this.cmd("Delete", this.RobotPointWorldIDs[i]);
+ }
+ for (i = 0; i < ChangeCoordinate3D.HAND_POINTS.length; i++)
+ {
+ this.cmd("Delete", this.HandPointHandIDs[i]);
+ this.cmd("Delete", this.HandPointRobotIDs[i]);
+ this.cmd("Delete", this.HandPointWorldIDs[i]);
+ }
+ this.cmd("Delete", this.RobotHandAttachRobotID);
+ this.cmd("Delete", this.RobotHandAttachWorldID);
+ this.PositionIndex+= 1;
+ if (this.PositionIndex >= ChangeCoordinate3D.ROBOT_POSITION_VALUES.length)
+ {
+ this.PositionIndex = 0;
+ }
+
+ this.RobotPositionValues = ChangeCoordinate3D.ROBOT_POSITION_VALUES[this.PositionIndex];
+ this.RobotMatrixValues = ChangeCoordinate3D.ROBOT_MATRIX_VALUES[this.PositionIndex];
+ this.HandPositionValues = ChangeCoordinate3D.HAND_POSITION_VALUES[this.PositionIndex];
+ this.HandMatrixValues = ChangeCoordinate3D.HAND_MATRIX_VALUES[this.PositionIndex];
+
+ this.setupExtraAxes();
+ this.setupObjects();
+
+
+ this.RobotPosition.data = [this.RobotPositionValues];
+ this.RobotMatrix.data = this.RobotMatrixValues;
+ this.HandPosition.data = [this.HandPositionValues];
+ this.HandMatrix.data =this.HandMatrixValues;
+ if (!this.rowMajor)
+ {
+ this.RobotPosition.transpose();
+ this.RobotMatrix.transpose();
+ this.HandPosition.transpose();
+ this.HandMatrix.transpose();
+ }
+ this.resetMatrixLabels(this.RobotMatrix);
+ this.resetMatrixLabels(this.RobotPosition);
+ this.resetMatrixLabels(this.HandMatrix);
+ this.resetMatrixLabels(this.HandPosition);
+
+
+ return this.commands;
+}
+
+
+function toRadians(degrees)
+{
+ return (degrees * 2 * Math.PI) / 360.0;
+}
+
+
+ChangeCoordinate3D.prototype.addMatrix = function(mat1, mat2, mat3, numDigits)
+{
+ var i;
+ var j;
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat1.data[i].length; j++)
+ {
+ explainText = "";
+ var value = 0;
+ this.cmd("SetHighlight", mat1.dataID[i][j], 1);
+ this.cmd("SetHighlight", mat2.dataID[i][j], 1);
+ this.cmd("Step");
+ mat3.data[i][j] = mat1.data[i][j] + mat2.data[i][j];
+ this.cmd("SetHighlight", mat1.dataID[i][j], 0);
+ this.cmd("SetHighlight", mat2.dataID[i][j], 0);
+ this.cmd("SetText", mat3.dataID[i][j], this.standardize(mat3.data[i][j], numDigits));
+ this.cmd("Step");
+ }
+ }
+}
+
+
+
+
+ChangeCoordinate3D.prototype.multiplyMatrix = function(mat1, mat2, mat3, explainID, numDigits)
+{
+ var i;
+ var j;
+ var explainText = "";
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat2.data[0].length; j++)
+ {
+ var explainText = "";
+ var value = 0;
+ for (k = 0; k < mat2.data.length; k++)
+ {
+ this.cmd("SetHighlight", mat1.dataID[i][k], 1);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 1);
+ if (explainText != "")
+ {
+ explainText = explainText + " + ";
+ }
+ value = value + mat1.data[i][k] * mat2.data[k][j];
+ explainText = explainText + this.standardize(String(mat1.data[i][k]), numDigits) + " * " + this.standardize(String(mat2.data[k][j]),numDigits);
+ this.cmd("SetText", explainID, explainText);
+ this.cmd("Step");
+ this.cmd("SetHighlight", mat1.dataID[i][k], 0);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 0);
+ }
+ explainText += " = " + this.standardize(String(value), numDigits);
+ this.cmd("SetText", explainID, explainText);
+ mat3.data[i][j] = value;
+ this.cmd("SetText", mat3.dataID[i][j], this.standardize(value,numDigits));
+ this.cmd("Step");
+ }
+ }
+ this.cmd("SetText", explainID, "");
+
+
+}
+
+ChangeCoordinate3D.prototype.standardize = function(lab, digits)
+{
+ digits = (digits == undefined) ? 3 : digits;
+ var shift = Math.pow(10, digits);
+ var newLab = Math.round(lab * shift) / shift;
+ if (isNaN(newLab))
+ {
+ return lab;
+ }
+ else
+ {
+ return newLab;
+ }
+}
+
+
+ChangeCoordinate3D.prototype.resetMatrixLabels = function(mat, numDigits)
+{
+ var i,j, newLab;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ newLab = this.standardize(mat.data[i][j], numDigits);
+ this.cmd("SetText", mat.dataID[i][j], newLab);
+ }
+ }
+}
+
+
+
+ChangeCoordinate3D.prototype.moveMatrix = function(mat, x, y)
+{
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ }
+
+
+ this.cmd("Move", mat.leftBrack1, x, y);
+ this.cmd("Move", mat.leftBrack2, x, y);
+ this.cmd("Move", mat.leftBrack3, x, y + height * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT);
+
+ this.cmd("Move", mat.rightBrack1, x + width * ChangeCoordinate3D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack2, x + width * ChangeCoordinate3D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack3, x+ width * ChangeCoordinate3D.MATRIX_ELEM_WIDTH, y + height * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT);
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Move", mat.dataID[i][j],
+ x + j*ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_ELEM_WIDTH / 2,
+ y + i*ChangeCoordinate3D.MATRIX_ELEM_HEIGHT + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ mat.x = x;
+ mat.y = y;
+}
+
+
+
+
+ChangeCoordinate3D.prototype.addMatrixIDsToList = function(mat, list)
+{
+ list.push(mat.leftBrack1);
+ list.push(mat.leftBrack2);
+ list.push(mat.leftBrack3);
+ list.push(mat.rightBrack1);
+ list.push(mat.rightBrack2);
+ list.push(mat.rightBrack3);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ list.push(mat.dataID[i][j]);
+ }
+
+ }
+}
+
+ChangeCoordinate3D.prototype.deleteMatrix = function(mat)
+{
+ var IDList = [];
+ this.addMatrixIDsToList(mat, IDList);
+ var i;
+ for (i = 0; i < IDList.length; i++)
+ {
+ this.cmd("Delete", IDList[i]);
+ }
+}
+
+
+
+
+ChangeCoordinate3D.prototype.aplyFunctionToMatrixElems = function(mat, command, value)
+{
+ this.cmd(command, mat.leftBrack1, value);
+ this.cmd(command, mat.leftBrack2, value);
+ this.cmd(command, mat.leftBrack3, value);
+ this.cmd(command, mat.rightBrack1, value);
+ this.cmd(command, mat.rightBrack2, value);
+ this.cmd(command, mat.rightBrack3, value);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd(command, mat.dataID[i][j], value);
+ }
+ }
+}
+
+
+
+// Multiply two (data only!) matrices (not complete matrix object with graphics, just
+// the data
+function multiply(lhs, rhs)
+{
+ var resultMat = new Array(lhs.length);
+ var i, j, k;
+
+ for (i = 0; i < lhs.length; i++)
+ {
+ resultMat[i] = new Array(rhs[0].length);
+ }
+ for (i = 0; i < lhs.length; i++)
+ {
+ for (j = 0; j < rhs[0].length; j++)
+ {
+ var value = 0;
+ for (k = 0; k < rhs.length; k++)
+ {
+ value = value + lhs[i][k] * rhs[k][j];
+ }
+ resultMat[i][j] = value;
+ }
+ }
+ return resultMat;
+}
+
+// Add two (data only!) matrices (not complete matrix object with graphics, just
+// the data)
+ChangeCoordinate3D.prototype.add = function(lhs, rhs)
+{
+ var resultMat = new Array(lhs.length);
+ var i,j;
+
+ for (i = 0; i < lhs.length; i++)
+ {
+ resultMat[i] = new Array(lhs[i].length);
+ for (j = 0; j < lhs[i].length; j++)
+ {
+ resultMat[i][j] = lhs[i][j] + rhs[i][j];
+
+ }
+ }
+ return resultMat;
+}
+
+
+ChangeCoordinate3D.prototype.createMatrix = function(contents, x, y)
+{
+ var mat = new Matrix(contents, x, y);
+ mat.leftBrack1 = this.nextIndex++;
+ mat.leftBrack2 = this.nextIndex++;
+ mat.leftBrack3 = this.nextIndex++;
+ mat.rightBrack1 = this.nextIndex++;
+ mat.rightBrack2 = this.nextIndex++;
+ mat.rightBrack3 = this.nextIndex++;
+
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ mat.dataID = new Array(mat.data.length);
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ mat.dataID[i] = new Array(mat.data[i].length);
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.dataID[i][j] = this.nextIndex++;
+ }
+ }
+
+ this.cmd("CreateRectangle", mat.leftBrack1, "", 5, 1, x, y, "left","center");
+ this.cmd("CreateRectangle", mat.leftBrack2, "", 1, height * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT, x, y, "center","top");
+ this.cmd("CreateRectangle", mat.leftBrack3, "", 5, 1, x, y + height * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT , "left","center");
+
+ this.cmd("CreateRectangle", mat.rightBrack1, "", 5, 1, x + width * ChangeCoordinate3D.MATRIX_ELEM_WIDTH, y, "right","center");
+ this.cmd("CreateRectangle", mat.rightBrack2, "", 1, height * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT, x + width * ChangeCoordinate3D.MATRIX_ELEM_WIDTH, y, "center","top");
+ this.cmd("CreateRectangle", mat.rightBrack3, "", 5, 1, x+ width * ChangeCoordinate3D.MATRIX_ELEM_WIDTH, y + height * ChangeCoordinate3D.MATRIX_ELEM_HEIGHT , "right","center");
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("CreateLabel", mat.dataID[i][j], mat.data[i][j],
+ x + j*ChangeCoordinate3D.MATRIX_ELEM_WIDTH + ChangeCoordinate3D.MATRIX_ELEM_WIDTH / 2,
+ y + i*ChangeCoordinate3D.MATRIX_ELEM_HEIGHT + ChangeCoordinate3D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ return mat;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ChangeCoordinate3D(animManag, canvas.width, canvas.height);
+}
+
+function Matrix(contents, x, y)
+{
+ this.data = contents;
+ this.x = x;
+ this.y = y;
+}
+
+Matrix.prototype.transpose = function()
+{
+ var newData = new Array(this.data[0].length);
+ var i,j;
+ for (i = 0; i < this.data[0].length; i++)
+ {
+ newData[i] = new Array(this.data.length);
+ }
+ for (i = 0; i < this.data.length; i++)
+ {
+ for (j = 0; j < this.data[i].length; j++)
+ {
+ newData[j][i] = this.data[i][j];
+ }
+ }
+ this.data = newData;
+}
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ClosedHash.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ClosedHash.js
new file mode 100644
index 0000000..3fe1fe5
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ClosedHash.js
@@ -0,0 +1,417 @@
+// 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 ``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 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
+
+
+function ClosedHash(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+var ARRAY_ELEM_WIDTH = 90;
+var ARRAY_ELEM_HEIGHT = 30;
+var ARRAY_ELEM_START_X = 50;
+var ARRAY_ELEM_START_Y = 100;
+var ARRAY_VERTICAL_SEPARATION = 100;
+
+var CLOSED_HASH_TABLE_SIZE = 29;
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+
+var MAX_DATA_VALUE = 999;
+
+var HASH_TABLE_SIZE = 13;
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+ClosedHash.prototype = new Hash();
+ClosedHash.prototype.constructor = ClosedHash;
+ClosedHash.superclass = Hash.prototype;
+
+
+ClosedHash.prototype.init = function(am, w, h)
+{
+ var sc = ClosedHash.superclass;
+ var fn = sc.init;
+ this.elements_per_row = Math.floor(w / ARRAY_ELEM_WIDTH);
+
+ fn.call(this,am, w, h);
+
+ //Change me!
+ this.nextIndex = 0;
+ //this.POINTER_ARRAY_ELEM_Y = h - POINTER_ARRAY_ELEM_WIDTH;
+ this.setup();
+}
+
+ClosedHash.prototype.addControls = function()
+{
+ ClosedHash.superclass.addControls.call(this);
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Linear Probing: f(i) = i",
+ "Quadratic Probing: f(i) = i * i",
+ "Double Hashing: f(i) = i * hash2(elem)"],
+ "CollisionStrategy");
+ this.linearProblingButton = radioButtonList[0];
+ this.linearProblingButton.onclick = this.linearProbeCallback.bind(this);
+ this.quadraticProbingButton = radioButtonList[1];
+ this.quadraticProbingButton.onclick = this.quadraticProbeCallback.bind(this);
+ this.doubleHashingButton = radioButtonList[2];
+ this.doubleHashingButton.onclick = this.doubleHashingCallback.bind(this);
+
+ this.linearProblingButton.checked = true;
+ this.currentHashingTypeButtonState = this.linearProblingButton;
+
+ // Add new controls
+
+}
+
+
+ClosedHash.prototype.changeProbeType = function(newProbingType)
+{
+ if (newProbingType == this.linearProblingButton)
+ {
+ this.linearProblingButton.checked = true;
+ this.currentHashingTypeButtonState = this.linearProblingButton;
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.skipDist[i] = i;
+ }
+
+ }
+ else if (newProbingType == this.quadraticProbingButton)
+ {
+ this.quadraticProbingButton.checked = true;
+ this.currentHashingTypeButtonState = this.quadraticProbingButton;
+
+ for (var i = 0; i < this. table_size; i++)
+ {
+ this.skipDist[i] = i * i;
+ }
+
+
+ }
+ else if (newProbingType == this.doubleHashingButton)
+ {
+ this.doubleHashingButton.checked = true;
+ this.currentHashingTypeButtonState = this.doubleHashingButton;
+
+
+ }
+ this.commands = this.resetAll();
+ return this.commands;
+}
+
+
+
+ClosedHash.prototype.quadraticProbeCallback = function(event)
+{
+ if (this.currentHashingTypeButtonState != this.quadraticProbingButton)
+ {
+ this.implementAction(this.changeProbeType.bind(this),this.quadraticProbingButton);
+ }
+
+}
+
+
+ClosedHash.prototype.doubleHashingCallback = function(event)
+{
+ if (this.currentHashingTypeButtonState != this.doubleHashingButton)
+ {
+ this.implementAction(this.changeProbeType.bind(this),this.doubleHashingButton);
+ }
+
+}
+
+ClosedHash.prototype.linearProbeCallback = function(event)
+{
+ if (this.currentHashingTypeButtonState != this.linearProblingButton)
+ {
+ this.implementAction(this.changeProbeType.bind(this),this.linearProblingButton);
+ }
+
+}
+
+ClosedHash.prototype.insertElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "Inserting element: " + String(elem));
+ var index = this.doHash(elem);
+
+ index = this.getEmptyIndex(index, elem);
+ this.cmd("SetText", this.ExplainLabel, "");
+ if (index != -1)
+ {
+ var labID = this.nextIndex++;
+ this.cmd("CreateLabel", labID, elem, 20, 25);
+ this.cmd("Move", labID, this.indexXPos[index], this.indexYPos[index] - ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+ this.cmd("Delete", labID);
+ this.cmd("SetText", this.hashTableVisual[index], elem);
+ this.hashTableValues[index] = elem;
+ this.empty[index] = false;
+ this.deleted[index] = false;
+ }
+ return this.commands;
+
+}
+
+
+ClosedHash.prototype.resetSkipDist = function(elem, labelID)
+{
+ var skipVal = 7 - (this.currHash % 7);
+ this.cmd("CreateLabel", labelID, "hash2("+String(elem) +") = 1 - " + String(this.currHash) +" % 7 = " + String(skipVal), 20, 45, 0);
+ this.skipDist[0] = 0;
+ for (var i = 1; i < this.table_size; i++)
+ {
+ this.skipDist[i] = this.skipDist[i-1] + skipVal;
+ }
+
+
+}
+
+ClosedHash.prototype.getEmptyIndex = function(index, elem)
+{
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ this.resetSkipDist(elem, this.nextIndex++);
+ }
+ var foundIndex = -1;
+ for (var i = 0; i < this.table_size; i++)
+ {
+ var candidateIndex = (index + this.skipDist[i]) % this.table_size;
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+ if (this.empty[candidateIndex])
+ {
+ foundIndex = candidateIndex;
+ break;
+ }
+ }
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ this.cmd("Delete", --this.nextIndex);
+ }
+ return foundIndex;
+}
+
+ClosedHash.prototype.getElemIndex = function(index, elem)
+{
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ resetSkipDist(elem, this.nextIndex++);
+ }
+ var foundIndex = -1;
+ for (var i = 0; i < this.table_size; i++)
+ {
+ var candidateIndex = (index + this.skipDist[i]) % this.table_size;
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+ if (!this.empty[candidateIndex] && this.hashTableValues[candidateIndex] == elem)
+ {
+ foundIndex= candidateIndex;
+ break;
+ }
+ else if (this.empty[candidateIndex] && !this.deleted[candidateIndex])
+ {
+ break; }
+ }
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ this.cmd("Delete", --this.nextIndex);
+ }
+ return foundIndex;
+}
+
+ClosedHash.prototype.deleteElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem);
+ var index = this.doHash(elem);
+
+ index = this.getElemIndex(index, elem);
+
+ if (index > 0)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " 元素已删除");
+ this.empty[index] = true;
+ this.deleted[index] = true;
+ this.cmd("SetText", this.hashTableVisual[index], "");
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " Element not in table");
+ }
+ return this.commands;
+
+}
+ClosedHash.prototype.findElement = function(elem)
+{
+ this.commands = new Array();
+
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem);
+ var index = this.doHash(elem);
+
+ var found = this.getElemIndex(index, elem) != -1;
+ if (found)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem+ " 已找到!")
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem+ " 未找到!")
+
+ }
+ return this.commands;
+}
+
+
+
+
+ClosedHash.prototype.setup = function()
+{
+ this.table_size = CLOSED_HASH_TABLE_SIZE;
+ this.skipDist = new Array(this.table_size);
+ this.hashTableVisual = new Array(this.table_size);
+ this.hashTableIndices = new Array(this.table_size);
+ this.hashTableValues = new Array(this.table_size);
+
+ this.indexXPos = new Array(this.table_size);
+ this.indexYPos = new Array(this.table_size);
+
+ this.empty = new Array(this.table_size);
+ this.deleted = new Array(this.table_size);
+
+ this.ExplainLabel = this.nextIndex++;
+
+ this.commands = [];
+
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.skipDist[i] = i; // Start with linear probing
+ var nextID = this.nextIndex++;
+ this.empty[i] = true;
+ this.deleted[i] = false;
+
+ var nextXPos = ARRAY_ELEM_START_X + (i % this.elements_per_row) * ARRAY_ELEM_WIDTH;
+ var nextYPos = ARRAY_ELEM_START_Y + Math.floor(i / this.elements_per_row) * ARRAY_VERTICAL_SEPARATION;
+ this.cmd("CreateRectangle", nextID, "", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT,nextXPos, nextYPos)
+ this.hashTableVisual[i] = nextID;
+ nextID = this.nextIndex++;
+ this.hashTableIndices[i] = nextID;
+ this.indexXPos[i] = nextXPos;
+ this.indexYPos[i] = nextYPos + ARRAY_ELEM_HEIGHT
+
+ this.cmd("CreateLabel", nextID, i,this.indexXPos[i],this.indexYPos[i]);
+ this.cmd("SetForegroundColor", nextID, INDEX_COLOR);
+ }
+ this.cmd("CreateLabel", this.ExplainLabel, "", 10, 25, 0);
+ animationManager.StartNewAnimation(this.commands);
+ animationManager.skipForward();
+ animationManager.clearHistory();
+ this.resetIndex = this.nextIndex;
+}
+
+
+
+ClosedHash.prototype.resetAll = function()
+{
+ this.commands = ClosedHash.superclass.resetAll.call(this);
+
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.empty[i] = true;
+ this.deleted[i] = false;
+ this.cmd("SetText", this.hashTableVisual[i], "");
+ }
+ return this.commands;
+ // Clear array, etc
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+ClosedHash.prototype.reset = function()
+{
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.empty[i]= true;
+ this.deleted[i] = false;
+ }
+ this.nextIndex = this.resetIndex ;
+ ClosedHash.superclass.reset.call(this);
+
+}
+
+
+function resetCallback(event)
+{
+
+}
+
+
+
+
+
+ClosedHash.prototype.disableUI = function(event)
+{
+ ClosedHash.superclass.disableUI.call(this);
+ this.linearProblingButton.disabled = true;
+ this.quadraticProbingButton.disabled = true;
+ this.doubleHashingButton.disabled = true;
+}
+
+ClosedHash.prototype.enableUI = function(event)
+{
+ ClosedHash.superclass.enableUI.call(this);
+ this.linearProblingButton.disabled = false;
+ this.quadraticProbingButton.disabled = false;
+ this.doubleHashingButton.disabled = false;
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ClosedHash(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ClosedHashBucket.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ClosedHashBucket.js
new file mode 100644
index 0000000..d9d2539
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ClosedHashBucket.js
@@ -0,0 +1,363 @@
+// 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 ``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 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
+
+
+function ClosedHashBucket(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+var ARRAY_ELEM_WIDTH = 90;
+var ARRAY_ELEM_HEIGHT = 30;
+var ARRAY_ELEM_START_X = 50;
+var ARRAY_ELEM_START_Y = 100;
+var ARRAY_VERTICAL_SEPARATION = 100;
+
+var CLOSED_HASH_TABLE_SIZE = 29;
+
+
+var BUCKET_SIZE = 3;
+var NUM_BUCKETS = 11;
+var CLOSED_HASH_TABLE_SIZE = 40;
+
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+
+var MAX_DATA_VALUE = 999;
+
+var HASH_TABLE_SIZE = 13;
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+ClosedHashBucket.prototype = new Hash();
+ClosedHashBucket.prototype.constructor = ClosedHashBucket;
+ClosedHashBucket.superclass = Hash.prototype;
+
+
+ClosedHashBucket.prototype.init = function(am, w, h)
+{
+ var sc = ClosedHashBucket.superclass;
+ var fn = sc.init;
+ fn.call(this,am, w, h);
+
+ this.elements_per_row = Math.floor(w / ARRAY_ELEM_WIDTH) ;
+
+
+ //Change me!
+ this.nextIndex = 0;
+ //this.POINTER_ARRAY_ELEM_Y = h - POINTER_ARRAY_ELEM_WIDTH;
+ this.setup();
+}
+
+ClosedHashBucket.prototype.addControls = function()
+{
+ ClosedHashBucket.superclass.addControls.call(this);
+
+
+
+ // Add new controls
+
+}
+
+
+
+
+
+ClosedHashBucket.prototype.insertElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "Inserting element: " + String(elem));
+ var index = this.doHash(elem);
+
+ var foundIndex = -1;
+ for (var candidateIndex = index * BUCKET_SIZE; candidateIndex < index * BUCKET_SIZE + BUCKET_SIZE; candidateIndex++)
+ {
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+ if (this.empty[candidateIndex])
+ {
+ foundIndex = candidateIndex;
+ break;
+ }
+ }
+ if (foundIndex == -1)
+ {
+ for (candidateIndex = BUCKET_SIZE * NUM_BUCKETS; candidateIndex < CLOSED_HASH_TABLE_SIZE; candidateIndex++)
+ {
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+
+ if (this.empty[candidateIndex])
+ {
+ foundIndex = candidateIndex;
+ break;
+ }
+
+ }
+ }
+
+ if (foundIndex != -1)
+ {
+ var labID = this.nextIndex++;
+ this.cmd("CreateLabel", labID, elem, 20, 25);
+ this.cmd("Move", labID, this.indexXPos2[foundIndex], this.indexYPos2[foundIndex] - ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+ this.cmd("Delete", labID);
+ this.cmd("SetText", this.hashTableVisual[foundIndex], elem);
+ this.hashTableValues[foundIndex] = elem;
+ this.empty[foundIndex] = false;
+ this.deleted[foundIndex] = false;
+ }
+
+
+ this.cmd("SetText", this.ExplainLabel, "");
+
+ return this.commands;
+
+}
+
+
+
+
+ClosedHashBucket.prototype.getElemIndex = function(elem)
+{
+ var foundIndex = -1;
+ var initialIndex = this.doHash(elem);
+
+ for (var candidateIndex = initialIndex * BUCKET_SIZE; candidateIndex < initialIndex* BUCKET_SIZE + BUCKET_SIZE; candidateIndex++)
+ {
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+ if (!this.empty[candidateIndex] && this.hashTableValues[candidateIndex] == elem)
+ {
+ return candidateIndex;
+ }
+ else if (this.empty[candidateIndex] && !this.deleted[candidateIndex])
+ {
+ return -1;
+ }
+ }
+ // Can only get this far if we didn't find the element we are looking for,
+ // *and* the bucekt was full -- look at overflow bucket.
+ for (candidateIndex = BUCKET_SIZE * NUM_BUCKETS; candidateIndex < CLOSED_HASH_TABLE_SIZE; candidateIndex++)
+ {
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+
+ if (!this.empty[candidateIndex] && this.hashTableValues[candidateIndex] == elem)
+ {
+ return candidateIndex;
+ }
+ else if (this.empty[candidateIndex] && !this.deleted[candidateIndex])
+ {
+ return -1;
+ }
+ }
+ return -1;
+}
+
+
+ClosedHashBucket.prototype.deleteElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem);
+ var index = this.getElemIndex(elem);
+
+ if (index == -1)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " Element not in table");
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " Element this.deleted");
+ this.empty[index] = true;
+ this.deleted[index] = true;
+ this.cmd("SetText", this.hashTableVisual[index], "");
+ }
+
+ return this.commands;
+
+}
+ClosedHashBucket.prototype.findElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem);
+ var index = this.getElemIndex(elem);
+ if (index == -1)
+ {
+ this.cmd("SetText", this.ExplainLabel, "Element " + elem + " 未找到");
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "Element " + elem + " found");
+ }
+ return this.commands;
+}
+
+
+
+
+ClosedHashBucket.prototype.setup = function()
+{
+ this.table_size = NUM_BUCKETS;
+ this.hashTableVisual = new Array(CLOSED_HASH_TABLE_SIZE);
+ this.hashTableIndices = new Array(CLOSED_HASH_TABLE_SIZE);
+ this.hashTableValues = new Array(CLOSED_HASH_TABLE_SIZE);
+
+ this.indexXPos = new Array(NUM_BUCKETS);
+ this.indexYPos = new Array(NUM_BUCKETS);
+
+ this.indexXPos2 = new Array(CLOSED_HASH_TABLE_SIZE);
+ this.indexYPos2 = new Array(CLOSED_HASH_TABLE_SIZE);
+
+
+ this.empty = new Array(CLOSED_HASH_TABLE_SIZE);
+ this.deleted = new Array(CLOSED_HASH_TABLE_SIZE);
+
+ this.ExplainLabel = this.nextIndex++;
+
+ this.commands = [];
+
+ for (var i = 0; i < CLOSED_HASH_TABLE_SIZE; i++)
+ {
+ var nextID = this.nextIndex++;
+ this.empty[i] = true;
+ this.deleted[i] = false;
+
+ var nextXPos = ARRAY_ELEM_START_X + (i % this.elements_per_row) * ARRAY_ELEM_WIDTH;
+ var nextYPos = ARRAY_ELEM_START_Y + Math.floor(i / this.elements_per_row) * ARRAY_VERTICAL_SEPARATION;
+ this.cmd("CreateRectangle", nextID, "", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT,nextXPos, nextYPos)
+ this.hashTableVisual[i] = nextID;
+ nextID = this.nextIndex++;
+ this.hashTableIndices[i] = nextID;
+ this.indexXPos2[i] = nextXPos;
+ this.indexYPos2[i] = nextYPos + ARRAY_ELEM_HEIGHT
+
+ this.cmd("CreateLabel", nextID, i,this.indexXPos2[i],this.indexYPos2[i]);
+ this.cmd("SetForegroundColor", nextID, INDEX_COLOR);
+ }
+
+ for (i = 0; i <= NUM_BUCKETS; i++)
+ {
+ nextID = this.nextIndex++;
+ nextXPos = ARRAY_ELEM_START_X + (i * 3 % this.elements_per_row) * ARRAY_ELEM_WIDTH - ARRAY_ELEM_WIDTH / 2;
+ nextYPos = ARRAY_ELEM_START_Y + Math.floor((i * 3) / this.elements_per_row) * ARRAY_VERTICAL_SEPARATION + ARRAY_ELEM_HEIGHT;
+ this.cmd("CreateRectangle", nextID, "", 0, ARRAY_ELEM_HEIGHT * 2,nextXPos, nextYPos)
+ nextID = this.nextIndex++;
+ if (i == NUM_BUCKETS)
+ {
+ this.cmd("CreateLabel", nextID, "Overflow", nextXPos + 3, nextYPos + ARRAY_ELEM_HEIGHT / 2 , 0);
+ }
+ else
+ {
+ this.indexXPos[i] = nextXPos + 5;
+ this.indexYPos[i] = nextYPos + ARRAY_ELEM_HEIGHT / 2;
+ this.cmd("CreateLabel", nextID, i, this.indexXPos[i],this.indexYPos[i], 0);
+ }
+ }
+
+ this.cmd("CreateLabel", this.ExplainLabel, "", 10, 25, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.resetIndex = this.nextIndex;
+}
+
+
+
+
+
+
+
+ClosedHashBucket.prototype.resetAll = function()
+{
+ this.commands = ClosedHashBucket.superclass.resetAll.call(this);
+
+ for (var i = 0; i < CLOSED_HASH_TABLE_SIZE; i++)
+ {
+ this.empty[i] = true;
+ this.deleted[i] = false;
+ this.cmd("SetText", this.hashTableVisual[i], "");
+ }
+ return this.commands;
+ // Clear array, etc
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+ClosedHashBucket.prototype.reset = function()
+{
+ for (var i = 0; i < CLOSED_HASH_TABLE_SIZE; i++)
+ {
+ this.empty[i]= true;
+ this.deleted[i] = false;
+ }
+ this.nextIndex = this.resetIndex ;
+ ClosedHashBucket.superclass.reset.call(this);
+
+}
+
+
+
+
+ClosedHashBucket.prototype.disableUI = function(event)
+{
+ ClosedHashBucket.superclass.disableUI.call(this);
+}
+
+ClosedHashBucket.prototype.enableUI = function(event)
+{
+ ClosedHashBucket.superclass.enableUI.call(this);
+
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ClosedHashBucket(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ComparisonSort.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ComparisonSort.js
new file mode 100644
index 0000000..163fb32
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ComparisonSort.js
@@ -0,0 +1,684 @@
+// 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 ``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 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
+
+
+function ComparisonSort(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+
+var ARRAY_SIZE_SMALL = 50;
+var ARRAY_WIDTH_SMALL = 17;
+var ARRAY_BAR_WIDTH_SMALL = 10;
+var ARRAY_INITIAL_X_SMALL = 15;
+
+var ARRAY_Y_POS = 250;
+var ARRAY_LABEL_Y_POS = 260;
+
+var LOWER_ARRAY_Y_POS = 500;
+var LOWER_ARRAY_LABEL_Y_POS = 510;
+
+var SCALE_FACTOR = 2.0;
+
+var ARRAY_SIZE_LARGE = 200;
+var ARRAY_WIDTH_LARGE = 4;
+var ARRAY_BAR_WIDTH_LARGE = 2;
+var ARRAY_INITIAL_X_LARGE = 15;
+
+var BAR_FOREGROUND_COLOR = "#0000FF";
+var BAR_BACKGROUND_COLOR ="#AAAAFF";
+var INDEX_COLOR = "#0000FF";
+var HIGHLIGHT_BAR_COLOR = "#FF0000";
+var HIGHLIGHT_BAR_BACKGROUND_COLOR = "#FFAAAA";
+
+var QUICKSORT_LINE_COLOR = "#FF0000";
+
+
+
+ComparisonSort.prototype = new Algorithm();
+ComparisonSort.prototype.constructor = ComparisonSort;
+ComparisonSort.superclass = Algorithm.prototype;
+
+ComparisonSort.prototype.init = function(am, w, h)
+{
+ var sc = ComparisonSort.superclass;
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+
+ this.setArraySize(true);
+ this.arrayData = new Array(ARRAY_SIZE_LARGE);
+ this.arraySwap = new Array(ARRAY_SIZE_LARGE);
+ this.labelsSwap = new Array(ARRAY_SIZE_LARGE);
+ this.objectsSwap = new Array(ARRAY_SIZE_LARGE);
+
+ this.createVisualObjects();
+}
+
+
+
+ComparisonSort.prototype.addControls = function()
+{
+ this.resetButton = addControlToAlgorithmBar("Button", "Randomize Array");
+ this.resetButton.onclick = this.resetCallback.bind(this);
+
+ this.insertSortButton = addControlToAlgorithmBar("Button", "Insertion Sort");
+ this.insertSortButton.onclick = this.insertSortCallback.bind(this);
+
+ this.selectSortButton = addControlToAlgorithmBar("Button", "Selection Sort");
+ this.selectSortButton.onclick = this.selectSortCallback.bind(this);
+
+ this.bubbleSortButton = addControlToAlgorithmBar("Button", "Bubble Sort");
+ this.bubbleSortButton.onclick = this.bubbleSortCallback.bind(this);
+
+ this.quickSortButton = addControlToAlgorithmBar("Button", "Quick Sort");
+ this.quickSortButton.onclick = this.quickSortCallback.bind(this);
+
+ this.mergeSortButton = addControlToAlgorithmBar("Button", "Merge Sort");
+ this.mergeSortButton.onclick = this.mergeSortCallback.bind(this);
+
+ this.shellSortButton = addControlToAlgorithmBar("Button", "Shell Sort");
+ this.shellSortButton.onclick = this.shellSortCallback.bind(this);
+
+ this.sizeButton = addControlToAlgorithmBar("Button", "Change Size");
+ this.sizeButton.onclick = this.changeSizeCallback.bind(this);
+}
+
+
+ComparisonSort.prototype.setArraySize = function (small)
+{
+ if (small)
+ {
+ this.array_size = ARRAY_SIZE_SMALL;
+ this.array_width = ARRAY_WIDTH_SMALL;
+ this.array_bar_width = ARRAY_BAR_WIDTH_SMALL;
+ this.array_initial_x = ARRAY_INITIAL_X_SMALL;
+ this.array_y_pos = ARRAY_Y_POS;
+ this.array_label_y_pos = ARRAY_LABEL_Y_POS;
+ this.showLabels = true;
+ }
+ else
+ {
+ this.array_size = ARRAY_SIZE_LARGE;
+ this.array_width = ARRAY_WIDTH_LARGE;
+ this.array_bar_width = ARRAY_BAR_WIDTH_LARGE;
+ this.array_initial_x = ARRAY_INITIAL_X_LARGE;
+ this.array_y_pos = ARRAY_Y_POS;
+ this.array_label_y_pos = ARRAY_LABEL_Y_POS;
+ this.showLabels = false;
+ }
+
+}
+
+
+ComparisonSort.prototype.resetAll = function(small)
+{
+ this.animationManager.resetAll();
+ this.setArraySize(!small);
+ this.nextIndex = 0;
+ this.createVisualObjects();
+}
+
+
+ComparisonSort.prototype.randomizeArray = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < this.array_size; i++)
+ {
+ this.arrayData[i] = Math.floor(1 + Math.random()*99);
+ this.oldData[i] = this.arrayData[i];
+ if (this.showLabels)
+ {
+ this.cmd("SetText", this.barLabels[i], this.arrayData[i]);
+ }
+ else
+ {
+ this.cmd("SetText", this.barLabels[i], "");
+ }
+ this.cmd("SetHeight", this.barObjects[i], this.arrayData[i] * SCALE_FACTOR);
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+ComparisonSort.prototype.swap = function(index1, index2)
+{
+ var tmp = this.arrayData[index1];
+ this.arrayData[index1] = this.arrayData[index2];
+ this.arrayData[index2] = tmp;
+
+ tmp = this.barObjects[index1];
+ this.barObjects[index1] = this.barObjects[index2];
+ this.barObjects[index2] = tmp;
+
+ tmp = this.barLabels[index1];
+ this.barLabels[index1] = this.barLabels[index2];
+ this.barLabels[index2] = tmp;
+
+
+ this.cmd("Move", this.barObjects[index1], this.barPositionsX[index1], this.array_y_pos);
+ this.cmd("Move", this.barObjects[index2], this.barPositionsX[index2], this.array_y_pos);
+ this.cmd("Move", this.barLabels[index1], this.barPositionsX[index1], this.array_label_y_pos);
+ this.cmd("Move", this.barLabels[index2], this.barPositionsX[index2], this.array_label_y_pos);
+ this.cmd("Step");
+}
+
+
+ComparisonSort.prototype.createVisualObjects = function()
+{
+ this.barObjects = new Array(this.array_size);
+ this.oldBarObjects= new Array(this.array_size);
+ this.oldbarLabels= new Array(this.array_size);
+
+ this.barLabels = new Array(this.array_size);
+ this.barPositionsX = new Array(this.array_size);
+ this.oldData = new Array(this.array_size);
+ this.obscureObject = new Array(this.array_size);
+
+
+ var xPos = this.array_initial_x;
+ var yPos = this.array_y_pos;
+ var yLabelPos = this.array_label_y_pos;
+
+ this.commands = new Array();
+ for (var i = 0; i < this.array_size; i++)
+ {
+ xPos = xPos + this.array_width;
+ this.barPositionsX[i] = xPos;
+ this.cmd("CreateRectangle", this.nextIndex, "", this.array_bar_width, 200, xPos, yPos,"center","bottom");
+ this.cmd("SetForegroundColor", this.nextIndex, BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, BAR_BACKGROUND_COLOR);
+ this.barObjects[i] = this.nextIndex;
+ this.oldBarObjects[i] = this.barObjects[i];
+ this.nextIndex += 1;
+ if (this.showLabels)
+ {
+ this.cmd("CreateLabel", this.nextIndex, "99", xPos, yLabelPos);
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.nextIndex, "", xPos, yLabelPos);
+ }
+ this.cmd("SetForegroundColor", this.nextIndex, INDEX_COLOR);
+
+ this.barLabels[i] = this.nextIndex;
+ this.oldbarLabels[i] = this.barLabels[i];
+ ++this.nextIndex;
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.randomizeArray();
+ for (i = 0; i < this.array_size; i++)
+ {
+ this.obscureObject[i] = false;
+ }
+ this.lastCreatedIndex = this.nextIndex;
+}
+
+ComparisonSort.prototype.highlightRange = function(lowIndex, highIndex)
+{
+ for (var i = 0; i < lowIndex; i++)
+ {
+ if (!this.obscureObject[i])
+ {
+ this.obscureObject[i] = true;
+ this.cmd("SetAlpha", this.barObjects[i], 0.08);
+ this.cmd("SetAlpha", this.barLabels[i], 0.08);
+ }
+ }
+ for (i = lowIndex; i <= highIndex; i++)
+ {
+ if (this.obscureObject[i])
+ {
+ this.obscureObject[i] = false;
+ this.cmd("SetAlpha", this.barObjects[i], 1.0);
+ this.cmd("SetAlpha", this.barLabels[i], 1.0);
+ }
+ }
+ for (i = highIndex+1; i < this.array_size; i++)
+ {
+ if (!this.obscureObject[i])
+ {
+ this.obscureObject[i] = true;
+ this.cmd("SetAlpha", this.barObjects[i], 0.08);
+ this.cmd("SetAlpha", this.barLabels[i], 0.08);
+ }
+ }
+}
+
+
+
+ComparisonSort.prototype.reset = function()
+{
+ for (var i = 0; i < this.array_size; i++)
+ {
+
+ this.arrayData[i]= this.oldData[i];
+ this.barObjects[i] = this.oldBarObjects[i];
+ this.barLabels[i] = this.oldbarLabels[i];
+ if (this.showLabels)
+ {
+ this.cmd("SetText", this.barLabels[i], this.arrayData[i]);
+ }
+ else
+ {
+ this.cmd("SetText", this.barLabels[i], "");
+ }
+ this.cmd("SetHeight", this.barObjects[i], this.arrayData[i] * SCALE_FACTOR);
+ }
+ this.commands = new Array();
+}
+
+
+ComparisonSort.prototype.resetCallback = function(event)
+{
+ this.randomizeArray();
+}
+
+ComparisonSort.prototype.changeSizeCallback = function(event)
+{
+ this.resetAll(this.showLabels);
+}
+
+
+
+ComparisonSort.prototype.insertSortCallback = function(event)
+{
+ this.animationManager.clearHistory();
+ this.commands = new Array();
+ this.insertionSortSkip(1,0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.commands = new Array();
+}
+
+ComparisonSort.prototype.selectSortCallback = function(event)
+{
+ this.commands = new Array();
+ this.animationManager.clearHistory();
+
+
+ for (var i = 0; i < this.array_size - 1; i++)
+ {
+ var smallestIndex = i;
+ this.cmd("SetForegroundColor", this.barObjects[smallestIndex], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[smallestIndex], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ for (var j = i+1; j < this.array_size; j++)
+ {
+ this.cmd("SetForegroundColor", this.barObjects[j], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("Step");
+ if (this.arrayData[j] < this.arrayData[smallestIndex])
+ {
+ this.cmd("SetForegroundColor", this.barObjects[smallestIndex], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[smallestIndex], BAR_BACKGROUND_COLOR);
+ smallestIndex = j;
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+ }
+ }
+ if (smallestIndex != i)
+ {
+ this.swap(smallestIndex, i);
+ }
+ this.cmd("SetForegroundColor", this.barObjects[i], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[i], BAR_BACKGROUND_COLOR);
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+}
+ComparisonSort.prototype.bubbleSortCallback = function(event)
+{
+ this.animationManager.clearHistory();
+
+ this.commands = new Array();
+ for (var i = this.array_size-1; i > 0; i--)
+ {
+ for (var j = 0; j < i; j++)
+ {
+ this.cmd("SetForegroundColor", this.barObjects[j], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[j+1], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j+1], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("Step");
+ if (this.arrayData[j] > this.arrayData[j+1])
+ {
+ this.swap(j,j+1);
+ }
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[j+1], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j+1], BAR_BACKGROUND_COLOR);
+
+ }
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+}
+ComparisonSort.prototype.quickSortCallback = function(event)
+{
+ this.animationManager.clearHistory();
+
+ this.commands = new Array();
+ this.iID = this.nextIndex++;
+ this.jID= this.nextIndex++;
+ this.cmd("CreateLabel", this.iID, "i", this.barObjects[0], this.array_label_y_pos + 20);
+ this.cmd("CreateLabel", this.jID, "j", this.barObjects[this.array_size - 1], this.array_label_y_pos + 20);
+ this.cmd("SetForegroundColor", this.iID, HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.iID, HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("SetForegroundColor", this.jID, HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.jID, HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.doQuickSort(0, this.array_size - 1);
+ this.cmd("Delete", this.iID);
+ this.cmd("Delete", this.jID);
+ this.animationManager.StartNewAnimation(this.commands);
+}
+
+ComparisonSort.prototype.doQuickSort = function(low, high)
+{
+ this.highlightRange(low,high);
+ if (high <= low)
+ return;
+ this.cmd("Step");
+ var lineID = this.nextIndex;
+ var pivot = this.arrayData[low];
+ this.cmd("CreateRectangle", lineID, "", (this.array_size + 1) * this.array_width, 0, this.array_initial_x, this.array_y_pos - pivot * 2,"left","bottom");
+ this.cmd("SetForegroundColor", lineID, QUICKSORT_LINE_COLOR);
+ var i = low+1;
+ var j = high;
+
+ this.cmd("Move", this.iID, this.barPositionsX[i], this.array_label_y_pos + 20);
+ this.cmd("Move", this.jID, this.barPositionsX[j], this.array_label_y_pos + 20);
+ this.cmd("Step");
+
+ while (i <= j)
+ {
+
+ this.cmd("SetForegroundColor", this.barObjects[i], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[i], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("SetForegroundColor", this.barObjects[low], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.barObjects[low], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[i], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[i], BAR_BACKGROUND_COLOR);
+ while (i <= j && this.arrayData[i] < pivot)
+ {
+ ++i;
+ this.cmd("Move", this.iID, this.barPositionsX[i], this.array_label_y_pos + 20);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.barObjects[low], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("SetForegroundColor", this.barObjects[i], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[i], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.barObjects[low], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[i], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[i], BAR_BACKGROUND_COLOR);
+ }
+ this.cmd("SetForegroundColor", this.barObjects[j], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[low], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[low], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], BAR_BACKGROUND_COLOR);
+
+ while (j >= i && this.arrayData[j] > pivot)
+ {
+ --j;
+ this.cmd("Move", this.jID, this.barPositionsX[j], this.array_label_y_pos + 20);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.barObjects[j], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+
+ this.cmd("SetForegroundColor", this.barObjects[low], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+ this.cmd("SetForegroundColor", this.barObjects[low], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[low], BAR_BACKGROUND_COLOR);
+ }
+ if (i <= j)
+ {
+ this.cmd("Move", this.jID, this.barPositionsX[j-1], this.array_label_y_pos + 20);
+ this.cmd("Move", this.iID, this.barPositionsX[i+1], this.array_label_y_pos + 20);
+
+ this.swap(i,j);
+ ++i;
+ --j;
+ }
+ }
+ if (i >= low)
+ {
+ this.cmd("SetForegroundColor", this.barObjects[i], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[i], BAR_BACKGROUND_COLOR);
+
+ }
+ if (j <= high)
+ {
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+
+ }
+ this.swap(low, j);
+
+ this.cmd("Step");
+ this.cmd("Delete", lineID);
+
+ this.doQuickSort(low, j-1);
+ this.doQuickSort(j+1,high);
+ this.highlightRange(low,high);
+}
+
+ComparisonSort.prototype.mergeSortCallback = function(event)
+{
+ this.animationManager.clearHistory();
+
+ this.commands = new Array();
+ this.doMergeSort(0, this.array_size-1);
+ this.animationManager.StartNewAnimation(this.commands);
+}
+
+ComparisonSort.prototype.doMergeSort = function(low,high)
+{
+ this.highlightRange(low, high);
+ if (low < high)
+ {
+ this.cmd("Step");
+ var mid = Math.floor((low + high) / 2);
+ this.doMergeSort(low,mid);
+ this.doMergeSort(mid+1, high);
+ this.highlightRange(low,high);
+ var insertIndex = low;
+ var leftIndex = low;
+ var rightIndex = mid+1;
+ while (insertIndex <= high)
+ {
+ if (leftIndex <= mid && (rightIndex > high || this.arrayData[leftIndex] <= this.arrayData[rightIndex]))
+ {
+ this.arraySwap[insertIndex] = this.arrayData[leftIndex];
+ this.cmd("Move", this.barObjects[leftIndex], this.barPositionsX[insertIndex], LOWER_ARRAY_Y_POS);
+ this.cmd("Move", this.barLabels[leftIndex], this.barPositionsX[insertIndex], LOWER_ARRAY_LABEL_Y_POS);
+ this.cmd("Step");
+ this.labelsSwap[insertIndex] = this.barLabels[leftIndex];
+ this.objectsSwap[insertIndex] = this.barObjects[leftIndex];
+ insertIndex++;
+ leftIndex++;
+ }
+ else
+ {
+ this.arraySwap[insertIndex] = this.arrayData[rightIndex];
+ this.cmd("Move", this.barLabels[rightIndex], this.barPositionsX[insertIndex], LOWER_ARRAY_LABEL_Y_POS);
+ this.cmd("Move", this.barObjects[rightIndex], this.barPositionsX[insertIndex], LOWER_ARRAY_Y_POS);
+ this.cmd("Step");
+ this.labelsSwap[insertIndex] = this.barLabels[rightIndex];
+ this.objectsSwap[insertIndex] = this.barObjects[rightIndex];
+
+ insertIndex++;
+ rightIndex++;
+ }
+ }
+ for (insertIndex = low; insertIndex <= high; insertIndex++)
+ {
+ this.barObjects[insertIndex] = this.objectsSwap[insertIndex];
+ this.barLabels[insertIndex] = this.labelsSwap[insertIndex];
+ this.arrayData[insertIndex] = this.arraySwap[insertIndex];
+ this.cmd("Move", this.barObjects[insertIndex], this.barPositionsX[insertIndex], this.array_y_pos);
+ this.cmd("Move", this.barLabels[insertIndex], this.barPositionsX[insertIndex], this.array_label_y_pos);
+ }
+ this.cmd("Step");
+ }
+ else
+ {
+ this.cmd("Step");
+ }
+
+}
+
+ComparisonSort.prototype.shellSortCallback = function(event)
+{
+ this.animationManager.clearHistory();
+
+ this.commands = new Array();
+ var inc;
+ for (inc = Math.floor(this.array_size / 2); inc >=1; inc = Math.floor(inc / 2))
+ {
+ for (var offset = 0; offset < inc; offset = offset + 1)
+ {
+ for (var k = 0; k < this.array_size; k++)
+ {
+ if ((k - offset) % inc == 0)
+ {
+ if (this.obscureObject[k])
+ {
+ this.obscureObject[k] = false;
+ this.cmd("SetAlpha", this.barObjects[k], 1.0);
+ this.cmd("SetAlpha", this.barLabels[k], 1.0);
+ }
+
+ }
+ else
+ {
+ if (!this.obscureObject[k])
+ {
+ this.obscureObject[k] = true;
+ this.cmd("SetAlpha", this.barObjects[k], 0.08);
+ this.cmd("SetAlpha", this.barLabels[k], 0.08);
+ }
+ }
+ }
+ this.cmd("Step");
+ this.insertionSortSkip(inc, offset)
+
+ }
+
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+
+}
+
+ComparisonSort.prototype.insertionSortSkip = function(inc, offset)
+{
+ for (var i =inc + offset; i < this.array_size; i = i + inc)
+ {
+ var j = i;
+ while (j > inc - 1)
+ {
+ this.cmd("SetForegroundColor", this.barObjects[j], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetForegroundColor", this.barObjects[j-inc], HIGHLIGHT_BAR_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j - inc], HIGHLIGHT_BAR_BACKGROUND_COLOR);
+ this.cmd("Step");
+ if (this.arrayData[j-inc] <= this.arrayData[j])
+ {
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetForegroundColor", this.barObjects[j-inc], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j - inc], BAR_BACKGROUND_COLOR);
+ break;
+ }
+ this.swap(j,j-inc);
+ this.cmd("SetForegroundColor", this.barObjects[j], BAR_FOREGROUND_COLOR);
+ this.cmd("SetForegroundColor", this.barObjects[j-inc], BAR_FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j], BAR_BACKGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.barObjects[j - inc], BAR_BACKGROUND_COLOR);
+ j = j - inc;
+ }
+
+ }
+}
+
+ComparisonSort.prototype.disableUI = function(event)
+{
+ this.resetButton.disabled = true;
+ this.insertSortButton.disabled = true;
+ this.selectSortButton.disabled = true;
+ this.bubbleSortButton.disabled = true;
+ this.quickSortButton.disabled = true;
+ this.mergeSortButton.disabled = true;
+ this.shellSortButton.disabled = true;
+ this.sizeButton.disabled = true;
+}
+ComparisonSort.prototype.enableUI = function(event)
+{
+ this.resetButton.disabled = false;
+ this.insertSortButton.disabled = false;
+ this.selectSortButton.disabled = false;
+ this.bubbleSortButton.disabled = false;
+ this.quickSortButton.disabled = false;
+ this.mergeSortButton.disabled = false;
+ this.shellSortButton.disabled = false;
+ this.sizeButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ComparisonSort(animManag, canvas.width, canvas.height);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ConnectedComponent.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ConnectedComponent.js
new file mode 100644
index 0000000..89d5fd1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/ConnectedComponent.js
@@ -0,0 +1,484 @@
+// 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 ``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 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 AUX_ARRAY_WIDTH = 25;
+var AUX_ARRAY_HEIGHT = 25;
+var AUX_ARRAY_START_Y = 100;
+
+var VISITED_START_X = 475;
+var PARENT_START_X = 400;
+
+
+var D_X_POS_SMALL = [760, 685, 915, 610, 910, 685, 915, 760];
+var F_X_POS_SMALL = [760, 685, 915, 610, 910, 685, 915, 760];
+
+
+
+var D_Y_POS_SMALL = [18, 118, 118, 218, 218, 318, 318, 418];
+var F_Y_POS_SMALL = [32, 132, 132, 232, 232, 332, 332, 432];
+
+var D_X_POS_LARGE = [560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860];
+
+var F_X_POS_LARGE = [560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860];
+
+
+
+var D_Y_POS_LARGE = [037, 037, 037, 037,
+ 137, 137, 137,
+ 237, 237, 237, 237,
+ 337, 337, 337,
+ 437, 437, 437, 437];
+
+var F_Y_POS_LARGE = [62, 62, 62, 62,
+ 162, 162, 162,
+ 262, 262, 262, 262,
+ 362, 362, 362,
+ 462, 462, 462, 462];
+
+
+var HIGHLIGHT_CIRCLE_COLOR = "#000000";
+var DFS_TREE_COLOR = "#0000FF";
+
+
+function ConnectedComponent(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+ConnectedComponent.prototype = new Graph();
+ConnectedComponent.prototype.constructor = ConnectedComponent;
+ConnectedComponent.superclass = Graph.prototype;
+
+ConnectedComponent.prototype.addControls = function()
+{
+ this.startButton = addControlToAlgorithmBar("Button", "Run Connected Component");
+ this.startButton.onclick = this.startCallback.bind(this);
+ ConnectedComponent.superclass.addControls.call(this, false);
+}
+
+
+ConnectedComponent.prototype.init = function(am, w, h)
+{
+ this.showEdgeCosts = false;
+ ConnectedComponent.superclass.init.call(this, am, w, h, true, false); // TODO: add no edge label flag to this?
+ // Setup called in base class init function
+}
+
+
+ConnectedComponent.prototype.setup = function()
+{
+ ConnectedComponent.superclass.setup.call(this);
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+ this.messageID = new Array();
+ this.commands = new Array();
+ this.animationManager.clearHistory();
+ this.messageID = new Array();
+ this.commands = new Array();
+
+ this.highlightCircleL = this.nextIndex++;
+ this.highlightCircleAL = this.nextIndex++;
+ this.highlightCircleAM= this.nextIndex++
+ this.initialIndex = this.nextIndex;
+
+ this.old_adj_matrix = new Array(this.size);
+ this.old_adj_list_list = new Array(this.size);
+ this.old_adj_list_index = new Array(this.size);
+ this.old_adj_list_edges = new Array(this.size);
+ for (var i = 0; i < this.size; i++)
+ {
+ this.old_adj_matrix[i] = new Array(this.size);
+ this.old_adj_list_index[i] = this.adj_list_index[i];
+ this.old_adj_list_list[i] = this.adj_list_list[i];
+ this.old_adj_list_edges[i] = new Array(this.size);
+ for (var j = 0; j < this.size; j++)
+ {
+ this.old_adj_matrix[i][j] = this.adj_matrix[i][j];
+ if (this.adj_matrix[i][j] > 0)
+ {
+ this.old_adj_list_edges[i][j] = this.adj_list_edges[i][j];
+ }
+
+ }
+ }
+}
+
+
+ConnectedComponent.prototype.startCallback = function(event)
+{
+ this.implementAction(this.doCC.bind(this),"");
+}
+
+
+ConnectedComponent.prototype.transpose = function()
+{
+ for (var i = 0; i < this.size; i++)
+ {
+ for (var j = i+1; j 0)
+ {
+ var breakID = this.nextIndex++;
+ this.messageID.push(breakID);
+ this.cmd("CreateRectangle", breakID, "", 200, 0, 10, this.messageY,"left","bottom");
+ this.messageY = this.messageY + 20;
+ }
+ this.dfsVisit(vertex, 10, false);
+ this.cmd("Delete", this.highlightCircleL, 2);
+ this.cmd("Delete", this.highlightCircleAL, 3);
+ this.cmd("Delete", this.highlightCircleAM, 4);
+ }
+ }
+ this.clearEdges();
+ this.removeAdjList();
+ this.transpose();
+ this.buildEdges();
+ this.buildAdjList();
+ this.currentTime = 1
+
+ for (i=0; i < this.size; i++)
+ {
+ for (j = 0; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] >= 0)
+ {
+ this.cmd("SetText", this.adj_matrixID[i][j], "1");
+ }
+ else
+ {
+ this.cmd("SetText", this.adj_matrixID[i][j], "");
+ }
+ }
+ }
+
+
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ this.visited[vertex] = false;
+ this.cmd("Delete", this.d_timesID_L[vertex], 5);
+ this.cmd("Delete", this.f_timesID_L[vertex], 6);
+ this.cmd("Delete", this.d_timesID_AL[vertex], 7);
+ this.cmd("Delete", this.f_timesID_AL[vertex], 8);
+ }
+
+ var sortedVertex = new Array(this.size);
+ var sortedID = new Array(this.size);
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ sortedVertex[vertex] = vertex;
+ sortedID[vertex] = this.nextIndex++;
+ this.cmd("CreateLabel", sortedID[vertex], "Vertex: " + String(vertex)+ " f = " + String(this.f_times[vertex]), 400, 110 + vertex*20, 0);
+ }
+ this.cmd("Step");
+
+ for (i = 1; i < this.size; i++)
+ {
+ var j = i;
+ var tmpTime = this.f_times[i];
+ var tmpIndex = sortedVertex[i];
+ var tmpID = sortedID[i];
+ while (j > 0 && this.f_times[j-1] < tmpTime)
+ {
+ this.f_times[j] = this.f_times[j-1];
+ sortedVertex[j] = sortedVertex[j-1];
+ sortedID[j] = sortedID[j-1];
+ j--;
+ }
+ this.f_times[j] = tmpTime;
+ sortedVertex[j] = tmpIndex;
+ sortedID[j] = tmpID;
+ }
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ this.cmd("Move", sortedID[vertex], 400, 110 + vertex*20);
+ }
+
+ for (i = 0; i < this.messageID.length; i++)
+ {
+ this.cmd("Delete", this.messageID[i], 9);
+ }
+
+ this.messageID = new Array();
+ this.messageY = 30;
+
+ var ccNum = 1;
+ for (i = 0; i < this.size; i++)
+ {
+ vertex = sortedVertex[i];
+ if (!this.visited[vertex])
+ {
+
+ var breakID1 = this.nextIndex++;
+ this.messageID.push(breakID1);
+ var breakID2 = this.nextIndex++;
+ this.messageID.push(breakID2);
+ this.cmd("CreateRectangle", breakID1, "", 200, 0, 50, this.messageY + 8,"left","center");
+ this.cmd("CreateLabel", breakID2, "CC #" + String(ccNum++), 10, this.messageY, 0);
+ this.cmd("SetForegroundColor",breakID1 ,"#004B00");
+ this.cmd("SetForegroundColor",breakID2 ,"#004B00");
+ this.messageY = this.messageY + 20;
+
+ this.cmd("CreateHighlightCircle", this.highlightCircleL, HIGHLIGHT_CIRCLE_COLOR, this.x_pos_logical[vertex], this.y_pos_logical[vertex]);
+ this.cmd("SetLayer", this.highlightCircleL, 1);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAL, HIGHLIGHT_CIRCLE_COLOR,this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + vertex*this.adj_list_height);
+ this.cmd("SetLayer", this.highlightCircleAL, 2);
+
+ this.cmd("CreateHighlightCircle", this.highlightCircleAM, HIGHLIGHT_CIRCLE_COLOR,this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + vertex*this.adj_matrix_height);
+ this.cmd("SetLayer", this.highlightCircleAM, 3);
+
+
+
+
+
+ this.dfsVisit(vertex, 75, true);
+ this.cmd("Delete", this.highlightCircleL, 10);
+ this.cmd("Delete", this.highlightCircleAL, 11);
+ this.cmd("Delete", this.highlightCircleAM, 12);
+ }
+ this.cmd("Delete", sortedID[i], 13);
+ }
+
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ this.cmd("Delete", this.d_timesID_L[vertex], 14);
+ this.cmd("Delete", this.f_timesID_L[vertex], 15);
+ this.cmd("Delete", this.d_timesID_AL[vertex], 16);
+ this.cmd("Delete", this.f_timesID_AL[vertex], 17);
+ }
+
+ return this.commands
+
+}
+
+
+ConnectedComponent.prototype.setup_large = function()
+{
+ this.d_x_pos = D_X_POS_LARGE;
+ this.d_y_pos = D_Y_POS_LARGE;
+ this.f_x_pos = F_X_POS_LARGE;
+ this.f_y_pos = F_Y_POS_LARGE;
+
+ ConnectedComponent.superclass.setup_large.call(this);
+}
+ConnectedComponent.prototype.setup_small = function()
+{
+
+ this.d_x_pos = D_X_POS_SMALL;
+ this.d_y_pos = D_Y_POS_SMALL;
+ this.f_x_pos = F_X_POS_SMALL;
+ this.f_y_pos = F_Y_POS_SMALL;
+
+ ConnectedComponent.superclass.setup_small.call(this);
+}
+
+ConnectedComponent.prototype.dfsVisit = function(startVertex, messageX, printCCNum)
+{
+ if (printCCNum)
+ {
+ var ccNumberID = this.nextIndex++;
+ this.messageID.push(ccNumberID);
+ this.cmd("CreateLabel",ccNumberID, "Vertex " + String(startVertex), 5, this.messageY, 0);
+ this.cmd("SetForegroundColor", ccNumberID, "#0000FF");
+ }
+ var nextMessage = this.nextIndex++;
+ this.messageID.push(nextMessage);
+ this.cmd("CreateLabel",nextMessage, "DFS(" + String(startVertex) + ")", messageX, this.messageY, 0);
+
+ this.messageY = this.messageY + 20;
+ if (!this.visited[startVertex])
+ {
+ this.d_times[startVertex] = this.currentTime++;
+ this.cmd("CreateLabel", this.d_timesID_L[startVertex], "d = " + String(this.d_times[startVertex]), this.d_x_pos[startVertex], this.d_y_pos[startVertex]);
+ this.cmd("CreateLabel", this.d_timesID_AL[startVertex], "d = " + String(this.d_times[startVertex]), this.adj_list_x_start - 2*this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height - 1/4*this.adj_list_height);
+ this.cmd("SetLayer", this.d_timesID_L[startVertex], 1);
+ this.cmd("SetLayer", this.d_timesID_AL[startVertex], 2);
+
+ this.visited[startVertex] = true;
+ this.cmd("Step");
+ for (var neighbor = 0; neighbor < this.size; neighbor++)
+ {
+ if (this.adj_matrix[startVertex][neighbor] > 0)
+ {
+ this.highlightEdge(startVertex, neighbor, 1);
+ if (this.visited[neighbor])
+ {
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Vertex " + String(neighbor) + " already this.visited.", messageX, this.messageY, 0);
+ }
+ this.cmd("Step");
+ this.highlightEdge(startVertex, neighbor, 0);
+ if (this.visited[neighbor])
+ {
+ this.cmd("Delete", nextMessage, "DNM");
+ }
+
+ if (!this.visited[neighbor])
+ {
+ this.cmd("Disconnect", this.circleID[startVertex], this.circleID[neighbor]);
+ this.cmd("Connect", this.circleID[startVertex], this.circleID[neighbor], DFS_TREE_COLOR, this.curve[startVertex][neighbor], 1, "");
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[neighbor], this.y_pos_logical[neighbor]);
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + neighbor*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + neighbor*this.adj_matrix_height);
+
+ this.cmd("Step");
+ this.dfsVisit(neighbor, messageX + 10, printCCNum);
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Returning from recursive call: DFS(" + String(neighbor) + ")", messageX + 20, this.messageY, 0);
+
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[startVertex], this.y_pos_logical[startVertex]);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + startVertex*this.adj_matrix_height);
+ this.cmd("Step");
+ this.cmd("Delete", nextMessage, 18);
+ }
+ this.cmd("Step");
+
+
+
+ }
+
+ }
+ this.f_times[startVertex] = this.currentTime++;
+ this.cmd("CreateLabel", this.f_timesID_L[startVertex],"f = " + String(this.f_times[startVertex]), this.f_x_pos[startVertex], this.f_y_pos[startVertex]);
+ this.cmd("CreateLabel", this.f_timesID_AL[startVertex], "f = " + String(this.f_times[startVertex]), this.adj_list_x_start - 2*this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height + 1/4*this.adj_list_height);
+
+ this.cmd("SetLayer", this.f_timesID_L[startVertex], 1);
+ this.cmd("SetLayer", this.f_timesID_AL[startVertex], 2);
+
+
+
+ }
+
+}
+
+
+ConnectedComponent.prototype.reset = function()
+{
+ // TODO: Fix undo messing with setup vars.
+ this.messageID = new Array();
+ this.nextIndex = this.initialIndex;
+ for (var i = 0; i < this.size; i++)
+ {
+ this.adj_list_list[i] = this.old_adj_list_list[i];
+ this.adj_list_index[i] = this.old_adj_list_index[i];
+
+ for (var j = 0; j < this.size; j++)
+ {
+ this.adj_matrix[i][j] = this.old_adj_matrix[i][j];
+ if (this.adj_matrix[i][j] > 0)
+ {
+ this.adj_list_edges[i][j] = this.old_adj_list_edges[i][j];
+ }
+ }
+ }
+
+}
+
+
+
+ConnectedComponent.prototype.enableUI = function(event)
+{
+ this.startButton.disabled = false;
+
+ ConnectedComponent.superclass.enableUI.call(this,event);
+}
+ConnectedComponent.prototype.disableUI = function(event)
+{
+
+ this.startButton.disabled = true;
+
+ ConnectedComponent.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ConnectedComponent(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/CountingSort.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/CountingSort.js
new file mode 100644
index 0000000..fcbbfd1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/CountingSort.js
@@ -0,0 +1,325 @@
+// 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 ``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 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
+
+
+function CountingSort(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+
+var ARRAY_ELEM_WIDTH = 30;
+var ARRAY_ELEM_HEIGHT = 30;
+var ARRAY_ELEM_START_X = 20;
+
+
+
+var COUNTER_ARRAY_ELEM_WIDTH = 30;
+var COUNTER_ARRAY_ELEM_HEIGHT = 30;
+var COUNTER_ARRAY_ELEM_START_X = 20;
+
+
+
+var MAX_DATA_VALUE = 30;
+var COUNTER_ARRAY_SIZE = MAX_DATA_VALUE + 1;
+
+var ARRAY_SIZE = 30;
+
+
+CountingSort.prototype = new Algorithm();
+CountingSort.prototype.constructor = CountingSort;
+CountingSort.superclass = Algorithm.prototype;
+
+CountingSort.prototype.init = function(am, w, h)
+{
+ this.ARRAY_ELEM_Y = 3 * COUNTER_ARRAY_ELEM_HEIGHT;
+ this.COUNTER_ARRAY_ELEM_Y = Math.floor(h / 2);
+ this.SWAP_ARRAY_ELEM_Y = h - 3 * COUNTER_ARRAY_ELEM_HEIGHT
+
+ var sc = CountingSort.superclass;
+ var fn = sc.init;
+ fn.call(this,am,w,h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.setup();
+
+
+
+}
+
+
+
+CountingSort.prototype.sizeChanged = function(newWidth, newHeight)
+{
+ this.ARRAY_ELEM_Y = 3 * COUNTER_ARRAY_ELEM_HEIGHT;
+ this.COUNTER_ARRAY_ELEM_Y = Math.floor(newHeight / 2);
+ this.SWAP_ARRAY_ELEM_Y = newHeight - 3 * COUNTER_ARRAY_ELEM_HEIGHT
+ this.setup();
+}
+
+
+CountingSort.prototype.addControls = function()
+{
+ this.resetButton = addControlToAlgorithmBar("Button", "Randomize List");
+ this.resetButton.onclick = this.resetCallback.bind(this);
+
+ this.countingsSortButton = addControlToAlgorithmBar("Button", "Counting Sort");
+ this.countingsSortButton.onclick = this.countingSortCallback.bind(this);
+
+}
+
+
+
+CountingSort.prototype.setup = function()
+{
+ this.arrayData = new Array(ARRAY_SIZE);
+ this. arrayRects= new Array(ARRAY_SIZE);
+ this. arrayIndices = new Array(ARRAY_SIZE);
+
+
+ this. counterData = new Array(COUNTER_ARRAY_SIZE);
+ this. counterRects= new Array(COUNTER_ARRAY_SIZE);
+ this. counterIndices = new Array(COUNTER_ARRAY_SIZE);
+
+ this. swapData = new Array(ARRAY_SIZE);
+ this. swapRects= new Array(ARRAY_SIZE);
+ this. swapIndices = new Array(ARRAY_SIZE);
+
+ this. commands = new Array();
+
+ this.animationManager.resetAll();
+ for (var i = 0; i < ARRAY_SIZE; i++)
+ {
+ var nextID = this.nextIndex++;
+ this.arrayData[i] = Math.floor(Math.random()*MAX_DATA_VALUE);
+ this.cmd("CreateRectangle", nextID, this.arrayData[i], ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y)
+ this. arrayRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this. arrayIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y + ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+
+ nextID = this.nextIndex++;
+ this.cmd("CreateRectangle", nextID, "", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y)
+ this. swapRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this. swapIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y + ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+
+ }
+ for (i = COUNTER_ARRAY_SIZE - 1; i >= 0; i--)
+ {
+ nextID = this.nextIndex++;
+ this.cmd("CreateRectangle", nextID,"", COUNTER_ARRAY_ELEM_WIDTH, COUNTER_ARRAY_ELEM_HEIGHT, COUNTER_ARRAY_ELEM_START_X + i *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y)
+ this. counterRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this. counterIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, COUNTER_ARRAY_ELEM_START_X + i *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+ }
+ this.animationManager.StartNewAnimation(this. commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+
+CountingSort.prototype.resetAll = function(small)
+{
+ this.animationManager.resetAll();
+ this.nextIndex = 0;
+}
+
+CountingSort.prototype.countingSortCallback = function(event)
+{
+ this. commands = new Array();
+ var animatedCircleID = this.nextIndex++;
+ var animatedCircleID2 = this.nextIndex++;
+ var animatedCircleID3 = this.nextIndex++;
+ var animatedCircleID4 = this.nextIndex++;
+ for (var i = 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this. counterData[i] = 0;
+ this.cmd("SetText", this. counterRects[i], 0);
+ }
+ for (i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("CreateHighlightCircle", animatedCircleID, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("CreateHighlightCircle", animatedCircleID2, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ var index = this.arrayData[i];
+ this.cmd("Move", animatedCircleID, COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT)
+ this.cmd("Step");
+ this. counterData[index]++;
+ this.cmd("SetText", this. counterRects[this.arrayData[i]], this. counterData[this.arrayData[i]]);
+ this.cmd("Step");
+ this.cmd("SetAlpha", this. arrayRects[i], 0.2);
+ this.cmd("Delete", animatedCircleID);
+ this.cmd("Delete", animatedCircleID2);
+ }
+ for (i=1; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetHighlight", this. counterRects[i-1], 1);
+ this.cmd("SetHighlight", this. counterRects[i], 1);
+ this.cmd("Step")
+ this. counterData[i] = this. counterData[i] + this. counterData[i-1];
+ this.cmd("SetText", this. counterRects[i], this. counterData[i]);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this. counterRects[i-1], 0);
+ this.cmd("SetHighlight", this. counterRects[i], 0);
+ }
+ for (i=ARRAY_SIZE - 1; i >= 0; i--)
+ {
+ this.cmd("SetAlpha", this. arrayRects[i], 1.0);
+ }
+ for (i=ARRAY_SIZE - 1; i >= 0; i--)
+ {
+ this.cmd("CreateHighlightCircle", animatedCircleID, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("CreateHighlightCircle", animatedCircleID2, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+
+ index = this.arrayData[i];
+ this.cmd("Move", animatedCircleID2, COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT)
+ this.cmd("Step");
+
+ var insertIndex = --this. counterData[this.arrayData[i]];
+ this.cmd("SetText", this. counterRects[this.arrayData[i]], this. counterData[this.arrayData[i]]);
+ this.cmd("Step");
+
+ this.cmd("CreateHighlightCircle", animatedCircleID3, "#AAAAFF", COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y);
+ this.cmd("CreateHighlightCircle", animatedCircleID4, "#AAAAFF", COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y);
+
+ this.cmd("Move", animatedCircleID4, ARRAY_ELEM_START_X + insertIndex * ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT)
+ this.cmd("Step");
+
+ var moveLabel = this.nextIndex++;
+ this.cmd("SetText", this. arrayRects[i], "");
+ this.cmd("CreateLabel", moveLabel, this.arrayData[i], ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("Move", moveLabel, ARRAY_ELEM_START_X + insertIndex *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y);
+ this. swapData[insertIndex] = this.arrayData[i];
+ this.cmd("Step");
+ this.cmd("Delete", moveLabel);
+ this.nextIndex--; // Reuse index from moveLabel, now that it has been removed.
+ this.cmd("SetText", this. swapRects[insertIndex], this. swapData[insertIndex]);
+ this.cmd("Delete", animatedCircleID);
+ this.cmd("Delete", animatedCircleID2);
+ this.cmd("Delete", animatedCircleID3);
+ this.cmd("Delete", animatedCircleID4);
+
+ }
+ for (i= 0; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("SetText", this. arrayRects[i], "");
+ }
+
+ for (i= 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetAlpha", this. counterRects[i], 0.05);
+ this.cmd("SetAlpha", this. counterIndices[i], 0.05);
+ }
+
+ this.cmd("Step");
+ var startLab = this.nextIndex;
+ for (i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("CreateLabel", startLab+i, this. swapData[i], ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y);
+ this.cmd("Move", startLab+i, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("SetText", this. swapRects[i], "");
+
+ }
+ this.cmd("Step");
+ for (i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.arrayData[i] = this. swapData[i];
+ this.cmd("SetText", this. arrayRects[i], this.arrayData[i]);
+ this.cmd("Delete", startLab + i);
+ }
+ for (i= 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetAlpha", this. counterRects[i], 1);
+ this.cmd("SetAlpha", this. counterIndices[i], 1);
+ }
+ this.animationManager.StartNewAnimation(this. commands);
+
+}
+
+CountingSort.prototype.randomizeArray = function()
+{
+ this. commands = new Array();
+ for (var i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.arrayData[i] = Math.floor(1 + Math.random()*MAX_DATA_VALUE);
+ this.cmd("SetText", this. arrayRects[i], this.arrayData[i]);
+ }
+
+ for (i = 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetText", this. counterRects[i], "");
+ }
+
+
+ this.animationManager.StartNewAnimation(this. commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+
+// We want to (mostly) ignore resets, since we are disallowing undoing
+CountingSort.prototype.reset = function()
+{
+ this.commands = new Array();
+}
+
+
+CountingSort.prototype.resetCallback = function(event)
+{
+ this.randomizeArray();
+}
+
+
+
+CountingSort.prototype.disableUI = function(event)
+{
+ this.resetButton.disabled = true;
+ this.countingsSortButton.disabled = true;
+}
+CountingSort.prototype.enableUI = function(event)
+{
+ this.resetButton.disabled = false;
+ this.countingsSortButton.disabled = false;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+
+ currentAlg = new CountingSort(animManag, canvas.width, canvas.height);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DFS.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DFS.js
new file mode 100644
index 0000000..96536c1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DFS.js
@@ -0,0 +1,260 @@
+// 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 ``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 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 AUX_ARRAY_WIDTH = 25;
+var AUX_ARRAY_HEIGHT = 25;
+var AUX_ARRAY_START_Y = 50;
+
+var VISITED_START_X = 475;
+var PARENT_START_X = 400;
+
+var HIGHLIGHT_CIRCLE_COLOR = "#000000";
+var DFS_TREE_COLOR = "#0000FF";
+var BFS_QUEUE_HEAD_COLOR = "#0000FF";
+
+
+var QUEUE_START_X = 30;
+var QUEUE_START_Y = 50;
+var QUEUE_SPACING = 30;
+
+
+function DFS(am)
+{
+ this.init(am);
+
+}
+
+DFS.prototype = new Graph();
+DFS.prototype.constructor = DFS;
+DFS.superclass = Graph.prototype;
+
+DFS.prototype.addControls = function()
+{
+ addLabelToAlgorithmBar("Start Vertex: ");
+ this.startField = addControlToAlgorithmBar("Text", "");
+ this.startField.onkeydown = this.returnSubmit(this.startField, this.startCallback.bind(this), 2, true);
+ this.startButton = addControlToAlgorithmBar("Button", "Run DFS");
+ this.startButton.onclick = this.startCallback.bind(this);
+ DFS.superclass.addControls.call(this);
+}
+
+
+DFS.prototype.init = function(am, w, h)
+{
+ showEdgeCosts = false;
+ DFS.superclass.init.call(this, am, w, h); // TODO: add no edge label flag to this?
+ // Setup called in base class constructor
+}
+
+
+DFS.prototype.setup = function()
+{
+ DFS.superclass.setup.call(this);
+ this.messageID = new Array();
+ this.commands = new Array();
+ this.visitedID = new Array(this.size);
+ this.visitedIndexID = new Array(this.size);
+ this.parentID = new Array(this.size);
+ this.parentIndexID = new Array(this.size);
+ for (var i = 0; i < this.size; i++)
+ {
+ this.visitedID[i] = this.nextIndex++;
+ this.visitedIndexID[i] = this.nextIndex++;
+ this.parentID[i] = this.nextIndex++;
+ this.parentIndexID[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.visitedID[i], "f", AUX_ARRAY_WIDTH, AUX_ARRAY_HEIGHT, VISITED_START_X, AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("CreateLabel", this.visitedIndexID[i], i, VISITED_START_X - AUX_ARRAY_WIDTH , AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("SetForegroundColor", this.visitedIndexID[i], VERTEX_INDEX_COLOR);
+ this.cmd("CreateRectangle", this.parentID[i], "", AUX_ARRAY_WIDTH, AUX_ARRAY_HEIGHT, PARENT_START_X, AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("CreateLabel", this.parentIndexID[i], i, PARENT_START_X - AUX_ARRAY_WIDTH , AUX_ARRAY_START_Y + i*AUX_ARRAY_HEIGHT);
+ this.cmd("SetForegroundColor", this.parentIndexID[i], VERTEX_INDEX_COLOR);
+
+ }
+ this.cmd("CreateLabel", this.nextIndex++, "Parent", PARENT_START_X - AUX_ARRAY_WIDTH, AUX_ARRAY_START_Y - AUX_ARRAY_HEIGHT * 1.5, 0);
+ this.cmd("CreateLabel", this.nextIndex++, "Visited", VISITED_START_X - AUX_ARRAY_WIDTH, AUX_ARRAY_START_Y - AUX_ARRAY_HEIGHT * 1.5, 0);
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.highlightCircleL = this.nextIndex++;
+ this.highlightCircleAL = this.nextIndex++;
+ this.highlightCircleAM= this.nextIndex++
+}
+
+DFS.prototype.startCallback = function(event)
+{
+ var startValue;
+
+ if (this.startField.value != "")
+ {
+ startvalue = this.startField.value;
+ this.startField.value = "";
+ if (parseInt(startvalue) < this.size)
+ this.implementAction(this.doDFS.bind(this),startvalue);
+ }
+}
+
+
+
+DFS.prototype.doDFS = function(startVetex)
+{
+ this.visited = new Array(this.size);
+ this.commands = new Array();
+ if (this.messageID != null)
+ {
+ for (var i = 0; i < this.messageID.length; i++)
+ {
+ this.cmd("Delete", this.messageID[i]);
+ }
+ }
+ this.rebuildEdges();
+ this.messageID = new Array();
+ for (i = 0; i < this.size; i++)
+ {
+ this.cmd("SetText", this.visitedID[i], "f");
+ this.cmd("SetText", this.parentID[i], "");
+ this.visited[i] = false;
+ }
+ var vertex = parseInt(startVetex);
+ this.cmd("CreateHighlightCircle", this.highlightCircleL, HIGHLIGHT_CIRCLE_COLOR, this.x_pos_logical[vertex], this.y_pos_logical[vertex]);
+ this.cmd("SetLayer", this.highlightCircleL, 1);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAL, HIGHLIGHT_CIRCLE_COLOR,this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + vertex*this.adj_list_height);
+ this.cmd("SetLayer", this.highlightCircleAL, 2);
+
+ this.cmd("CreateHighlightCircle", this.highlightCircleAM, HIGHLIGHT_CIRCLE_COLOR,this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + vertex*this.adj_matrix_height);
+ this.cmd("SetLayer", this.highlightCircleAM, 3);
+
+ this.messageY = 30;
+ this.dfsVisit(vertex, 10);
+ this.cmd("Delete", this.highlightCircleL);
+ this.cmd("Delete", this.highlightCircleAL);
+ this.cmd("Delete", this.highlightCircleAM);
+ return this.commands
+
+}
+
+
+DFS.prototype.dfsVisit = function(startVertex, messageX)
+{
+ var nextMessage = this.nextIndex++;
+ this.messageID.push(nextMessage);
+
+ this.cmd("CreateLabel",nextMessage, "DFS(" + String(startVertex) + ")", messageX, this.messageY, 0);
+ this.messageY = this.messageY + 20;
+ if (!this.visited[startVertex])
+ {
+ this.visited[startVertex] = true;
+ this.cmd("SetText", this.visitedID[startVertex], "T");
+ this.cmd("Step");
+ for (var neighbor = 0; neighbor < this.size; neighbor++)
+ {
+ if (this.adj_matrix[startVertex][neighbor] > 0)
+ {
+ this.highlightEdge(startVertex, neighbor, 1);
+ this.cmd("SetHighlight", this.visitedID[neighbor], 1);
+ if (this.visited[neighbor])
+ {
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Vertex " + String(neighbor) + " already visited.", messageX, this.messageY, 0);
+ }
+ this.cmd("Step");
+ this.highlightEdge(startVertex, neighbor, 0);
+ this.cmd("SetHighlight", this.visitedID[neighbor], 0);
+ if (this.visited[neighbor])
+ {
+ this.cmd("Delete", nextMessage);
+ }
+
+ if (!this.visited[neighbor])
+ {
+ this.cmd("Disconnect", this.circleID[startVertex], this.circleID[neighbor]);
+ this.cmd("Connect", this.circleID[startVertex], this.circleID[neighbor], DFS_TREE_COLOR, this.curve[startVertex][neighbor], 1, "");
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[neighbor], this.y_pos_logical[neighbor]);
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + neighbor*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + neighbor*this.adj_matrix_height);
+
+ this.cmd("SetText", this.parentID[neighbor], startVertex);
+ this.cmd("Step");
+ this.dfsVisit(neighbor, messageX + 20);
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Returning from recursive call: DFS(" + String(neighbor) + ")", messageX + 20, this.messageY, 0);
+
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[startVertex], this.y_pos_logical[startVertex]);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + startVertex*this.adj_matrix_height);
+ this.cmd("Step");
+ this.cmd("Delete", nextMessage);
+ }
+ this.cmd("Step");
+
+
+
+ }
+
+ }
+
+ }
+
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+DFS.prototype.reset = function()
+{
+ // Throw an error?
+}
+
+
+
+
+DFS.prototype.enableUI = function(event)
+{
+ this.startField.disabled = false;
+ this.startButton.disabled = false;
+ this.startButton
+
+
+ DFS.superclass.enableUI.call(this,event);
+}
+DFS.prototype.disableUI = function(event)
+{
+
+ this.startField.disabled = true;
+ this.startButton.disabled = true;
+
+ DFS.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new DFS(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPChange.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPChange.js
new file mode 100644
index 0000000..de016a1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPChange.js
@@ -0,0 +1,985 @@
+// 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 ``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 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
+
+
+
+function DPChange(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+DPChange.prototype = new Algorithm();
+DPChange.prototype.constructor = DPChange;
+DPChange.superclass = Algorithm.prototype;
+
+DPChange.TABLE_ELEM_WIDTH = 30;
+DPChange.TABLE_ELEM_HEIGHT = 30;
+
+DPChange.TABLE_START_X = 500;
+DPChange.TABLE_START_Y = 50;
+DPChange.TABLE_DIFF_X = 70;
+
+DPChange.CODE_START_X = 10;
+DPChange.CODE_START_Y = 10;
+DPChange.CODE_LINE_HEIGHT = 14;
+
+
+DPChange.GREEDY_START_X = 100;
+DPChange.GREEDY_START_Y = 150;
+DPChange.RECURSIVE_START_X = 220;
+DPChange.RECURSIVE_START_Y = 10;
+DPChange.RECURSIVE_DELTA_Y = 14;
+DPChange.RECURSIVE_DELTA_X = 8;
+DPChange.CODE_HIGHLIGHT_COLOR = "#FF0000";
+DPChange.CODE_STANDARD_COLOR = "#000000";
+
+DPChange.TABLE_INDEX_COLOR = "#0000FF"
+DPChange.CODE_RECURSIVE_1_COLOR = "#339933";
+DPChange.CODE_RECURSIVE_2_COLOR = "#0099FF";
+
+DPChange.DPCode = [["def ","change(n, coinArray)",":"],
+ [" if ","(n == 0) "],
+ [" return 0"],
+ [" best = -1"],
+ [" for coin in coinArray:"],
+ [" if ","(coin <= n)",":"],
+ [" nextTry = ","change(n - coin, coinArray)"],
+ [" if (", "best < 0", " or ", "best > nextTry + 1", ")"],
+ [" best = nextTry + 1"],
+ [" return best"]];
+
+
+DPChange.GREEDYCode = [["def ","changeGreedy(n, coinArray)",":"],
+ [" coinsRequired = 0"],
+ [" for coin in reversed(coinArray): "],
+ [" while ", "(n <= coin)"],
+ [" n = n - coin"],
+ [" coinsRequired = coinsRequired + 1"],
+ [" return coinsRequired"]];
+
+
+DPChange.COINS = [[1, 5, 10, 25],
+ [1, 4, 6, 10]];
+
+
+DPChange.MAX_VALUE = 30;
+
+DPChange.MESSAGE_ID = 0;
+
+
+DPChange.prototype.setCode = function(codeArray)
+{
+ this.code = codeArray;
+ this.codeID = Array(this.code.length);
+ var i, j;
+ for (i = 0; i < this.code.length; i++)
+ {
+ this.codeID[i] = new Array(this.code[i].length);
+ for (j = 0; j < this.code[i].length; j++)
+ {
+ this.codeID[i][j] = this.nextIndex++;
+ this.cmd("CreateLabel", this.codeID[i][j], this.code[i][j], DPChange.CODE_START_X, DPChange.CODE_START_Y + i * DPChange.CODE_LINE_HEIGHT, 0);
+ this.cmd("SetForegroundColor", this.codeID[i][j], DPChange.CODE_STANDARD_COLOR);
+ if (j > 0)
+ {
+ this.cmd("AlignRight", this.codeID[i][j], this.codeID[i][j-1]);
+ }
+ }
+ }
+}
+
+
+DPChange.prototype.deleteCode = function()
+{
+ var i,j
+ for (i = 0; i < this.codeID.length; i++)
+ {
+ for (j = 0; j < this.codeID[i].length; j++)
+ {
+ this.cmd("Delete", this.codeID[i][j]);
+ }
+ }
+ this.codeID = [];
+}
+
+DPChange.prototype.setCodeAlpha = function(codeArray, alpha)
+{
+ var i, j
+ for (i = 0; i < codeArray.length; i++)
+ {
+ var foo = 3;
+ foo = codeArray[i];
+ for (j = 0; j < codeArray[i].length; j++)
+ {
+ this.cmd("SetAlpha", codeArray[i][j], alpha);
+ }
+ }
+}
+
+
+
+DPChange.prototype.init = function(am, w, h)
+{
+ DPChange.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ // HACK!!
+ this.setCode(DPChange.GREEDYCode);
+ this.greedyCodeID = this.codeID;
+ this.setCodeAlpha(this.greedyCodeID, 0);
+ ///
+ this.setCode(DPChange.DPCode);
+ this.usingDPCode = true;
+
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+DPChange.prototype.addControls = function()
+{
+ this.controls = [];
+ this.fibField = addControlToAlgorithmBar("Text", "");
+ this.fibField.onkeydown = this.returnSubmit(this.fibField, this.emptyCallback.bind(this), 2, true);
+ this.controls.push(this.fibField);
+
+ this.recursiveButton = addControlToAlgorithmBar("Button", "Change Recursive");
+ this.recursiveButton.onclick = this.recursiveCallback.bind(this);
+ this.controls.push(this.recursiveButton);
+
+ this.tableButton = addControlToAlgorithmBar("Button", "Change Table");
+ this.tableButton.onclick = this.tableCallback.bind(this);
+ this.controls.push(this.tableButton);
+
+ this.memoizedButton = addControlToAlgorithmBar("Button", "Change Memoized");
+ this.memoizedButton.onclick = this.memoizedCallback.bind(this);
+ this.controls.push(this.memoizedButton);
+
+
+ this.greedyButton = addControlToAlgorithmBar("Button", "Change Greedy");
+ this.greedyButton.onclick = this.greedyCallback.bind(this);
+ this.controls.push(this.greedyButton);
+
+
+
+
+ var coinLabels = [];
+ var i, j;
+ for (i = 0; i < DPChange.COINS.length; i++)
+ {
+ var nextLabel = "Coins: [" + DPChange.COINS[i][0];
+ for (j = 1; j < DPChange.COINS[i].length; j++)
+ {
+ nextLabel = nextLabel + ", " + DPChange.COINS[i][j];
+ }
+ nextLabel = nextLabel + "]";
+ coinLabels.push(nextLabel);
+ }
+
+ this.coinTypeButtons = addRadioButtonGroupToAlgorithmBar(coinLabels, "CoinType");
+
+ for (i = 0; i < this.coinTypeButtons.length; i++)
+ {
+ this.coinTypeButtons[i].onclick = this.coinTypeChangedCallback.bind(this, i);
+ this.controls.push(this.coinTypeButtons[i]);
+ }
+
+ this.coinTypeButtons[0].checked = true;
+ this.coinIndex = 0;
+}
+
+
+
+DPChange.prototype.coinTypeChangedCallback = function(coinIndex)
+{
+ this.implementAction(this.coinTypeChanged.bind(this), coinIndex);
+}
+
+
+DPChange.prototype.coinTypeChanged = function(coinIndex)
+{
+ this.commands = [];
+ this.coinIndex = coinIndex;
+ this.coinTypeButtons[coinIndex].checked = true;
+ this.clearOldIDs();
+
+ return this.commands;
+}
+
+
+
+
+
+DPChange.prototype.greedyCallback = function(value)
+{
+
+ if (this.fibField.value != "")
+ {
+ this.implementAction(this.implementGreedy.bind(this),parseInt(this.fibField.value));
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+
+DPChange.prototype.implementGreedy = function(value)
+{
+ this.commands = [];
+ this.clearOldIDs();
+ var initialValue = value;
+ if (this.usingDPCode)
+ {
+ this.setCodeAlpha(this.greedyCodeID, 1);
+ this.setCodeAlpha(this.codeID, 0);
+ this.usingDPCode = false;
+ }
+
+ var currX = DPChange.GREEDY_START_X;
+ var currY = DPChange.GREEDY_START_Y + 2.5 * DPChange.TABLE_ELEM_HEIGHT;
+
+ var messageID = this.nextIndex++;
+ this.oldIDs.push(messageID);
+
+ var valueRemainingID = this.nextIndex++;
+ this.oldIDs.push(valueRemainingID);
+
+ this.cmd("CreateRectangle", valueRemainingID, value, DPChange.TABLE_ELEM_WIDTH,
+ DPChange.TABLE_ELEM_HEIGHT,
+ DPChange.GREEDY_START_X, DPChange.GREEDY_START_Y);
+
+ var tempLabel = this.nextIndex++;
+ this.oldIDs.push(tempLabel);
+ this.cmd("CreateLabel", tempLabel, "Amount remaining:",0, 0);
+ this.cmd("AlignLeft", tempLabel, valueRemainingID);
+
+ var requiredCoinsID = this.nextIndex++;
+ this.oldIDs.push(requiredCoinsID);
+
+ this.cmd("CreateRectangle", requiredCoinsID, value, DPChange.TABLE_ELEM_WIDTH,
+ DPChange.TABLE_ELEM_HEIGHT,
+ DPChange.GREEDY_START_X, DPChange.GREEDY_START_Y + DPChange.TABLE_ELEM_HEIGHT);
+
+ tempLabel = this.nextIndex++;
+ this.oldIDs.push(tempLabel);
+ this.cmd("CreateLabel", tempLabel, "Required Coins:",0, 0);
+ this.cmd("AlignLeft", tempLabel, requiredCoinsID);
+
+
+ var requiredCoins = 0;
+ var i;
+ for (i = DPChange.COINS[this.coinIndex].length - 1; i >=0; i--)
+ {
+ while (value >= DPChange.COINS[this.coinIndex][i])
+ {
+ requiredCoins = requiredCoins + 1;
+ value = value - DPChange.COINS[this.coinIndex][i];
+ this.cmd("SetText", valueRemainingID, value);
+ this.cmd("SetText", requiredCoinsID, requiredCoins);
+ var moveIndex = this.nextIndex++;
+ this.oldIDs.push(moveIndex);
+ this.cmd("CreateLabel", moveIndex, DPChange.COINS[this.coinIndex][i], DPChange.GREEDY_START_X, DPChange.GREEDY_START_Y);
+ this.cmd("Move", moveIndex, currX, currY);
+ currX += DPChange.TABLE_ELEM_WIDTH;
+ this.cmd("Step");
+ }
+
+ }
+
+ this.cmd("CreateLabel", messageID,
+ "changeGreedy(" + String(initialValue)+ ", [" +String(DPChange.COINS[this.coinIndex]) +"]) = " + String(requiredCoins),
+ DPChange.RECURSIVE_START_X, DPChange.RECURSIVE_START_Y, 0);
+
+ return this.commands;
+}
+
+
+
+
+DPChange.prototype.buildTable = function(maxVal)
+{
+
+ this.tableID = new Array(2);
+ this.tableVals = new Array(2);
+ this.tableXPos = new Array(2);
+ this.tableYPos = new Array(2);
+ var i;
+ for (i = 0; i < 2; i++)
+ {
+ this.tableID[i] = new Array(maxVal + 1);
+ this.tableVals[i] = new Array(maxVal + 1);
+ this.tableXPos[i] = new Array(maxVal + 1);
+ this.tableYPos[i] = new Array(maxVal + 1);
+ }
+
+ var j;
+ var indexID;
+ var xPos;
+ var yPos;
+ var table_rows = Math.floor((this.canvasHeight - DPChange.TABLE_ELEM_HEIGHT - DPChange.TABLE_START_Y) / DPChange.TABLE_ELEM_HEIGHT);
+ var table_cols = Math.ceil((maxVal + 1) / table_rows);
+
+ var header1ID = this.nextIndex++;
+ this.oldIDs.push(header1ID);
+
+ this.cmd("CreateLabel", header1ID, "# of Coins Required", DPChange.TABLE_START_X, DPChange.TABLE_START_Y - 30);
+
+
+ var header2ID = this.nextIndex++;
+ this.oldIDs.push(header2ID);
+
+ this.cmd("CreateLabel", header2ID, "Coins to Use", DPChange.TABLE_START_X + table_cols*DPChange.TABLE_DIFF_X + 1.5*DPChange.TABLE_DIFF_X, DPChange.TABLE_START_Y - 30);
+
+
+
+ for (i = 0; i <= maxVal; i++)
+ {
+ yPos = i % table_rows * DPChange.TABLE_ELEM_HEIGHT + DPChange.TABLE_START_Y;
+ xPos = Math.floor(i / table_rows) * DPChange.TABLE_DIFF_X + DPChange.TABLE_START_X;
+
+ for (j = 0; j < 2; j++)
+ {
+
+ this.tableID[j][i] = this.nextIndex++;
+ this.tableVals[j][i] = -1;
+ this.oldIDs.push(this.tableID[j][i]);
+
+
+ this.tableXPos[j][i] = xPos;
+ this.tableYPos[j][i] = yPos;
+
+ this.cmd("CreateRectangle", this.tableID[j][i],
+ "",
+ DPChange.TABLE_ELEM_WIDTH,
+ DPChange.TABLE_ELEM_HEIGHT,
+ xPos,
+ yPos);
+ indexID = this.nextIndex++;
+ this.oldIDs.push(indexID);
+ this.cmd("CreateLabel", indexID, i, xPos - DPChange.TABLE_ELEM_WIDTH, yPos);
+ this.cmd("SetForegroundColor", indexID, DPChange.TABLE_INDEX_COLOR);
+
+ xPos = xPos + table_cols * DPChange.TABLE_DIFF_X + 1.5*DPChange.TABLE_DIFF_X;
+ }
+
+
+
+ }
+}
+
+DPChange.prototype.clearOldIDs = function()
+{
+ for (var i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+DPChange.prototype.reset = function()
+{
+ this.oldIDs =[];
+ this.coinIndex = 0;
+ this.usingDPCode = true;
+ this.coinTypeButtons[0].checked = true;
+ this.nextIndex = this.initialIndex;
+}
+
+
+
+DPChange.prototype.emptyCallback = function(event)
+{
+ this.implementAction(this.helpMessage.bind(this), "");
+ // TODO: Put up a message to push the appropriate button?
+
+}
+
+DPChange.prototype.displayCoinsUsed = function()
+{
+ var currValue = this.tableVals[1].length - 1;
+ var currX = 30;
+ var currY = 200;
+
+ var moveID;
+ moveID = this.nextIndex++;
+
+ while (currValue > 0)
+ {
+ moveID = this.nextIndex++;
+ this.oldIDs.push(moveID);
+ this.cmd("CreateLabel", moveID, this.tableVals[1][currValue], this.tableXPos[1][currValue], this.tableYPos[1][currValue]);
+ this.cmd("Move", moveID, currX, currY);
+ this.cmd("Step");
+ currX += 20;
+ currValue = currValue - this.tableVals[1][currValue];
+ }
+}
+
+DPChange.prototype.recursiveCallback = function(event)
+{
+ var fibValue;
+
+ if (this.fibField.value != "")
+ {
+ var fibValue = Math.min(parseInt(this.fibField.value), DPChange.MAX_VALUE - 5);
+ this.fibField.value = String(fibValue);
+ this.implementAction(this.recursiveChange.bind(this),fibValue);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+
+DPChange.prototype.tableCallback = function(event)
+{
+ var fibValue;
+
+ if (this.fibField.value != "")
+ {
+ var fibValue = Math.min(parseInt(this.fibField.value), DPChange.MAX_VALUE);
+ this.fibField.value = String(fibValue);
+ this.implementAction(this.tableChange.bind(this),fibValue);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+
+}
+
+
+DPChange.prototype.memoizedCallback = function(event)
+{
+ var fibValue;
+
+ if (this.fibField.value != "")
+ {
+ var changeVal = Math.min(parseInt(this.fibField.value), DPChange.MAX_VALUE);
+ this.fibField.value = String(changeVal);
+ this.implementAction(this.memoizedChange.bind(this),changeVal);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+DPChange.prototype.helpMessage = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ var messageID = this.nextIndex++;
+ this.oldIDs.push(messageID);
+ this.cmd("CreateLabel", messageID,
+ "Enter a value between 0 and " + String(DPChange.MAX_VALUE) + " in the text field.\n" +
+ "Then press the Change Recursive, Change Table, Change Memoized, or Change Greedy button",
+ DPChange.RECURSIVE_START_X, DPChange.RECURSIVE_START_Y, 0);
+ return this.commands;
+
+
+}
+
+
+DPChange.prototype.recursiveChange = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+ if (!this.usingDPCode)
+ {
+ this.setCodeAlpha(this.greedyCodeID, 0);
+ this.setCodeAlpha(this.codeID, 1);
+ this.usingDPCode = true;
+ }
+
+ this.currentY = DPChange.RECURSIVE_START_Y;
+
+ var functionCallID = this.nextIndex++;
+ this.oldIDs.push(functionCallID);
+ var final = this.change(value, DPChange.RECURSIVE_START_X, functionCallID);
+ this.cmd("SetText", functionCallID, "change(" + String(value)+ ", [" +String(DPChange.COINS[this.coinIndex]) +"]) = " + String(final[0]));
+ return this.commands;
+}
+
+
+DPChange.prototype.change = function(value, xPos, ID)
+{
+ var coins = DPChange.COINS[this.coinIndex];
+ this.cmd("CreateLabel", ID, "change(" + String(value)+ ", [" +String(coins) +"])", xPos, this.currentY, 0);
+ this.currentY += DPChange.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
+ // return 1;
+ if (value > 0)
+ {
+ this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_STANDARD_COLOR);
+
+ var i;
+ var best = -1;
+ var nextID = this.nextIndex++;
+ var nextID2 = this.nextIndex++;
+ var recID = nextID;
+ var bestList;
+ for (i = 0; i < coins.length; i++)
+ {
+ this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_STANDARD_COLOR);
+ if (value >= coins[i])
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_STANDARD_COLOR);
+ var nextTry = this.change(value - coins[i], xPos + DPChange.RECURSIVE_DELTA_X, recID);
+ // TODO: SOMEHTING ELSE HERE
+ if (best == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_STANDARD_COLOR);
+ best = nextTry[0] + 1;
+ bestList = nextTry[1];
+ bestList.push(coins[i]);
+ this.currentY += DPChange.RECURSIVE_DELTA_Y;
+ recID = nextID2;
+ }
+ else if (best > nextTry[0] + 1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_STANDARD_COLOR);
+ best = nextTry[0] + 1;
+ bestList = nextTry[1];
+ bestList.push(coins[i]);;
+ this.cmd("Delete", recID);
+ this.cmd("SetText", nextID, String(best) + " ([" + String(bestList) + "])");
+ this.cmd("SetPosition", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
+ this.cmd("Move", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY - DPChange.RECURSIVE_DELTA_Y);
+ this.cmd("Step");
+ }
+ else
+ {
+ this.cmd("Delete", recID);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ this.cmd("Delete", nextID);
+ this.cmd("SetText", ID, String(best) + " ([" + String(bestList) + "])");
+ this.cmd("SetPosition", ID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
+ this.cmd("Move", ID, xPos, this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y);
+
+
+ this.currentY = this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y;
+
+ this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("Step");
+ return [best, bestList];
+ }
+ else
+ {
+ this.cmd("SetText", ID, "0");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
+
+ this.currentY -= DPChange.RECURSIVE_DELTA_Y;
+ return [0, []];
+ }
+
+
+
+}
+
+
+
+
+DPChange.prototype.tableChange = function(value)
+{
+ this.commands = [];
+ this.clearOldIDs();
+ if (!this.usingDPCode)
+ {
+ this.setCodeAlpha(this.greedyCodeID, 0);
+ this.setCodeAlpha(this.codeID, 1);
+ this.usingDPCode = true;
+ }
+
+ this.buildTable(value);
+ coins = DPChange.COINS[this.coinIndex];
+ var i;
+ for (i = 0; i <= value && i <= 0; i++)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.tableID[0][i], 1);
+ this.cmd("SetText", this.tableID[0][i], 0);
+ this.tableVals[0][i] = 0;
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[0][i], 0);
+ }
+ for (i = 1; i <= value; i++)
+ {
+ this.tableVals[0][i] = -1;
+ var j;
+ for (j = 0; j < coins.length; j++)
+ {
+ if (coins[j] <= i)
+ {
+ this.cmd("SetHighlight", this.tableID[0][i-coins[j]], 1);
+ this.cmd("SetHighlight", this.tableID[0][i], 1);
+ this.cmd("Step");
+ if (this.tableVals[0][i] == -1 || this.tableVals[0][i] > this.tableVals[0][i - coins[j]] + 1)
+ {
+ this.tableVals[0][i] = this.tableVals[0][i- coins[j]] + 1;
+ this.cmd("SetText", this.tableID[0][i], this.tableVals[0][i]);
+ this.cmd("SetHighlight", this.tableID[1][i], 1);
+ this.cmd("SetText", this.tableID[1][i], coins[j]);
+ this.tableVals[1][i] = coins[j];
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.tableID[1][i], 0);
+ }
+ this.cmd("SetHighlight", this.tableID[0][i-coins[j]], 0);
+ this.cmd("SetHighlight", this.tableID[0][i], 0);
+ }
+ }
+ }
+
+ var finalID = this.nextIndex++;
+ this.oldIDs.push(finalID);
+ this.cmd("CreateLabel", finalID, this.tableVals[0][value], this.tableXPos[0][value] - 5, this.tableYPos[0][value] - 5, 0);
+ this.cmd("Move", finalID, DPChange.RECURSIVE_START_X, DPChange.RECURSIVE_START_Y);
+ this.cmd("Step");
+ this.cmd("SetText", finalID, "change(" + String(value) + ") = " + String(this.tableVals[0][value]));
+
+ this.displayCoinsUsed();
+
+ return this.commands;
+
+
+}
+
+
+
+DPChange.prototype.fibMem = function(value, xPos, ID)
+{
+ this.cmd("CreateLabel", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
+ this.cmd("SetHighlight", this.tableID[value], 1);
+ // TODO: Add an extra pause here?
+ this.cmd("Step");
+ if (this.tableVals[value] >= 0)
+ {
+ this.cmd("Delete", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
+ this.cmd("CreateLabel", ID, this.tableVals[value], this.tableXPos[value] - 5, this.tableYPos[value] - 5, 0);
+ this.cmd("Move", ID, xPos, this.currentY);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.tableID[value], 0);
+ return this.tableVals[value];
+ }
+ this.cmd("SetHighlight", this.tableID[value], 0);
+ this.currentY += DPChange.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
+ if (value > 1)
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_STANDARD_COLOR);
+ var firstValue = this.fibMem(value-1, xPos + DPChange.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPChange.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_STANDARD_COLOR);
+ var secondValue = this.fibMem(value-2, xPos + DPChange.RECURSIVE_DELTA_X, secondID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_RECURSIVE_1_COLOR);
+ this.cmd("SetForegroundColor", firstID, DPChange.CODE_RECURSIVE_1_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_RECURSIVE_2_COLOR);
+ this.cmd("SetForegroundColor", secondID, DPChange.CODE_RECURSIVE_2_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_STANDARD_COLOR);
+
+
+
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.cmd("SetText", ID, firstValue + secondValue);
+ this.cmd("Step");
+ this.tableVals[value] = firstValue + secondValue;
+ this.currentY = this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y;
+ this.cmd("CreateLabel", this.nextIndex, this.tableVals[value], xPos+5, this.currentY + 5);
+ this.cmd("Move", this.nextIndex, this.tableXPos[value], this.tableYPos[value], this.currentY);
+ this.cmd("Step");
+ this.cmd("Delete", this.nextIndex);
+ this.cmd("SetText", this.tableID[value], this.tableVals[value]);
+ return firstValue + secondValue;
+ }
+ else
+ {
+ this.cmd("SetText", ID, "1");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
+ this.tableVals[value] = 1;
+ this.cmd("CreateLabel", this.nextIndex, this.tableVals[value], xPos + 5, this.currentY + 5);
+ this.cmd("Move", this.nextIndex, this.tableXPos[value], this.tableYPos[value], this.currentY);
+ this.cmd("Step");
+ this.cmd("Delete", this.nextIndex);
+ this.cmd("SetText", this.tableID[value], this.tableVals[value]);
+
+ this.currentY -= DPChange.RECURSIVE_DELTA_Y;
+ return 1;
+ }
+
+}
+
+DPChange.prototype.memoizedChange = function(value)
+{
+ this.commands = [];
+
+ if (!this.usingDPCode)
+ {
+ this.setCodeAlpha(this.greedyCodeID, 0);
+ this.setCodeAlpha(this.codeID, 1);
+ this.usingDPCode = true;
+ }
+
+
+ this.clearOldIDs();
+ this.buildTable(value);
+
+ this.currentY = DPChange.RECURSIVE_START_Y;
+
+ var functionCallID = this.nextIndex++;
+ this.oldIDs.push(functionCallID);
+ var final = this.changeMem(value, DPChange.RECURSIVE_START_X, functionCallID);
+ this.cmd("SetText", functionCallID, "change(" + String(value)+ ", [" +String(DPChange.COINS[this.coinIndex]) +"]) = " + String(final[0]));
+ return this.commands;
+
+ this.currentY = DPChange.RECURSIVE_START_Y;
+
+ return this.commands;
+}
+
+
+
+DPChange.prototype.changeMem = function(value, xPos, ID)
+{
+ var coins = DPChange.COINS[this.coinIndex];
+ this.cmd("CreateLabel", ID, "change(" + String(value)+ ", [" +String(coins) +"])", xPos, this.currentY, 0);
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.tableID[0][value], 1);
+ this.cmd("Step");
+ if (this.tableVals[0][value] >= 0)
+ {
+ this.cmd("Delete", ID);
+ this.cmd("CreateLabel", ID, this.tableVals[0][value], this.tableXPos[0][value] - 5, this.tableYPos[0][value] - 5, 0);
+ this.cmd("Move", ID, xPos, this.currentY);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.tableID[0][value], 0);
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
+ return [this.tableVals[0][value], []];
+ }
+ this.cmd("SetHighlight", this.tableID[0][value], 0);
+ this.currentY += DPChange.RECURSIVE_DELTA_Y;
+
+
+
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
+ // return 1;
+ if (value > 0)
+ {
+ this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_STANDARD_COLOR);
+
+ var i;
+ var best = -1;
+ var nextID = this.nextIndex++;
+ var nextID2 = this.nextIndex++;
+ var recID = nextID;
+ var bestList;
+ for (i = 0; i < coins.length; i++)
+ {
+ this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_STANDARD_COLOR);
+ if (value >= coins[i])
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_STANDARD_COLOR);
+ var nextTry = this.changeMem(value - coins[i], xPos + DPChange.RECURSIVE_DELTA_X, recID);
+ // TODO: SOMEHTING ELSE HERE
+ if (best == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_STANDARD_COLOR);
+ best = nextTry[0] + 1;
+ bestList = nextTry[1];
+ bestList.push(coins[i]);;
+ this.currentY += DPChange.RECURSIVE_DELTA_Y;
+ recID = nextID2;
+ }
+ else if (best > nextTry[0] + 1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_STANDARD_COLOR);
+ best = nextTry[0] + 1;
+ bestList = nextTry[1];
+ bestList.push(coins[i]);;
+ this.cmd("Delete", recID);
+ this.cmd("SetText", nextID, String(best));
+ this.cmd("SetPosition", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
+ this.cmd("Move", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY - DPChange.RECURSIVE_DELTA_Y);
+ this.cmd("Step");
+ }
+ else
+ {
+ this.cmd("Step");
+ this.cmd("Delete", recID);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ this.cmd("Delete", nextID);
+ this.cmd("SetText", ID, String(best));
+ this.cmd("SetText", this.tableID[0][value], best);
+ this.cmd("SetText", this.tableID[1][value], bestList[0]);
+ this.tableVals[0][value] = best;
+ this.tableVals[1][value] = bestList[0];
+
+ this.cmd("SetPosition", ID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
+ this.cmd("Move", ID, xPos, this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y);
+
+
+ this.currentY = this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y;
+
+ this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("Step");
+ return [best, bestList];
+ }
+ else
+ {
+ this.cmd("SetText", ID, "0");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
+ this.cmd("SetText", this.tableID[0][value], 0);
+
+ this.currentY -= DPChange.RECURSIVE_DELTA_Y;
+ return [0, []];
+ }
+
+
+
+}
+
+
+
+DPChange.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+DPChange.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new DPChange(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPFib.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPFib.js
new file mode 100644
index 0000000..c216e60
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPFib.js
@@ -0,0 +1,522 @@
+// 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 ``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 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
+
+
+
+function DPFib(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+DPFib.prototype = new Algorithm();
+DPFib.prototype.constructor = DPFib;
+DPFib.superclass = Algorithm.prototype;
+
+DPFib.TABLE_ELEM_WIDTH = 40;
+DPFib.TABLE_ELEM_HEIGHT = 30;
+
+DPFib.TABLE_START_X = 500;
+DPFib.TABLE_START_Y = 40;
+DPFib.TABLE_DIFF_X = 100;
+
+DPFib.CODE_START_X = 10;
+DPFib.CODE_START_Y = 10;
+DPFib.CODE_LINE_HEIGHT = 14;
+
+DPFib.RECURSIVE_START_X = 20;
+DPFib.RECURSIVE_START_Y = 120;
+DPFib.RECURSIVE_DELTA_Y = 14;
+DPFib.RECURSIVE_DELTA_X = 15;
+DPFib.CODE_HIGHLIGHT_COLOR = "#FF0000";
+DPFib.CODE_STANDARD_COLOR = "#000000";
+
+DPFib.TABLE_INDEX_COLOR = "#0000FF"
+DPFib.CODE_RECURSIVE_1_COLOR = "#339933";
+DPFib.CODE_RECURSIVE_2_COLOR = "#0099FF";
+
+
+
+DPFib.MAX_VALUE = 20;
+
+DPFib.MESSAGE_ID = 0;
+
+DPFib.prototype.init = function(am, w, h)
+{
+ DPFib.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ this.code = [["def ","fib(n)",":"],
+ [" if ","(n <= 1) "],
+ [" return 1"],
+ [" else"],
+ [" return ", "fib(n-1)", " + ", "fib(n-2)"]];
+
+ this.codeID = Array(this.code.length);
+ var i, j;
+ for (i = 0; i < this.code.length; i++)
+ {
+ this.codeID[i] = new Array(this.code[i].length);
+ for (j = 0; j < this.code[i].length; j++)
+ {
+ this.codeID[i][j] = this.nextIndex++;
+ this.cmd("CreateLabel", this.codeID[i][j], this.code[i][j], DPFib.CODE_START_X, DPFib.CODE_START_Y + i * DPFib.CODE_LINE_HEIGHT, 0);
+ this.cmd("SetForegroundColor", this.codeID[i][j], DPFib.CODE_STANDARD_COLOR);
+ if (j > 0)
+ {
+ this.cmd("AlignRight", this.codeID[i][j], this.codeID[i][j-1]);
+ }
+ }
+
+
+ }
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+DPFib.prototype.addControls = function()
+{
+ this.controls = [];
+ this.fibField = addControlToAlgorithmBar("Text", "");
+ this.fibField.onkeydown = this.returnSubmit(this.fibField, this.emptyCallback.bind(this), 2, true);
+ this.controls.push(this.fibField);
+
+ this.recursiveButton = addControlToAlgorithmBar("Button", "Fibonacci Recursive");
+ this.recursiveButton.onclick = this.recursiveCallback.bind(this);
+ this.controls.push(this.recursiveButton);
+
+ this.tableButton = addControlToAlgorithmBar("Button", "Fibonacci Table");
+ this.tableButton.onclick = this.tableCallback.bind(this);
+ this.controls.push(this.tableButton);
+
+ this.memoizedButton = addControlToAlgorithmBar("Button", "Fibonacci Memoized");
+ this.memoizedButton.onclick = this.memoizedCallback.bind(this);
+ this.controls.push(this.memoizedButton);
+
+}
+
+
+
+DPFib.prototype.buildTable = function(maxVal)
+{
+ this.tableID = new Array(maxVal + 1);
+ this.tableVals = new Array(maxVal + 1);
+ this.tableXPos = new Array(maxVal + 1);
+ this.tableYPos = new Array(maxVal + 1);
+ var i;
+ var indexID;
+ var xPos;
+ var yPos;
+ var table_rows = Math.floor((this.canvasHeight - DPFib.TABLE_ELEM_HEIGHT - DPFib.TABLE_START_Y) / DPFib.TABLE_ELEM_HEIGHT);
+
+ for (i = 0; i <= maxVal; i++)
+ {
+ this.tableID[i] = this.nextIndex++;
+ this.tableVals[i] = -1;
+ this.oldIDs.push(this.tableID[i]);
+
+ yPos = i % table_rows * DPFib.TABLE_ELEM_HEIGHT + DPFib.TABLE_START_Y;
+ xPos = Math.floor(i / table_rows) * DPFib.TABLE_DIFF_X + DPFib.TABLE_START_X;
+
+ this.tableXPos[i] = xPos;
+ this.tableYPos[i] = yPos;
+
+ this.cmd("CreateRectangle", this.tableID[i],
+ "",
+ DPFib.TABLE_ELEM_WIDTH,
+ DPFib.TABLE_ELEM_HEIGHT,
+ xPos,
+ yPos);
+ indexID = this.nextIndex++;
+ this.oldIDs.push(indexID);
+ this.cmd("CreateLabel", indexID, i, xPos - DPFib.TABLE_ELEM_WIDTH, yPos);
+ this.cmd("SetForegroundColor", indexID, DPFib.TABLE_INDEX_COLOR);
+ }
+}
+
+DPFib.prototype.clearOldIDs = function()
+{
+ for (var i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+DPFib.prototype.reset = function()
+{
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+}
+
+
+
+DPFib.prototype.emptyCallback = function(event)
+{
+ this.implementAction(this.helpMessage.bind(this), "");
+ // TODO: Put up a message to push the appropriate button?
+
+}
+
+DPFib.prototype.recursiveCallback = function(event)
+{
+ var fibValue;
+
+ if (this.fibField.value != "")
+ {
+ var fibValue = Math.min(parseInt(this.fibField.value), DPFib.MAX_VALUE);
+ this.fibField.value = String(fibValue);
+ this.implementAction(this.recursiveFib.bind(this),fibValue);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+
+DPFib.prototype.tableCallback = function(event)
+{
+ var fibValue;
+
+ if (this.fibField.value != "")
+ {
+ var fibValue = Math.min(parseInt(this.fibField.value), DPFib.MAX_VALUE);
+ this.fibField.value = String(fibValue);
+ this.implementAction(this.tableFib.bind(this),fibValue);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+
+}
+
+
+DPFib.prototype.memoizedCallback = function(event)
+{
+ var fibValue;
+
+ if (this.fibField.value != "")
+ {
+ var fibValue = Math.min(parseInt(this.fibField.value), DPFib.MAX_VALUE);
+ this.fibField.value = String(fibValue);
+ this.implementAction(this.memoizedFib.bind(this),fibValue);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+DPFib.prototype.helpMessage = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ var messageID = this.nextIndex++;
+ this.oldIDs.push(messageID);
+ this.cmd("CreateLabel", messageID,
+ "Enter a value betweeen 0 and " + String(DPFib.MAX_VALUE) + " in the text field.\n" +
+ "Then press the Fibonacci Recursive, Fibonacci Table, or Fibonacci Memoized button",
+ DPFib.RECURSIVE_START_X, DPFib.RECURSIVE_START_Y, 0);
+ return this.commands;
+
+
+}
+
+
+DPFib.prototype.recursiveFib = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ this.currentY = DPFib.RECURSIVE_START_Y;
+
+ var functionCallID = this.nextIndex++;
+ this.oldIDs.push(functionCallID);
+ var final = this.fib(value, DPFib.RECURSIVE_START_X, functionCallID);
+ this.cmd("SetText", functionCallID, "fib(" + String(value) + ") = " + String(final));
+ return this.commands;
+}
+
+
+DPFib.prototype.fib = function(value, xPos, ID)
+{
+ this.cmd("CreateLabel", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
+ this.currentY += DPFib.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPFib.CODE_STANDARD_COLOR);
+ if (value > 1)
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_STANDARD_COLOR);
+ var firstValue = this.fib(value-1, xPos + DPFib.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPFib.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_STANDARD_COLOR);
+ var secondValue = this.fib(value-2, xPos + DPFib.RECURSIVE_DELTA_X, secondID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_RECURSIVE_1_COLOR);
+ this.cmd("SetForegroundColor", firstID, DPFib.CODE_RECURSIVE_1_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_RECURSIVE_2_COLOR);
+ this.cmd("SetForegroundColor", secondID, DPFib.CODE_RECURSIVE_2_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_STANDARD_COLOR);
+
+
+
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.cmd("SetText", ID, firstValue + secondValue);
+ this.cmd("Step");
+ this.currentY = this.currentY - 2 * DPFib.RECURSIVE_DELTA_Y;
+ return firstValue + secondValue;
+ }
+ else
+ {
+ this.cmd("SetText", ID, "1");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPFib.CODE_STANDARD_COLOR);
+
+ this.currentY -= DPFib.RECURSIVE_DELTA_Y;
+ return 1;
+ }
+
+
+
+}
+
+
+
+
+DPFib.prototype.tableFib = function(value)
+{
+ this.commands = [];
+ this.clearOldIDs();
+ this.buildTable(value);
+ var i;
+ for (i = 0; i <= value && i <= 1; i++)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.tableID[i], 1);
+ this.cmd("SetText", this.tableID[i], 1);
+ this.tableVals[i] = 1;
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i], 0);
+ }
+ for (i = 2; i <= value; i++)
+ {
+ this.cmd("SetHighlight", this.tableID[i-1], 1)
+ this.cmd("SetHighlight", this.tableID[i-2], 1)
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.tableVals[i] = this.tableVals[i-1] + this.tableVals[i-2];
+ this.cmd("SetText", this.tableID[i], this.tableVals[i]);
+ this.cmd("SetTextColor", this.tableID[i], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.tableID[i], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i-1], 0)
+ this.cmd("SetHighlight", this.tableID[i-2], 0)
+
+
+ }
+
+ var finalID = this.nextIndex++;
+ this.oldIDs.push(finalID);
+ this.cmd("CreateLabel", finalID, this.tableVals[value], this.tableXPos[value] - 5, this.tableYPos[value] - 5, 0);
+ this.cmd("Move", finalID, DPFib.RECURSIVE_START_X, DPFib.RECURSIVE_START_Y);
+ this.cmd("Step");
+ this.cmd("SetText", finalID, "fib(" + String(value) + ") = " + String(this.tableVals[value]));
+
+ return this.commands;
+
+
+}
+
+
+
+DPFib.prototype.fibMem = function(value, xPos, ID)
+{
+ this.cmd("CreateLabel", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
+ this.cmd("SetHighlight", this.tableID[value], 1);
+ // TODO: Add an extra pause here?
+ this.cmd("Step");
+ if (this.tableVals[value] >= 0)
+ {
+ this.cmd("Delete", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
+ this.cmd("CreateLabel", ID, this.tableVals[value], this.tableXPos[value] - 5, this.tableYPos[value] - 5, 0);
+ this.cmd("Move", ID, xPos, this.currentY);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.tableID[value], 0);
+ return this.tableVals[value];
+ }
+ this.cmd("SetHighlight", this.tableID[value], 0);
+ this.currentY += DPFib.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPFib.CODE_STANDARD_COLOR);
+ if (value > 1)
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_STANDARD_COLOR);
+ var firstValue = this.fibMem(value-1, xPos + DPFib.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPFib.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_STANDARD_COLOR);
+ var secondValue = this.fibMem(value-2, xPos + DPFib.RECURSIVE_DELTA_X, secondID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_RECURSIVE_1_COLOR);
+ this.cmd("SetForegroundColor", firstID, DPFib.CODE_RECURSIVE_1_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_RECURSIVE_2_COLOR);
+ this.cmd("SetForegroundColor", secondID, DPFib.CODE_RECURSIVE_2_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][2], DPFib.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][3], DPFib.CODE_STANDARD_COLOR);
+
+
+
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.cmd("SetText", ID, firstValue + secondValue);
+ this.cmd("Step");
+ this.tableVals[value] = firstValue + secondValue;
+ this.currentY = this.currentY - 2 * DPFib.RECURSIVE_DELTA_Y;
+ this.cmd("CreateLabel", this.nextIndex, this.tableVals[value], xPos+5, this.currentY + 5);
+ this.cmd("Move", this.nextIndex, this.tableXPos[value], this.tableYPos[value], this.currentY);
+ this.cmd("Step");
+ this.cmd("Delete", this.nextIndex);
+ this.cmd("SetText", this.tableID[value], this.tableVals[value]);
+ return firstValue + secondValue;
+ }
+ else
+ {
+ this.cmd("SetText", ID, "1");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPFib.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPFib.CODE_STANDARD_COLOR);
+ this.tableVals[value] = 1;
+ this.cmd("CreateLabel", this.nextIndex, this.tableVals[value], xPos + 5, this.currentY + 5);
+ this.cmd("Move", this.nextIndex, this.tableXPos[value], this.tableYPos[value], this.currentY);
+ this.cmd("Step");
+ this.cmd("Delete", this.nextIndex);
+ this.cmd("SetText", this.tableID[value], this.tableVals[value]);
+
+ this.currentY -= DPFib.RECURSIVE_DELTA_Y;
+ return 1;
+ }
+
+}
+
+DPFib.prototype.memoizedFib = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+ this.buildTable(value);
+
+ this.currentY = DPFib.RECURSIVE_START_Y;
+
+ var functionCallID = this.nextIndex++;
+ this.oldIDs.push(functionCallID);
+ var final = this.fibMem(value, DPFib.RECURSIVE_START_X, functionCallID);
+
+ this.cmd("SetText", functionCallID, "fib(" + String(value) + ") = " + String(final));
+ return this.commands;
+}
+
+DPFib.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+DPFib.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new DPFib(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPLCS.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPLCS.js
new file mode 100644
index 0000000..c2b2bf8
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPLCS.js
@@ -0,0 +1,829 @@
+// 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 ``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 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
+
+
+
+function DPLCS(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+DPLCS.prototype = new Algorithm();
+DPLCS.prototype.constructor = DPLCS;
+DPLCS.superclass = Algorithm.prototype;
+
+DPLCS.TABLE_ELEM_WIDTH = 40;
+DPLCS.TABLE_ELEM_HEIGHT = 30;
+
+DPLCS.TABLE_START_X = 500;
+DPLCS.TABLE_START_Y = 80;
+
+
+DPLCS.TABLE_DIFF_X = 100;
+
+DPLCS.CODE_START_X = 10;
+DPLCS.CODE_START_Y = 10;
+DPLCS.CODE_LINE_HEIGHT = 14;
+
+DPLCS.RECURSIVE_START_X = 20;
+DPLCS.RECURSIVE_START_Y = 120;
+DPLCS.RECURSIVE_DELTA_Y = 14;
+DPLCS.RECURSIVE_DELTA_X = 15;
+DPLCS.CODE_HIGHLIGHT_COLOR = "#FF0000";
+DPLCS.CODE_STANDARD_COLOR = "#000000";
+DPLCS.MAX_SEQUENCE_LENGTH = 15;
+
+DPLCS.TABLE_INDEX_COLOR = "#0000FF"
+DPLCS.CODE_RECURSIVE_1_COLOR = "#339933";
+DPLCS.CODE_RECURSIVE_2_COLOR = "#0099FF";
+
+DPLCS.SEQUENCE_START_X = 30;
+DPLCS.SEQUENCE_START_Y = 180;
+DPLCS.SEQUENCE_DELTA_X = 10;
+
+
+DPLCS.MAX_VALUE = 20;
+
+DPLCS.MESSAGE_ID = 0;
+
+DPLCS.prototype.init = function(am, w, h)
+{
+ DPLCS.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ this.code = [["def ","LCS(S1, S2, x, y)",":"],
+ [" if (","(x == -1) ", " or ", "(y == -1)", ")" ],
+ [" return 0"],
+ [" else if ", "(S1[x] == S2[y])"],
+ [" return 1 + ","LCS(S1, S2, x-1, y-1)"],
+ [" else"],
+ [" return max(", "LCS(S1, S2, x-1, y)", ",", "LCS(S1, S2, x, y-1)", ")"]];
+
+ this.codeID = Array(this.code.length);
+ var i, j;
+ for (i = 0; i < this.code.length; i++)
+ {
+ this.codeID[i] = new Array(this.code[i].length);
+ for (j = 0; j < this.code[i].length; j++)
+ {
+ this.codeID[i][j] = this.nextIndex++;
+ this.cmd("CreateLabel", this.codeID[i][j], this.code[i][j], DPLCS.CODE_START_X, DPLCS.CODE_START_Y + i * DPLCS.CODE_LINE_HEIGHT, 0);
+ this.cmd("SetForegroundColor", this.codeID[i][j], DPLCS.CODE_STANDARD_COLOR);
+ if (j > 0)
+ {
+ this.cmd("AlignRight", this.codeID[i][j], this.codeID[i][j-1]);
+ }
+ }
+
+
+ }
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+DPLCS.prototype.addControls = function()
+{
+ this.controls = [];
+ addLabelToAlgorithmBar("S1:");
+ this.S1Field = addControlToAlgorithmBar("Text", "");
+ this.S1Field.onkeydown = this.returnSubmit(this.S1Field, this.emptyCallback.bind(this), DPLCS.MAX_SEQUENCE_LENGTH, false);
+ this.controls.push(this.S1Field);
+
+ addLabelToAlgorithmBar("S2:");
+ this.S2Field = addControlToAlgorithmBar("Text", "");
+ this.S2Field.onkeydown = this.returnSubmit(this.S2Field, this.emptyCallback.bind(this), DPLCS.MAX_SEQUENCE_LENGTH, false);
+ this.controls.push(this.S2Field);
+
+ this.recursiveButton = addControlToAlgorithmBar("Button", "LCS Recursive");
+ this.recursiveButton.onclick = this.recursiveCallback.bind(this);
+ this.controls.push(this.recursiveButton);
+
+ this.tableButton = addControlToAlgorithmBar("Button", "LCS Table");
+ this.tableButton.onclick = this.tableCallback.bind(this);
+ this.controls.push(this.tableButton);
+
+ this.memoizedButton = addControlToAlgorithmBar("Button", "LCS Memoized");
+ this.memoizedButton.onclick = this.memoizedCallback.bind(this);
+ this.controls.push(this.memoizedButton);
+
+}
+
+
+
+DPLCS.prototype.buildTable = function(S1, S2)
+{
+ var x = S1.length;
+ var y = S2.length;
+ this.tableID = new Array(x+1);
+ this.tableVals = new Array(x + 1);
+ this.tableXPos = new Array(x + 1);
+ this.tableYPos = new Array(x + 1);
+
+ var i, j;
+ var sequence1ID = new Array(x);
+ var sequence2ID = new Array(y);
+
+ this.S1TableID = new Array(x);
+ for (i = 0; i <=x; i++)
+ {
+ if (i > 0)
+ {
+ this.S1TableID[i-1] = this.nextIndex++;
+ this.cmd("CreateLabel", this.S1TableID[i-1], S1.charAt(i-1),DPLCS.TABLE_START_X + i*DPLCS.TABLE_ELEM_WIDTH, DPLCS.TABLE_START_Y - 2 * DPLCS.TABLE_ELEM_HEIGHT);
+ this.oldIDs.push(this.S1TableID[i-1]);
+ }
+ var index = this.nextIndex++;
+ this.oldIDs.push(index);
+ this.cmd("CreateLabel", index, i - 1,DPLCS.TABLE_START_X + i*DPLCS.TABLE_ELEM_WIDTH, DPLCS.TABLE_START_Y - 1 * DPLCS.TABLE_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", index, "#0000FF");
+
+ }
+
+
+ this.S2TableID = new Array(y);
+ for (i = 0; i <=y; i++)
+ {
+ if (i > 0)
+ {
+ this.S2TableID[i-1] = this.nextIndex++;
+ this.cmd("CreateLabel", this.S2TableID[i-1], S2.charAt(i-1),DPLCS.TABLE_START_X - 2 * DPLCS.TABLE_ELEM_WIDTH, DPLCS.TABLE_START_Y + i * DPLCS.TABLE_ELEM_HEIGHT);
+ this.oldIDs.push(this.S2TableID[i-1]);
+ }
+ var index = this.nextIndex++;
+ this.oldIDs.push(index);
+ this.cmd("CreateLabel", index, i - 1, DPLCS.TABLE_START_X - 1 * DPLCS.TABLE_ELEM_WIDTH, DPLCS.TABLE_START_Y + i * DPLCS.TABLE_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", index, "#0000FF");
+ }
+
+
+ for (i = 0; i <= x; i++)
+ {
+ this.tableID[i] = new Array(y+1);
+ this.tableVals[i] =new Array(y+1);
+ this.tableXPos[i] = new Array(y+1);
+ this.tableYPos[i] = new Array(y+1);
+
+ for (j = 0; j <= y; j++)
+ {
+ this.tableID[i][j] = this.nextIndex++;
+ this.tableVals[i][j] = -1;
+ this.oldIDs.push(this.tableID[i][j]);
+
+ this.tableXPos[i][j] =DPLCS.TABLE_START_X + i * DPLCS.TABLE_ELEM_WIDTH;
+ this.tableYPos[i][j] = DPLCS.TABLE_START_Y + j * DPLCS.TABLE_ELEM_HEIGHT;
+
+ this.cmd("CreateRectangle", this.tableID[i][j],
+ "",
+ DPLCS.TABLE_ELEM_WIDTH,
+ DPLCS.TABLE_ELEM_HEIGHT,
+ this.tableXPos[i][j],
+ this.tableYPos[i][j]);
+
+ }
+
+ }
+}
+
+DPLCS.prototype.clearOldIDs = function()
+{
+ for (var i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+DPLCS.prototype.reset = function()
+{
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+}
+
+
+
+DPLCS.prototype.emptyCallback = function(event)
+{
+ this.implementAction(this.helpMessage.bind(this), "");
+ // TODO: Put up a message to push the appropriate button?
+
+}
+
+DPLCS.prototype.recursiveCallback = function(event)
+{
+ var fibValue;
+
+ if (this.S1Field.value != "" && this.S2Field.value != "" )
+ {
+ this.implementAction(this.recursiveLCS.bind(this),this.S1Field.value + ";" + this.S2Field.value);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+
+DPLCS.prototype.tableCallback = function(event)
+{
+ var fibValue;
+
+
+ if (this.S1Field.value != "" && this.S2Field.value != "" )
+ {
+ this.implementAction(this.tableLCS.bind(this),this.S1Field.value + ";" + this.S2Field.value);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+
+}
+
+
+DPLCS.prototype.memoizedCallback = function(event)
+{
+ var fibValue;
+
+
+ if (this.S1Field.value != "" && this.S2Field.value != "" )
+ {
+ this.implementAction(this.memoizedLCS.bind(this), this.S1Field.value + ";" + this.S2Field.value);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+
+}
+
+DPLCS.prototype.helpMessage = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ var messageID = this.nextIndex++;
+ this.oldIDs.push(messageID);
+ this.cmd("CreateLabel", messageID,
+ "Enter two sequences in the text fields.\n" +
+ "Then press the LCS Recursive, LCS Table, or LCS Memoized button",
+ DPLCS.RECURSIVE_START_X, DPLCS.RECURSIVE_START_Y, 0);
+ return this.commands;
+
+
+}
+
+
+DPLCS.prototype.recursiveLCS = function(value)
+{
+ this.commands = [];
+
+ var sequences=value.split(";");
+
+
+
+ this.clearOldIDs();
+
+ this.currentY = DPLCS.RECURSIVE_START_Y;
+
+ var functionCallID = this.nextIndex++;
+ this.oldIDs.push(functionCallID);
+ var final = this.LCS(sequences[0], sequences[1], sequences[0].length - 1, sequences[1].length - 1, DPLCS.RECURSIVE_START_X, functionCallID);
+ this.cmd("SetText", functionCallID, "LCS(" + sequences[0] + ", " + sequences[1] + ", " + String(sequences[0].length - 1) + ", " + String(sequences[1].length - 1) + ") = " + String(final));
+ return this.commands;
+}
+
+
+DPLCS.prototype.LCS = function(S1, S2, x, y, xPos, ID)
+{
+ var ID2 = this.nextIndex++;
+ this.cmd("CreateLabel", ID, "LCS(" + S1 + ", " + S2 + ", " + String(x) + ", "+ String(y) + ")", xPos, this.currentY, 0);
+ this.cmd("CreateLabel", ID2, " [LCS(" + S1.substring(0,x + 1)+ "," + S2.substring(0,y + 1) + ")]");
+ this.cmd("SetForegroundColor", ID2, "#3333FF");
+ this.cmd("AlignRight", ID2, ID);
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPLCS.CODE_STANDARD_COLOR);
+
+ if (x == -1 || y == -1)
+ {
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPLCS.CODE_HIGHLIGHT_COLOR);
+
+ }
+ this.cmd("Step");
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPLCS.CODE_STANDARD_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPLCS.CODE_STANDARD_COLOR);
+ }
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", ID, 0);
+ this.cmd("Delete", ID2);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPLCS.CODE_STANDARD_COLOR);
+ return 0;
+ }
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPLCS.CODE_STANDARD_COLOR);
+
+ if (S1.charAt(x) == S2.charAt(y))
+ {
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPLCS.CODE_STANDARD_COLOR);
+
+ var nextID = this.nextIndex++;
+ this.currentY += DPLCS.RECURSIVE_DELTA_Y;
+ var subProb = this.LCS(S1, S2, x-1, y-1, xPos + DPLCS.RECURSIVE_DELTA_X, nextID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPLCS.CODE_STANDARD_COLOR);
+
+
+ this.cmd("Delete", nextID);
+ this.cmd("SetText", ID, subProb + 1);
+ this.cmd("Delete", ID2);
+ this.cmd("step");
+ this.currentY -= DPLCS.RECURSIVE_DELTA_Y;
+ return subProb + 1
+ }
+ else
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.currentY += DPLCS.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_STANDARD_COLOR);
+
+ var subProb1 = this.LCS(S1, S2, x-1, y, xPos + DPLCS.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPLCS.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_STANDARD_COLOR);
+
+ var subProb2 = this.LCS(S1, S2, x, y-1, xPos + DPLCS.RECURSIVE_DELTA_X, secondID);
+
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.currentY -= 2*DPLCS.RECURSIVE_DELTA_Y;
+ var best = Math.max(subProb1, subProb2);
+ this.cmd("SetText", ID, best);
+ this.cmd("Delete", ID2);
+ this.cmd("step");
+ return best;
+ }
+}
+
+DPLCS.prototype.buildLCSFromTable = function(S1, S2)
+{
+ var currX = this.tableVals.length - 1;
+ var currY = this.tableVals[0].length - 1;
+
+ var sequence = [];
+
+ var header = this.nextIndex++;
+ this.oldIDs.push(header);
+ this.cmd("CreateLabel", header, "Sequence", DPLCS.SEQUENCE_START_X, DPLCS.SEQUENCE_START_Y - 30, 0);
+ this.cmd("SetForegroundColor", header, "#003300");
+
+ while (currX > 0 && currY > 0)
+ {
+ this.cmd("SetHighlight", this.tableID[currX][currY], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.S1TableID[currX-1], 1);
+ this.cmd("SetHighlight", this.S2TableID[currY-1], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.S1TableID[currX-1], 0);
+ this.cmd("SetHighlight", this.S2TableID[currY-1], 0);
+ this.cmd("SetHighlight", this.tableID[currX][currY], 0);
+
+ if (S1.charAt(currX - 1) == S2.charAt(currY - 1))
+ {
+ var nextSequenceID = this.nextIndex++;
+ this.oldIDs.push(nextSequenceID);
+ sequence.push(nextSequenceID);
+ this.cmd("CreateLabel", nextSequenceID, S1.charAt(currX - 1), DPLCS.TABLE_START_X + currX*DPLCS.TABLE_ELEM_WIDTH, DPLCS.TABLE_START_Y - 2 * DPLCS.TABLE_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextSequenceID, "#0000FF");
+
+ for (var i = sequence.length - 1; i >=0; i--)
+ {
+ this.cmd("Move", sequence[i], DPLCS.SEQUENCE_START_X + (sequence.length - 1 - i) * DPLCS.SEQUENCE_DELTA_X, DPLCS.SEQUENCE_START_Y);
+ }
+
+ currX = currX - 1;
+ currY = currY - 1;
+ }
+ else
+ {
+ this.cmd("SetHighlight", this.tableID[currX-1][currY], 1);
+ this.cmd("SetHighlight", this.tableID[currX][currY - 1], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.tableID[currX-1][currY], 0);
+ this.cmd("SetHighlight", this.tableID[currX][currY - 1], 0 );
+
+ if (this.tableVals[currX-1][currY] > this.tableVals[currX][currY - 1])
+ {
+ currX = currX - 1;
+ }
+ else
+ {
+ currY = currY - 1;
+
+ }
+ }
+
+ }
+
+
+
+}
+
+
+DPLCS.prototype.tableLCS = function(value)
+{
+ this.commands = [];
+ this.clearOldIDs();
+
+ var sequences=value.split(";");
+
+ this.buildTable(sequences[0], sequences[1]);
+
+ var moveID = this.nextIndex++;
+ var x = sequences[0].length;
+ var y = sequences[1].length;
+ var i, j;
+
+ for (i = 0; i <= x; i++)
+ {
+ this.cmd("SetText", this.tableID[i][0], "0");
+ this.tableVals[i][0] = 0;
+ }
+ for (i = 0; i <= y; i++)
+ {
+ this.cmd("SetText", this.tableID[0][i], "0");
+ this.tableVals[0][i] = 0;
+ }
+ this.cmd("Step");
+ for (j = 0; j < y; j++)
+ {
+ for (i = 0; i < x; i++)
+ {
+ this.cmd("SetHighlight", this.tableID[i+1][j+1], 1);
+ this.cmd("SetHighlight", this.S1TableID[i], 1);
+ this.cmd("SetHighlight", this.S2TableID[j], 1);
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.S1TableID[i], 0);
+ this.cmd("SetHighlight", this.S2TableID[j], 0);
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPLCS.CODE_STANDARD_COLOR);
+ if (sequences[0].charAt(i) == sequences[1].charAt(j))
+ {
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.tableID[i+1-1][j+1-1], 1);
+ this.cmd("Step");
+ this.cmd("CreateLabel", moveID, this.tableVals[i][j] + 1, this.tableXPos[i][j], this.tableYPos[i][j]);
+ this.cmd("Move", moveID, this.tableXPos[i+1][j+1], this.tableYPos[i+1][j+1]);
+ this.cmd("Step");
+ this.cmd("Delete", moveID);
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i+1-1][j+1-1], 0);
+ this.tableVals[i+1][j+1] = this.tableVals[i][j] + 1;
+ this.cmd("SetText", this.tableID[i+1][j+1], this.tableVals[i+1][j+1]);
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPLCS.CODE_HIGHLIGHT_COLOR);
+
+ this.cmd("SetHighlight", this.tableID[i][j+1], 1);
+ this.cmd("SetHighlight", this.tableID[i+1][j], 1);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPLCS.CODE_STANDARD_COLOR);
+
+ if (this.tableVals[i][j+1] > this.tableVals[i+1][j])
+ {
+ this.cmd("SetHighlight", this.tableID[i+1][j], 0);
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_STANDARD_COLOR);
+
+ this.tableVals[i+1][j+1] = this.tableVals[i][j+1];
+ this.cmd("CreateLabel", moveID, this.tableVals[i][j+1], this.tableXPos[i][j+1], this.tableYPos[i][j+1]);
+
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i][j+1], 0);
+ this.tableVals[i+1][j+1] = this.tableVals[i+1][j];
+ this.cmd("CreateLabel", moveID, this.tableVals[i+1][j], this.tableXPos[i+1][j], this.tableYPos[i+1][j]);
+ }
+ this.cmd("Move", moveID, this.tableXPos[i+1][j+1], this.tableYPos[i+1][j+1]);
+ this.cmd("Step");
+ this.cmd("SetText", this.tableID[i+1][j+1], this.tableVals[i+1][j+1]);
+ this.cmd("Delete", moveID);
+ if (this.tableVals[i][j+1] > this.tableVals[i+1][j])
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i][j+1], 0);
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i+1][j], 0);
+ }
+
+ }
+ this.cmd("SetHighlight", this.tableID[i+1][j+1], 0);
+ //this.cmd("Step");
+
+ }
+ }
+ this.buildLCSFromTable(sequences[0], sequences[1]);
+ return this.commands;
+}
+
+
+
+DPLCS.prototype.LCSMem = function(S1, S2, x, y, xPos, ID)
+{
+ var ID2 = this.nextIndex++;
+ this.cmd("CreateLabel", ID, "LCS(" + S1 + ", " + S2 + ", " + String(x) + ", "+ String(y) + ")", xPos, this.currentY, 0);
+ this.cmd("CreateLabel", ID2, " [LCS(" + S1.substring(0,x + 1)+ "," + S2.substring(0,y + 1) + ")]");
+ this.cmd("SetForegroundColor", ID2, "#3333FF");
+ this.cmd("AlignRight", ID2, ID);
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPLCS.CODE_STANDARD_COLOR);
+
+ if (this.tableVals[x+1][y+1] != -1)
+ {
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel, this.tableVals[x+1][y+1], this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Move", movingLabel, xPos, this.currentY);
+ this.cmd("SetText", ID, "");
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+
+ this.cmd("SetText", ID, this.tableVals[x+1][y+1]);
+ this.cmd("Delete", ID2);
+ this.cmd("Step");
+ return this.tableVals[x+1][y+1];
+ }
+
+
+ if (x == -1 || y == -1)
+ {
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPLCS.CODE_HIGHLIGHT_COLOR);
+
+ }
+ this.cmd("Step");
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPLCS.CODE_STANDARD_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPLCS.CODE_STANDARD_COLOR);
+ }
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", ID, 0);
+ this.cmd("Delete", ID2);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPLCS.CODE_STANDARD_COLOR);
+
+
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel,0, xPos, this.currentY);
+ this.cmd("Move", movingLabel, this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+ this.tableVals[x+1][y+1] = 0;
+ this.cmd("SetText", this.tableID[x+1][y+1], 0);
+
+
+ return 0;
+ }
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPLCS.CODE_STANDARD_COLOR);
+
+ if (S1.charAt(x) == S2.charAt(y))
+ {
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPLCS.CODE_STANDARD_COLOR);
+
+ var nextID = this.nextIndex++;
+ this.currentY += DPLCS.RECURSIVE_DELTA_Y;
+ var subProb = this.LCSMem(S1, S2, x-1, y-1, xPos + DPLCS.RECURSIVE_DELTA_X, nextID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPLCS.CODE_STANDARD_COLOR);
+
+
+ this.cmd("Delete", nextID);
+ this.cmd("SetText", ID, subProb + 1);
+ this.cmd("Delete", ID2);
+ this.cmd("step");
+ this.currentY -= DPLCS.RECURSIVE_DELTA_Y;
+
+ // TODO: Animate moving value into table here
+
+
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel, subProb + 1, xPos, this.currentY);
+ this.cmd("Move", movingLabel, this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+
+
+ this.tableVals[x+1][y+1] = subProb + 1;
+ this.cmd("SetText", this.tableID[x+1][y+1], subProb + 1);
+
+ return subProb + 1
+ }
+ else
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.currentY += DPLCS.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPLCS.CODE_STANDARD_COLOR);
+
+ var subProb1 = this.LCSMem(S1, S2, x-1, y, xPos + DPLCS.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPLCS.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPLCS.CODE_STANDARD_COLOR);
+
+ var subProb2 = this.LCSMem(S1, S2, x, y-1, xPos + DPLCS.RECURSIVE_DELTA_X, secondID);
+
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPLCS.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPLCS.CODE_STANDARD_COLOR);
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.currentY -= 2*DPLCS.RECURSIVE_DELTA_Y;
+ var best = Math.max(subProb1, subProb2);
+ this.cmd("SetText", ID, best);
+ this.cmd("Delete", ID2);
+
+
+
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel, best, xPos, this.currentY);
+ this.cmd("Move", movingLabel, this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+
+
+ // TODO: Animate moving value into table here
+ this.tableVals[x+1][y+1] = best;
+ this.cmd("SetText", this.tableID[x+1][y+1], best);
+
+
+
+ this.cmd("step");
+ return best;
+ }
+}
+
+
+DPLCS.prototype.memoizedLCS = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+ var sequences=value.split(";");
+
+ this.buildTable(sequences[0], sequences[1]);
+
+
+ var functionCallID = this.nextIndex++;
+ this.currentY = DPLCS.RECURSIVE_START_Y;
+
+ this.oldIDs.push(functionCallID);
+
+
+ var final = this.LCSMem(sequences[0], sequences[1], sequences[0].length - 1, sequences[1].length - 1, DPLCS.RECURSIVE_START_X, functionCallID);
+
+ this.cmd("SetText", functionCallID, "LCS(" + sequences[0] + ", " + sequences[1] + ", " + String(sequences[0].length - 1) + ", " + String(sequences[1].length - 1) + ") = " + String(final));
+
+
+ this.buildLCSFromTable(sequences[0], sequences[1]);
+
+ return this.commands;
+}
+
+DPLCS.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+DPLCS.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new DPLCS(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPMatrixMultiply.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPMatrixMultiply.js
new file mode 100644
index 0000000..68f97eb
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DPMatrixMultiply.js
@@ -0,0 +1,764 @@
+// 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 ``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 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
+
+
+
+function DPMatrixMultiply(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+DPMatrixMultiply.prototype = new Algorithm();
+DPMatrixMultiply.prototype.constructor = DPMatrixMultiply;
+DPMatrixMultiply.superclass = Algorithm.prototype;
+
+DPMatrixMultiply.TABLE_ELEM_WIDTH = 40;
+DPMatrixMultiply.TABLE_ELEM_HEIGHT = 30;
+
+DPMatrixMultiply.TABLE_START_X = 500;
+DPMatrixMultiply.TABLE_START_Y = 80;
+
+
+DPMatrixMultiply.TABLE_DIFF_X = 100;
+
+DPMatrixMultiply.CODE_START_X = 10;
+DPMatrixMultiply.CODE_START_Y = 10;
+DPMatrixMultiply.CODE_LINE_HEIGHT = 14;
+
+DPMatrixMultiply.RECURSIVE_START_X = 20;
+DPMatrixMultiply.RECURSIVE_START_Y = 120;
+DPMatrixMultiply.RECURSIVE_DELTA_Y = 14;
+DPMatrixMultiply.RECURSIVE_DELTA_X = 15;
+DPMatrixMultiply.CODE_HIGHLIGHT_COLOR = "#FF0000";
+DPMatrixMultiply.CODE_STANDARD_COLOR = "#000000";
+DPMatrixMultiply.MAX_SEQUENCE_LENGTH = 15;
+
+DPMatrixMultiply.TABLE_INDEX_COLOR = "#0000FF"
+DPMatrixMultiply.CODE_RECURSIVE_1_COLOR = "#339933";
+DPMatrixMultiply.CODE_RECURSIVE_2_COLOR = "#0099FF";
+
+
+
+DPMatrixMultiply.MAX_VALUE = 20;
+
+DPMatrixMultiply.MESSAGE_ID = 0;
+
+DPMatrixMultiply.prototype.init = function(am, w, h)
+{
+ DPMatrixMultiply.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ this.code = [["def ","MatrixMultiply(x, y, P)",":"],
+ [" if (","(x >= y)", ")" ],
+ [" return 0"],
+ [" best = -1"],
+ [" for i in range(x, y)"],
+ [" left = ", "MatrixMultiply(x, i, P)"],
+ [" right = ", "MatrixMultiply(i+1, y, P)"],
+ [" total = left + right + P[x] * P[i+1] * P[y]"],
+ [" if (", "best == -1", " or ", "best > total", ")"],
+ [" best = total"],
+ [" return best"]];
+
+ this.codeID = Array(this.code.length);
+ var i, j;
+ for (i = 0; i < this.code.length; i++)
+ {
+ this.codeID[i] = new Array(this.code[i].length);
+ for (j = 0; j < this.code[i].length; j++)
+ {
+ this.codeID[i][j] = this.nextIndex++;
+ this.cmd("CreateLabel", this.codeID[i][j], this.code[i][j], DPMatrixMultiply.CODE_START_X, DPMatrixMultiply.CODE_START_Y + i * DPMatrixMultiply.CODE_LINE_HEIGHT, 0);
+ this.cmd("SetForegroundColor", this.codeID[i][j], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ if (j > 0)
+ {
+ this.cmd("AlignRight", this.codeID[i][j], this.codeID[i][j-1]);
+ }
+ }
+
+
+ }
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+DPMatrixMultiply.prototype.addControls = function()
+{
+ this.controls = [];
+ addLabelToAlgorithmBar("S1:");
+ this.S1Field = addControlToAlgorithmBar("Text", "");
+ this.S1Field.onkeydown = this.returnSubmit(this.S1Field, this.emptyCallback.bind(this), DPMatrixMultiply.MAX_SEQUENCE_LENGTH, false);
+ this.controls.push(this.S1Field);
+
+ addLabelToAlgorithmBar("S2:");
+ this.S2Field = addControlToAlgorithmBar("Text", "");
+ this.S2Field.onkeydown = this.returnSubmit(this.S2Field, this.emptyCallback.bind(this), DPMatrixMultiply.MAX_SEQUENCE_LENGTH, false);
+ this.controls.push(this.S2Field);
+
+ this.recursiveButton = addControlToAlgorithmBar("Button", "LCS Recursive");
+ this.recursiveButton.onclick = this.recursiveCallback.bind(this);
+ this.controls.push(this.recursiveButton);
+
+ this.tableButton = addControlToAlgorithmBar("Button", "LCS Table");
+ this.tableButton.onclick = this.tableCallback.bind(this);
+ this.controls.push(this.tableButton);
+
+ this.memoizedButton = addControlToAlgorithmBar("Button", "LCS Memoized");
+ this.memoizedButton.onclick = this.memoizedCallback.bind(this);
+ this.controls.push(this.memoizedButton);
+
+}
+
+
+
+DPMatrixMultiply.prototype.buildTable = function(S1, S2)
+{
+ var x = S1.length;
+ var y = S2.length;
+ this.tableID = new Array(x+1);
+ this.tableVals = new Array(x + 1);
+ this.tableXPos = new Array(x + 1);
+ this.tableYPos = new Array(x + 1);
+
+ var i, j;
+ var sequence1ID = new Array(x);
+ var sequence2ID = new Array(y);
+
+ this.S1TableID = new Array(x);
+ for (i = 0; i <=x; i++)
+ {
+ if (i > 0)
+ {
+ this.S1TableID[i-1] = this.nextIndex++;
+ this.cmd("CreateLabel", this.S1TableID[i-1], S1.charAt(i-1),DPMatrixMultiply.TABLE_START_X + i*DPMatrixMultiply.TABLE_ELEM_WIDTH, DPMatrixMultiply.TABLE_START_Y - 2 * DPMatrixMultiply.TABLE_ELEM_HEIGHT);
+ this.oldIDs.push(this.S1TableID[i-1]);
+ }
+ var index = this.nextIndex++;
+ this.oldIDs.push(index);
+ this.cmd("CreateLabel", index, i - 1,DPMatrixMultiply.TABLE_START_X + i*DPMatrixMultiply.TABLE_ELEM_WIDTH, DPMatrixMultiply.TABLE_START_Y - 1 * DPMatrixMultiply.TABLE_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", index, "#0000FF");
+
+ }
+
+
+ this.S2TableID = new Array(y);
+ for (i = 0; i <=y; i++)
+ {
+ if (i > 0)
+ {
+ this.S2TableID[i-1] = this.nextIndex++;
+ this.cmd("CreateLabel", this.S2TableID[i-1], S2.charAt(i-1),DPMatrixMultiply.TABLE_START_X - 2 * DPMatrixMultiply.TABLE_ELEM_WIDTH, DPMatrixMultiply.TABLE_START_Y + i * DPMatrixMultiply.TABLE_ELEM_HEIGHT);
+ this.oldIDs.push(this.S2TableID[i-1]);
+ }
+ var index = this.nextIndex++;
+ this.oldIDs.push(index);
+ this.cmd("CreateLabel", index, i - 1, DPMatrixMultiply.TABLE_START_X - 1 * DPMatrixMultiply.TABLE_ELEM_WIDTH, DPMatrixMultiply.TABLE_START_Y + i * DPMatrixMultiply.TABLE_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", index, "#0000FF");
+ }
+
+
+ for (i = 0; i <= x; i++)
+ {
+ this.tableID[i] = new Array(y+1);
+ this.tableVals[i] =new Array(y+1);
+ this.tableXPos[i] = new Array(y+1);
+ this.tableYPos[i] = new Array(y+1);
+
+ for (j = 0; j <= y; j++)
+ {
+ this.tableID[i][j] = this.nextIndex++;
+ this.tableVals[i][j] = -1;
+ this.oldIDs.push(this.tableID[i][j]);
+
+ this.tableXPos[i][j] =DPMatrixMultiply.TABLE_START_X + i * DPMatrixMultiply.TABLE_ELEM_WIDTH;
+ this.tableYPos[i][j] = DPMatrixMultiply.TABLE_START_Y + j * DPMatrixMultiply.TABLE_ELEM_HEIGHT;
+
+ this.cmd("CreateRectangle", this.tableID[i][j],
+ "",
+ DPMatrixMultiply.TABLE_ELEM_WIDTH,
+ DPMatrixMultiply.TABLE_ELEM_HEIGHT,
+ this.tableXPos[i][j],
+ this.tableYPos[i][j]);
+
+ }
+
+ }
+}
+
+DPMatrixMultiply.prototype.clearOldIDs = function()
+{
+ for (var i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+DPMatrixMultiply.prototype.reset = function()
+{
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+}
+
+
+
+DPMatrixMultiply.prototype.emptyCallback = function(event)
+{
+ this.implementAction(this.helpMessage.bind(this), "");
+ // TODO: Put up a message to push the appropriate button?
+
+}
+
+DPMatrixMultiply.prototype.recursiveCallback = function(event)
+{
+ var fibValue;
+
+ if (this.S1Field.value != "" && this.S2Field.value != "" )
+ {
+ this.implementAction(this.recursiveLCS.bind(this),this.S1Field.value + ";" + this.S2Field.value);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+}
+
+
+DPMatrixMultiply.prototype.tableCallback = function(event)
+{
+ var fibValue;
+
+
+ if (this.S1Field.value != "" && this.S2Field.value != "" )
+ {
+ this.implementAction(this.tableLCS.bind(this),this.S1Field.value + ";" + this.S2Field.value);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+
+}
+
+
+DPMatrixMultiply.prototype.memoizedCallback = function(event)
+{
+ var fibValue;
+
+
+ if (this.S1Field.value != "" && this.S2Field.value != "" )
+ {
+ this.implementAction(this.memoizedLCS.bind(this), this.S1Field.value + ";" + this.S2Field.value);
+ }
+ else
+ {
+ this.implementAction(this.helpMessage.bind(this), "");
+ }
+
+}
+
+DPMatrixMultiply.prototype.helpMessage = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ var messageID = this.nextIndex++;
+ this.oldIDs.push(messageID);
+ this.cmd("CreateLabel", messageID,
+ "Enter two sequences in the text fields.\n" +
+ "Then press the LCS Recursive, LCS Table, or LCS Memoized button",
+ DPMatrixMultiply.RECURSIVE_START_X, DPMatrixMultiply.RECURSIVE_START_Y, 0);
+ return this.commands;
+
+
+}
+
+
+DPMatrixMultiply.prototype.recursiveLCS = function(value)
+{
+ this.commands = [];
+
+ var sequences=value.split(";");
+
+
+
+ this.clearOldIDs();
+
+ this.currentY = DPMatrixMultiply.RECURSIVE_START_Y;
+
+ var functionCallID = this.nextIndex++;
+ this.oldIDs.push(functionCallID);
+ var final = this.LCS(sequences[0], sequences[1], sequences[0].length - 1, sequences[1].length - 1, DPMatrixMultiply.RECURSIVE_START_X, functionCallID);
+ this.cmd("SetText", functionCallID, "LCS(" + sequences[0] + ", " + sequences[1] + ", " + String(sequences[0].length - 1) + ", " + String(sequences[1].length - 1) + ") = " + String(final));
+ return this.commands;
+}
+
+
+DPMatrixMultiply.prototype.LCS = function(S1, S2, x, y, xPos, ID)
+{
+ var ID2 = this.nextIndex++;
+ this.cmd("CreateLabel", ID, "LCS(" + S1 + ", " + S2 + ", " + String(x) + ", "+ String(y) + ")", xPos, this.currentY, 0);
+ this.cmd("CreateLabel", ID2, " [LCS(" + S1.substring(0,x + 1)+ "," + S2.substring(0,y + 1) + ")]");
+ this.cmd("SetForegroundColor", ID2, "#3333FF");
+ this.cmd("AlignRight", ID2, ID);
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ if (x == -1 || y == -1)
+ {
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+
+ }
+ this.cmd("Step");
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ }
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", ID, 0);
+ this.cmd("Delete", ID2);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ return 0;
+ }
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ if (S1.charAt(x) == S2.charAt(y))
+ {
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ var nextID = this.nextIndex++;
+ this.currentY += DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ var subProb = this.LCS(S1, S2, x-1, y-1, xPos + DPMatrixMultiply.RECURSIVE_DELTA_X, nextID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+
+ this.cmd("Delete", nextID);
+ this.cmd("SetText", ID, subProb + 1);
+ this.cmd("Delete", ID2);
+ this.cmd("step");
+ this.currentY -= DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ return subProb + 1
+ }
+ else
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.currentY += DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ var subProb1 = this.LCS(S1, S2, x-1, y, xPos + DPMatrixMultiply.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ var subProb2 = this.LCS(S1, S2, x, y-1, xPos + DPMatrixMultiply.RECURSIVE_DELTA_X, secondID);
+
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.currentY -= 2*DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ var best = Math.max(subProb1, subProb2);
+ this.cmd("SetText", ID, best);
+ this.cmd("Delete", ID2);
+ this.cmd("step");
+ return best;
+ }
+}
+
+
+
+
+DPMatrixMultiply.prototype.tableLCS = function(value)
+{
+ this.commands = [];
+ this.clearOldIDs();
+
+ var sequences=value.split(";");
+
+ this.buildTable(sequences[0], sequences[1]);
+
+ var moveID = this.nextIndex++;
+ var x = sequences[0].length;
+ var y = sequences[1].length;
+ var i, j;
+
+ for (i = 0; i <= x; i++)
+ {
+ this.cmd("SetText", this.tableID[i][0], "0");
+ this.tableVals[i][0] = 0;
+ }
+ for (i = 0; i <= y; i++)
+ {
+ this.cmd("SetText", this.tableID[0][i], "0");
+ this.tableVals[0][i] = 0;
+ }
+ this.cmd("Step");
+ for (j = 0; j < y; j++)
+ {
+ for (i = 0; i < x; i++)
+ {
+ this.cmd("SetHighlight", this.tableID[i+1][j+1], 1);
+ this.cmd("SetHighlight", this.S1TableID[i], 1);
+ this.cmd("SetHighlight", this.S2TableID[j], 1);
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.S1TableID[i], 0);
+ this.cmd("SetHighlight", this.S2TableID[j], 0);
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ if (sequences[0].charAt(i) == sequences[1].charAt(j))
+ {
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.tableID[i+1-1][j+1-1], 1);
+ this.cmd("Step");
+ this.cmd("CreateLabel", moveID, this.tableVals[i][j] + 1, this.tableXPos[i][j], this.tableYPos[i][j]);
+ this.cmd("Move", moveID, this.tableXPos[i+1][j+1], this.tableYPos[i+1][j+1]);
+ this.cmd("Step");
+ this.cmd("Delete", moveID);
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i+1-1][j+1-1], 0);
+ this.tableVals[i+1][j+1] = this.tableVals[i][j] + 1;
+ this.cmd("SetText", this.tableID[i+1][j+1], this.tableVals[i+1][j+1]);
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+
+ this.cmd("SetHighlight", this.tableID[i][j+1], 1);
+ this.cmd("SetHighlight", this.tableID[i+1][j], 1);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ if (this.tableVals[i][j+1] > this.tableVals[i+1][j])
+ {
+ this.cmd("SetHighlight", this.tableID[i+1][j], 0);
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ this.tableVals[i+1][j+1] = this.tableVals[i][j+1];
+ this.cmd("CreateLabel", moveID, this.tableVals[i][j+1], this.tableXPos[i][j+1], this.tableYPos[i][j+1]);
+
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i][j+1], 0);
+ this.tableVals[i+1][j+1] = this.tableVals[i+1][j];
+ this.cmd("CreateLabel", moveID, this.tableVals[i+1][j], this.tableXPos[i+1][j], this.tableYPos[i+1][j]);
+ }
+ this.cmd("Move", moveID, this.tableXPos[i+1][j+1], this.tableYPos[i+1][j+1]);
+ this.cmd("Step");
+ this.cmd("SetText", this.tableID[i+1][j+1], this.tableVals[i+1][j+1]);
+ this.cmd("Delete", moveID);
+ if (this.tableVals[i][j+1] > this.tableVals[i+1][j])
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i][j+1], 0);
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.tableID[i+1][j], 0);
+ }
+
+ }
+ this.cmd("SetHighlight", this.tableID[i+1][j+1], 0);
+ //this.cmd("Step");
+
+ }
+ }
+ return this.commands;
+}
+
+
+
+DPMatrixMultiply.prototype.LCSMem = function(S1, S2, x, y, xPos, ID)
+{
+ var ID2 = this.nextIndex++;
+ this.cmd("CreateLabel", ID, "LCS(" + S1 + ", " + S2 + ", " + String(x) + ", "+ String(y) + ")", xPos, this.currentY, 0);
+ this.cmd("CreateLabel", ID2, " [LCS(" + S1.substring(0,x + 1)+ "," + S2.substring(0,y + 1) + ")]");
+ this.cmd("SetForegroundColor", ID2, "#3333FF");
+ this.cmd("AlignRight", ID2, ID);
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ if (this.tableVals[x+1][y+1] != -1)
+ {
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel, this.tableVals[x+1][y+1], this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Move", movingLabel, xPos, this.currentY);
+ this.cmd("SetText", ID, "");
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+
+ this.cmd("SetText", ID, this.tableVals[x+1][y+1]);
+ this.cmd("Delete", ID2);
+ this.cmd("Step");
+ return this.tableVals[x+1][y+1];
+ }
+
+
+ if (x == -1 || y == -1)
+ {
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+
+ }
+ this.cmd("Step");
+ if (x == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ }
+ if (y == -1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[1][3], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ }
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", ID, 0);
+ this.cmd("Delete", ID2);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel,0, xPos, this.currentY);
+ this.cmd("Move", movingLabel, this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+ this.tableVals[x+1][y+1] = 0;
+ this.cmd("SetText", this.tableID[x+1][y+1], 0);
+
+
+ return 0;
+ }
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[3][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ if (S1.charAt(x) == S2.charAt(y))
+ {
+
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ var nextID = this.nextIndex++;
+ this.currentY += DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ var subProb = this.LCSMem(S1, S2, x-1, y-1, xPos + DPMatrixMultiply.RECURSIVE_DELTA_X, nextID);
+
+
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+
+ this.cmd("Delete", nextID);
+ this.cmd("SetText", ID, subProb + 1);
+ this.cmd("Delete", ID2);
+ this.cmd("step");
+ this.currentY -= DPMatrixMultiply.RECURSIVE_DELTA_Y;
+
+ // TODO: Animate moving value into table here
+
+
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel, subProb + 1, xPos, this.currentY);
+ this.cmd("Move", movingLabel, this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+
+
+ this.tableVals[x+1][y+1] = subProb + 1;
+ this.cmd("SetText", this.tableID[x+1][y+1], subProb + 1);
+
+ return subProb + 1
+ }
+ else
+ {
+ var firstID = this.nextIndex++;
+ var secondID = this.nextIndex++;
+ this.currentY += DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][1], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ var subProb1 = this.LCSMem(S1, S2, x-1, y, xPos + DPMatrixMultiply.RECURSIVE_DELTA_X, firstID);
+ this.currentY += DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][3], DPMatrixMultiply.CODE_STANDARD_COLOR);
+
+ var subProb2 = this.LCSMem(S1, S2, x, y-1, xPos + DPMatrixMultiply.RECURSIVE_DELTA_X, secondID);
+
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPMatrixMultiply.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][2], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][4], DPMatrixMultiply.CODE_STANDARD_COLOR);
+ this.cmd("Delete", firstID);
+ this.cmd("Delete", secondID);
+ this.currentY -= 2*DPMatrixMultiply.RECURSIVE_DELTA_Y;
+ var best = Math.max(subProb1, subProb2);
+ this.cmd("SetText", ID, best);
+ this.cmd("Delete", ID2);
+
+
+
+ var movingLabel = this.nextIndex++;
+ this.cmd("CreateLabel", movingLabel, best, xPos, this.currentY);
+ this.cmd("Move", movingLabel, this.tableXPos[x+1][y+1], this.tableYPos[x+1][y+1]);
+ this.cmd("Step");
+ this.cmd("Delete", movingLabel);
+
+
+
+ // TODO: Animate moving value into table here
+ this.tableVals[x+1][y+1] = best;
+ this.cmd("SetText", this.tableID[x+1][y+1], best);
+
+
+
+ this.cmd("step");
+ return best;
+ }
+}
+
+
+DPMatrixMultiply.prototype.memoizedLCS = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+ var sequences=value.split(";");
+
+ this.buildTable(sequences[0], sequences[1]);
+
+
+ var functionCallID = this.nextIndex++;
+ this.currentY = DPMatrixMultiply.RECURSIVE_START_Y;
+
+ this.oldIDs.push(functionCallID);
+
+
+ var final = this.LCSMem(sequences[0], sequences[1], sequences[0].length - 1, sequences[1].length - 1, DPMatrixMultiply.RECURSIVE_START_X, functionCallID);
+
+ this.cmd("SetText", functionCallID, "LCS(" + sequences[0] + ", " + sequences[1] + ", " + String(sequences[0].length - 1) + ", " + String(sequences[1].length - 1) + ") = " + String(final));
+
+ return this.commands;
+}
+
+DPMatrixMultiply.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+DPMatrixMultiply.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new DPMatrixMultiply(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DijkstraPrim.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DijkstraPrim.js
new file mode 100644
index 0000000..a3d65b4
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DijkstraPrim.js
@@ -0,0 +1,433 @@
+// 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 ``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 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 TABLE_ENTRY_WIDTH = 50;
+var TABLE_ENTRY_HEIGHT = 25;
+var TABLE_START_X = 50;
+var TABLE_START_Y = 80;
+
+var MESSAGE_LABEL_1_X = 20;
+var MESSAGE_LABEL_1_Y = 10;
+
+
+
+var HIGHLIGHT_CIRCLE_COLOR = "#000000";
+
+
+
+function DijkstraPrim(am, runningDijkstra, w, h)
+{
+ this.init(am, runningDijkstra, w, h);
+
+}
+
+DijkstraPrim.prototype = new Graph();
+DijkstraPrim.prototype.constructor = DijkstraPrim;
+DijkstraPrim.superclass = Graph.prototype;
+
+DijkstraPrim.prototype.addControls = function()
+{
+ addLabelToAlgorithmBar("Start Vertex: ");
+ this.startField = addControlToAlgorithmBar("Text", "");
+ this.startField.onkeydown = this.returnSubmit(this.startField, this.startCallback.bind(this), 2, true);
+ this.startField.size = 2
+ if (this.runningDijkstra)
+ {
+ this.startButton = addControlToAlgorithmBar("Button", "Run Dijkstra");
+
+ }
+ else
+ {
+ this.startButton = addControlToAlgorithmBar("Button", "Run Prim");
+
+ }
+ this.startButton.onclick = this.startCallback.bind(this);
+ DijkstraPrim.superclass.addControls.call(this, this.runningDijkstra);
+}
+
+
+DijkstraPrim.prototype.init = function(am, runningDijkstra, w, h)
+{
+ this.runningDijkstra = runningDijkstra;
+ this.showEdgeCosts = true;
+ DijkstraPrim.superclass.init.call(this, am, w, h, false, false); // TODO: add no edge label flag to this?
+ // Setup called in base class init function
+}
+
+
+DijkstraPrim.prototype.setup = function()
+{
+ this.message1ID = this.nextIndex++;
+ DijkstraPrim.superclass.setup.call(this);
+
+ this.commands = new Array();
+ this.cmd("CreateLabel", this.message1ID, "", MESSAGE_LABEL_1_X, MESSAGE_LABEL_1_Y, 0);
+
+
+ this.vertexID = new Array(this.size);
+ this.knownID = new Array(this.size);
+ this.distanceID = new Array(this.size);
+ this.pathID = new Array(this.size);
+ this.known = new Array(this.size);
+ this.distance = new Array(this.size);
+ this.path = new Array(this.size);
+
+ this.messageID = null;
+
+ for (var i = 0; i < this.size; i++)
+ {
+ this.vertexID[i] = this.nextIndex++;
+ this.knownID[i] = this.nextIndex++;
+ this.distanceID[i] = this.nextIndex++;
+ this.pathID[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.vertexID[i], i, TABLE_ENTRY_WIDTH, TABLE_ENTRY_HEIGHT, TABLE_START_X, TABLE_START_Y + i*TABLE_ENTRY_HEIGHT);
+ this.cmd("CreateRectangle", this.knownID[i], "", TABLE_ENTRY_WIDTH, TABLE_ENTRY_HEIGHT, TABLE_START_X + TABLE_ENTRY_WIDTH, TABLE_START_Y + i*TABLE_ENTRY_HEIGHT);
+ this.cmd("CreateRectangle", this.distanceID[i], "", TABLE_ENTRY_WIDTH, TABLE_ENTRY_HEIGHT, TABLE_START_X + 2 * TABLE_ENTRY_WIDTH, TABLE_START_Y + i*TABLE_ENTRY_HEIGHT);
+ this.cmd("CreateRectangle", this.pathID[i], "", TABLE_ENTRY_WIDTH, TABLE_ENTRY_HEIGHT, TABLE_START_X+ 3 * TABLE_ENTRY_WIDTH, TABLE_START_Y + i*TABLE_ENTRY_HEIGHT);
+ this.cmd("SetTextColor", this.vertexID[i], VERTEX_INDEX_COLOR);
+
+ }
+ this.cmd("CreateLabel", this.nextIndex++, "Vertex", TABLE_START_X, TABLE_START_Y - TABLE_ENTRY_HEIGHT);
+ this.cmd("CreateLabel", this.nextIndex++, "Known", TABLE_START_X + TABLE_ENTRY_WIDTH, TABLE_START_Y - TABLE_ENTRY_HEIGHT);
+ this.cmd("CreateLabel", this.nextIndex++, "Cost", TABLE_START_X + 2 * TABLE_ENTRY_WIDTH, TABLE_START_Y - TABLE_ENTRY_HEIGHT);
+ this.cmd("CreateLabel", this.nextIndex++, "Path", TABLE_START_X + 3 * TABLE_ENTRY_WIDTH, TABLE_START_Y - TABLE_ENTRY_HEIGHT);
+
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.comparisonMessageID = this.nextIndex++;
+}
+
+
+
+DijkstraPrim.prototype.findCheapestUnknown = function()
+{
+ var bestIndex = -1;
+ this.cmd("SetText", this.message1ID,"Finding Cheapest Uknown Vertex");
+
+ for (var i = 0; i < this.size; i++)
+ {
+ if (!this.known[i])
+ {
+ this.cmd("SetHighlight", this.distanceID[i], 1);
+ }
+
+ if (!this.known[i] && this.distance[i] != -1 && (bestIndex == -1 ||
+ (this.distance[i] < this.distance[bestIndex])))
+ {
+ bestIndex = i;
+ }
+ }
+ if (bestIndex == -1)
+ {
+ var x = 3;
+ x = x + 2;
+ }
+ this.cmd("Step");
+ for (var i = 0; i < this.size; i++)
+ {
+ if (!this.known[i])
+ {
+ this.cmd("SetHighlight", this.distanceID[i], 0);
+ }
+
+ }
+ return bestIndex;
+}
+
+
+DijkstraPrim.prototype.doDijkstraPrim = function(startVertex)
+{
+ this.commands = new Array();
+
+ if (!this.runningDijkstra)
+ {
+ this.recolorGraph();
+ }
+
+
+ var current = parseInt(startVertex);
+
+ for (var i = 0; i < this.size; i++)
+ {
+ this.known[i] = false;
+ this.distance[i] = -1;
+ this.path[i] = -1;
+ this.cmd("SetText", this.knownID[i], "F");
+ this.cmd("SetText", this.distanceID[i], "INF");
+ this.cmd("SetText", this.pathID[i], "-1");
+ this.cmd("SetTextColor", this.knownID[i], "#000000");
+
+ }
+ if (this.messageID != null)
+ {
+ for (i = 0; i < this.messageID.length; i++)
+ {
+ this.cmd("Delete", this.messageID[i]);
+ }
+ }
+ this.messageID = new Array();
+
+ this.distance[current] = 0;
+ this.cmd("SetText", this.distanceID[current], 0);
+
+ for (i = 0; i < this.size; i++)
+ {
+ current = this.findCheapestUnknown();
+ if (current < 0)
+ {
+ break;
+ }
+ this.cmd("SetText",this.message1ID, "Cheapest Unknown Vertex: " + current); // Gotta love Auto Conversion
+ this.cmd("SetHighlight", this.distanceID[current], 1);
+
+ this.cmd("SetHighlight", this.circleID[current], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.distanceID[current], 0);
+ this.cmd("SetText", this.message1ID,"Setting known field to True");
+ this.cmd("SetHighlight", this.knownID[current], 1);
+ this.known[current] = true;
+ this.cmd("SetText", this.knownID[current], "T");
+ this.cmd("SetTextColor", this.knownID[current], "#AAAAAA");
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.knownID[current], 0);
+ this.cmd("SetText",this.message1ID, "Updating neighbors of vertex " + current); // Gotta love Auto Conversion
+ for (var neighbor = 0; neighbor < this.size; neighbor++)
+ {
+ if (this.adj_matrix[current][neighbor] >= 0)
+ {
+ this.highlightEdge(current, neighbor, 1);
+ if (this.known[neighbor])
+ {
+
+ this.cmd("CreateLabel", this.comparisonMessageID,"Vertex " + String(neighbor) + " known",
+ TABLE_START_X + 5 * TABLE_ENTRY_WIDTH,TABLE_START_Y + neighbor*TABLE_ENTRY_HEIGHT);
+ this.cmd("SetHighlight", this.knownID[neighbor], 1);
+ }
+ else
+ { this.cmd("SetHighlight", this.distanceID[current], 1);
+ this.cmd("SetHighlight", this.distanceID[neighbor], 1);
+ var distString = String(this.distance[neighbor]);
+ if (this.distance[neighbor] < 0)
+ {
+ distString = "INF";
+ }
+
+ if (this.runningDijkstra)
+ {
+ if (this.distance[neighbor] < 0 || this.distance[neighbor] > this.distance[current] + this.adj_matrix[current][neighbor])
+ {
+ this.cmd("CreateLabel", this.comparisonMessageID, distString + " > " + String(this.distance[current]) + " + " + String(this.adj_matrix[current][neighbor]),
+ TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + neighbor*TABLE_ENTRY_HEIGHT);
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.comparisonMessageID,"!(" + String(this.distance[neighbor]) + " > " + String(this.distance[current]) + " + " + String(this.adj_matrix[current][neighbor]) + ")",
+ TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + neighbor*TABLE_ENTRY_HEIGHT);
+ }
+
+ }
+ else
+ {
+ if (this.distance[neighbor] < 0 || this.distance[neighbor] > this.adj_matrix[current][neighbor])
+ {
+ this.cmd("CreateLabel", this.comparisonMessageID, distString + " > " + String(this.adj_matrix[current][neighbor]),
+ TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + neighbor*TABLE_ENTRY_HEIGHT);
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.comparisonMessageID,"!(" + String(this.distance[neighbor]) + " > " + String(this.adj_matrix[current][neighbor]) + ")",
+ TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + neighbor*TABLE_ENTRY_HEIGHT);
+ }
+
+
+ }
+
+
+ }
+
+ this.cmd("Step");
+ this.cmd("Delete", this.comparisonMessageID);
+ this.highlightEdge(current, neighbor, 0);
+ if (this.known[neighbor])
+ {
+ this.cmd("SetHighlight", this.knownID[neighbor], 0);
+
+ }
+ else
+ {
+ this.cmd("SetHighlight", this.distanceID[current], 0);
+ this.cmd("SetHighlight", this.distanceID[neighbor], 0);
+ var compare;
+ if (this.runningDijkstra)
+ {
+ compare = this.distance[current] + this.adj_matrix[current][neighbor];
+ }
+ else
+ {
+ compare = this.adj_matrix[current][neighbor];
+ }
+ if (this.distance[neighbor] < 0 || this.distance[neighbor] > compare)
+ {
+ this.distance[neighbor] = compare;
+ this.path[neighbor] = current;
+ this.cmd("SetText", this.distanceID[neighbor],this.distance[neighbor] );
+ this.cmd("SetText", this.pathID[neighbor],this.path[neighbor]);
+ }
+ }
+
+ }
+ }
+ this.cmd("SetHighlight", this.circleID[current], 0);
+
+ }
+ // Running Dijkstra's algorithm, create the paths
+ if (this.runningDijkstra)
+ {
+ this.cmd("SetText",this.message1ID, "Finding Paths in Table");
+ this.createPaths();
+ }
+ // Running Prim's algorithm, highlight the tree
+ else
+ {
+ this.cmd("SetText",this.message1ID, "Creating tree from table");
+ this.highlightTree();
+ }
+
+ this.cmd("SetText",this.message1ID, "");
+ return this.commands
+}
+
+DijkstraPrim.prototype.createPaths = function()
+{
+ for (var vertex = 0; vertex < this.size; vertex++)
+ {
+ var nextLabelID = this.nextIndex++;
+ if (this.distance[vertex] < 0)
+ {
+ this.cmd("CreateLabel", nextLabelID, "No Path", TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + vertex*TABLE_ENTRY_HEIGHT);
+ this.messageID.push(nextLabelID);
+ }
+ else
+ {
+ this.cmd("CreateLabel", nextLabelID, vertex, TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + vertex*TABLE_ENTRY_HEIGHT);
+ this.messageID.push(nextLabelID);
+ var pathList = [nextLabelID];
+ var nextInPath = vertex;
+ while (nextInPath >= 0)
+ {
+ this.cmd("SetHighlight", this.pathID[nextInPath], 1);
+ this.cmd("Step");
+ if (this.path[nextInPath] != -1)
+ {
+ nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, this.path[nextInPath], TABLE_START_X + 3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + nextInPath*TABLE_ENTRY_HEIGHT);
+ this.cmd("Move", nextLabelID, TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH,TABLE_START_Y + vertex*TABLE_ENTRY_HEIGHT);
+ this.messageID.push(nextLabelID);
+ for (var i = pathList.length - 1; i >= 0; i--)
+ {
+ this.cmd("Move", pathList[i], TABLE_START_X + 4.3 * TABLE_ENTRY_WIDTH + (pathList.length - i) * 17,TABLE_START_Y + vertex*TABLE_ENTRY_HEIGHT)
+
+ }
+ this.cmd("Step");
+ pathList.push(nextLabelID);
+ }
+ this.cmd("SetHighlight", this.pathID[nextInPath], 0);
+ nextInPath = this.path[nextInPath];
+
+ }
+ }
+ }
+}
+
+DijkstraPrim.prototype.highlightTree = function()
+{
+ for (var vertex = 0; vertex < this.size; vertex++)
+ {
+ if (this.path[vertex] >= 0)
+ {
+ this.cmd("SetHighlight", this.vertexID[vertex], 1)
+ this.cmd("SetHighlight", this.pathID[vertex], 1);
+ this.highlightEdge(vertex, this.path[vertex], 1)
+ this.highlightEdge(this.path[vertex], vertex, 1)
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.vertexID[vertex], 0)
+ this.cmd("SetHighlight", this.pathID[vertex], 0);
+ this.highlightEdge(vertex, this.path[vertex], 0)
+ this.highlightEdge(this.path[vertex], vertex, 0)
+ this.setEdgeColor(vertex, this.path[vertex], "#FF0000");
+ this.setEdgeColor(this.path[vertex], vertex,"#FF0000");
+ }
+ }
+}
+
+DijkstraPrim.prototype.reset = function()
+{
+ this.messageID = new Array();
+}
+
+DijkstraPrim.prototype.startCallback = function(event)
+{
+ var startValue;
+
+ if (this.startField.value != "")
+ {
+ startvalue = this.startField.value;
+ this.startField.value = "";
+ if (parseInt(startvalue) < this.size)
+ this.implementAction(this.doDijkstraPrim.bind(this),startvalue);
+ }
+}
+
+
+DijkstraPrim.prototype.enableUI = function(event)
+{
+ this.startField.disabled = false;
+ this.startButton.disabled = false;
+ this.startButton
+
+
+ DijkstraPrim.superclass.enableUI.call(this,event);
+}
+DijkstraPrim.prototype.disableUI = function(event)
+{
+
+ this.startField.disabled = true;
+ this.startButton.disabled = true;
+
+ DijkstraPrim.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init(runDijkstra)
+{
+ var animManag = initCanvas();
+ currentAlg = new DijkstraPrim(animManag, runDijkstra, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DisjointSet.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DisjointSet.js
new file mode 100644
index 0000000..0b147b7
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/DisjointSet.js
@@ -0,0 +1,695 @@
+// 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);
+}
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/EventTest.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/EventTest.js
new file mode 100644
index 0000000..81c3250
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/EventTest.js
@@ -0,0 +1,182 @@
+// 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 ``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 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
+
+
+function.prototype.bind = function(scope) {
+ var _function = this;
+
+ return function() {
+ return _function.apply(scope, arguments);
+ }
+}
+
+
+function EventListener()
+{
+ this.events = [];
+}
+
+
+EventListener.prototype.removeListener = function(kind, scope, func)
+{
+ if (this.events[kind] == undefined)
+ {
+ return;
+ }
+ var scopeFunctions == null;
+ var i;
+ for (i = 0; i < this.events[kind].length; i++)
+ {
+ if (this.events[kind][i].scope == scope)
+ {
+ scopeFunctions = this.events[kind][i];
+ break;
+ }
+ }
+ if (scopeFunctions == null)
+ {
+ return;
+ }
+ for (i = 0; i < scopeFunctions.functions.length; i++)
+ {
+ if (scopeFunctions.functions[i] == func)
+ {
+ scopeFunctions.functions.splice(i,1);
+ return;
+ }
+ }
+}
+
+
+EventListener.prototype.addListener = function(kind, scope, func)
+{
+ if (this.events[kind] === undefined)
+ {
+ this.events[kind] = [];
+ }
+ var i;
+ var scopeFunctions = null;
+ for (i = 0; i < this.events[kind].length; i++)
+ {
+ if (this.events[kind][i].scope == scope)
+ {
+ scopeFunctions = this.events[kind][i];
+ break;
+ }
+ }
+ if (scopeFunctions === null)
+ {
+ this.events[kind].push({scope:scope, functions:[] });
+ scopeFunctions = this.events[kind][this.events[kind].length - 1];
+ }
+ for (i = 0; i < scopeFunctions.functions.length; i++)
+ {
+ if (scopeFunctions.functions[i] == func)
+ {
+ return;
+ }
+ }
+ scopeFunctions.functions.push(func);
+}
+
+EventListener.prototype.fireEvent = function(kind, event)
+{
+ // TODO: Should add a deep clone here ...
+ if (this.events[kind] !== null)
+ {
+ for (var i = 0; i < this.events[kind].length; i++)
+ {
+ var objects = this.events[kind][i];
+ var functs = objects.functions;
+ for (var j = 0; j ``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 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
+
+
+FibonacciHeap.LINK_COLOR = "#007700";
+FibonacciHeap.FOREGROUND_COLOR = "#007700";
+FibonacciHeap.BACKGROUND_COLOR = "#EEFFEE";
+FibonacciHeap.INDEX_COLOR = "#0000FF";
+
+FibonacciHeap.DEGREE_OFFSET_X = -20;
+FibonacciHeap.DEGREE_OFFSET_Y = -20;
+
+FibonacciHeap.DELETE_LAB_X = 30;
+FibonacciHeap.DELETE_LAB_Y = 50;
+
+FibonacciHeap.NODE_WIDTH = 60;
+FibonacciHeap.NODE_HEIGHT = 70
+
+FibonacciHeap.STARTING_X = 70;
+
+FibonacciHeap.INSERT_X = 30;
+FibonacciHeap.INSERT_Y = 25
+
+FibonacciHeap.STARTING_Y = 100;
+FibonacciHeap.MAX_DEGREE = 7;
+FibonacciHeap.DEGREE_ARRAY_ELEM_WIDTH = 30;
+FibonacciHeap.DEGREE_ARRAY_ELEM_HEIGHT = 30;
+FibonacciHeap.DEGREE_ARRAY_START_X = 500;
+FibonacciHeap.INDEGREE_ARRAY_START_Y = 50;
+
+FibonacciHeap.TMP_PTR_Y = 60;
+
+function FibonacciHeap(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+FibonacciHeap.prototype = new Algorithm();
+FibonacciHeap.prototype.constructor = FibonacciHeap;
+FibonacciHeap.superclass = Algorithm.prototype;
+
+
+
+FibonacciHeap.prototype.init = function(am, w, h)
+{
+ FibonacciHeap.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.treeRoot = null;
+ this.currentLayer = 1;
+ this.animationManager.setAllLayers([0,this.currentLayer]);
+ this.minID = 0;
+ this.nextIndex = 1;
+}
+
+
+FibonacciHeap.prototype.addControls = function()
+{
+ this.controls = [];
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.controls.push(this.insertField);
+
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.controls.push(this.insertButton);
+
+ this.removeSmallestButton = addControlToAlgorithmBar("Button", "Remove Smallest");
+ this.removeSmallestButton.onclick = this.removeSmallestCallback.bind(this);
+ this.controls.push(this.removeSmallestButton);
+
+ this.clearHeapButton = addControlToAlgorithmBar("Button", "Clear Heap");
+ this.clearHeapButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearHeapButton);
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Logical Representation",
+ "Internal Representation",
+ ],
+ "BQueueRep");
+
+ radioButtonList[0].onclick = this.representationChangedHandler.bind(this, true);
+ radioButtonList[1].onclick = this.representationChangedHandler.bind(this, false);
+ radioButtonList[0].checked = true;
+
+}
+
+
+FibonacciHeap.prototype.representationChangedHandler = function(logicalRep, event)
+{
+ if (logicalRep)
+ {
+ this.animationManager.setAllLayers([0,1]);
+ this.currentLayer = 1;
+ }
+ else
+ {
+ this.animationManager.setAllLayers([0,2]);
+ this.currentLayer = 2;
+ }
+}
+
+
+
+
+FibonacciHeap.prototype.setPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ if (tree.degree == 0)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ return this.setPositions(tree.rightSib, xPosition + FibonacciHeap.NODE_WIDTH, yPosition);
+ }
+ else if (tree.degree == 1)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ this.setPositions(tree.leftChild, xPosition, yPosition + FibonacciHeap.NODE_HEIGHT);
+ return this.setPositions(tree.rightSib, xPosition + FibonacciHeap.NODE_WIDTH, yPosition);
+ }
+ else
+ {
+ var treeWidth = Math.pow(2, tree.degree - 1);
+ tree.x = xPosition + (treeWidth - 1) * FibonacciHeap.NODE_WIDTH;
+ tree.y = yPosition;
+ this.setPositions(tree.leftChild, xPosition, yPosition + FibonacciHeap.NODE_HEIGHT);
+ return this.setPositions(tree.rightSib, xPosition + treeWidth * FibonacciHeap.NODE_WIDTH, yPosition);
+ }
+ }
+ return xPosition;
+}
+
+FibonacciHeap.prototype.moveTree = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.cmd("Move", tree.internalGraphicID, tree.x, tree.y);
+ this.cmd("Move", tree.degreeID, tree.x + FibonacciHeap.DEGREE_OFFSET_X, tree.y + FibonacciHeap.DEGREE_OFFSET_Y);
+
+ this.moveTree(tree.leftChild);
+ this.moveTree(tree.rightSib);
+ }
+}
+
+
+FibonacciHeap.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+FibonacciHeap.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clear.bind(this),"");
+}
+
+FibonacciHeap.prototype.clear = function()
+{
+ this.commands = new Array();
+
+
+ this.deleteTree(this.treeRoot);
+
+ this.cmd("Delete", this.minID);
+ this.nextIndex = 1;
+ this.treeRoot = null;
+ this.minElement = null;
+ return this.commands;
+}
+
+
+FibonacciHeap.prototype.deleteTree = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Delete", tree.internalGraphicID);
+ this.cmd("Delete", tree.degreeID);
+ this.deleteTree(tree.leftChild);
+ this.deleteTree(tree.rightSib);
+ }
+}
+
+FibonacciHeap.prototype.reset = function()
+{
+ this.treeRoot = null;
+ this.nextIndex = 1;
+}
+
+FibonacciHeap.prototype.removeSmallestCallback = function(event)
+{
+ this.implementAction(this.removeSmallest.bind(this),"");
+}
+
+
+
+FibonacciHeap.prototype.removeSmallest = function(dummy)
+{
+ this.commands = new Array();
+
+ if (this.treeRoot != null)
+ {
+ var tmp;
+ var prev;
+
+
+
+ if (this.minElement == this.treeRoot) {
+ this.treeRoot = this.treeRoot.rightSib;
+ prev = null;
+ }
+ else
+ {
+ for (prev = this.treeRoot; prev.rightSib != this.minElement; prev = prev.rightSib) ;
+ prev.rightSib = prev.rightSib.rightSib;
+
+ }
+ var moveLabel = this.nextIndex++;
+ this.cmd("SetText", this.minElement.graphicID, "");
+ this.cmd("SetText", this.minElement.internalGraphicID, "");
+ this.cmd("CreateLabel", moveLabel, this.minElement.data, this.minElement.x, this.minElement.y);
+ this.cmd("Move", moveLabel, FibonacciHeap.DELETE_LAB_X, FibonacciHeap.DELETE_LAB_Y);
+ this.cmd("Step");
+ this.cmd("Delete", this.minID);
+ var childList = this.minElement.leftChild;
+ if (this.treeRoot == null)
+ {
+ this.cmd("Delete", this.minElement.graphicID);
+ this.cmd("Delete", this.minElement.internalGraphicID);
+ this.cmd("Delete", this.minElement.degreeID);
+ this.treeRoot = childList;
+ this.minElement = null;
+ if (this.treeRoot != null)
+ {
+ for (tmp = this.treeRoot; tmp != null; tmp = tmp.rightSib)
+ {
+ if (this.minElement == null || this.minElement.data > tmp.data)
+ {
+ this.minElement = tmp;
+
+ }
+ }
+ this.cmd("CreateLabel", this.minID, "Min element", this.minElement.x, FibonacciHeap.TMP_PTR_Y);
+ this.cmd("Connect", this.minID,
+ this.minElement.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", this.minID,
+ this.minElement.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ }
+
+ this.SetAllTreePositions(this.treeRoot, []);
+ this.MoveAllTrees(this.treeRoot, []);
+ this.cmd("Delete", moveLabel);
+ return this.commands;
+
+
+ }
+ else if (childList == null)
+ {
+ if (prev != null && prev.rightSib != null)
+ {
+ this.cmd("Connect", prev.internalGraphicID,
+ prev.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", prev.rightSib.internalGraphicID,
+ prev.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ }
+ }
+ else
+ {
+ var tmp;
+ for (tmp = childList; tmp.rightSib != null; tmp = tmp.rightSib)
+ {
+ tmp.parent = null;
+ }
+ tmp.parent = null;
+
+ // TODO: Add in implementation links
+ if (prev == null)
+ {
+ this.cmd("Connect", tmp.internalGraphicID,
+ this.treeRoot.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", this.treeRoot.internalGraphicID,
+ tmp.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ tmp.rightSib = this.treeRoot;
+ this.treeRoot = childList;
+ }
+ else
+ {
+ this.cmd("Connect", prev.internalGraphicID,
+ childList.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", childList.internalGraphicID,
+ prev.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ if (prev.rightSib != null)
+ {
+ this.cmd("Connect", prev.rightSib.internalGraphicID,
+ tmp.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", tmp.internalGraphicID,
+ prev.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ tmp.rightSib = prev.rightSib;
+ prev.rightSib = childList;
+ }
+ }
+ this.cmd("Delete", this.minElement.graphicID);
+ this.cmd("Delete", this.minElement.internalGraphicID);
+ this.cmd("Delete", this.minElement.degreeID);
+
+ this.SetAllTreePositions(this.treeRoot, []);
+ this.MoveAllTrees(this.treeRoot, []);
+ this.fixAfterRemoveMin();
+ this.cmd("Delete", moveLabel);
+ }
+ return this.commands;
+}
+
+
+FibonacciHeap.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+
+ var insertNode = new BinomialNode(insertedValue, this.nextIndex++, FibonacciHeap.INSERT_X, FibonacciHeap.INSERT_Y);
+ insertNode.internalGraphicID = this.nextIndex++;
+ insertNode.degreeID= this.nextIndex++;
+ this.cmd("CreateCircle", insertNode.graphicID, insertedValue, FibonacciHeap.INSERT_X, FibonacciHeap.INSERT_Y);
+ this.cmd("SetForegroundColor", insertNode.graphicID, FibonacciHeap.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", insertNode.graphicID, FibonacciHeap.BACKGROUND_COLOR);
+ this.cmd("SetLayer", insertNode.graphicID, 1);
+ this.cmd("CreateCircle", insertNode.internalGraphicID, insertedValue, FibonacciHeap.INSERT_X, FibonacciHeap.INSERT_Y);
+ this.cmd("SetForegroundColor", insertNode.internalGraphicID, FibonacciHeap.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", insertNode.internalGraphicID, FibonacciHeap.BACKGROUND_COLOR);
+ this.cmd("SetLayer", insertNode.internalGraphicID, 2);
+ this.cmd("CreateLabel", insertNode.degreeID, insertNode.degree, insertNode.x + FibonacciHeap.DEGREE_OFFSET_X, insertNode.y + FibonacciHeap.DEGREE_OFFSET_Y);
+ this.cmd("SetTextColor", insertNode.degreeID, "#0000FF");
+ this.cmd("SetLayer", insertNode.degreeID, 2);
+ this.cmd("Step");
+
+ if (this.treeRoot == null)
+ {
+ this.treeRoot = insertNode;
+ this.setPositions(this.treeRoot, FibonacciHeap.STARTING_X, FibonacciHeap.STARTING_Y);
+ this.moveTree(this.treeRoot);
+ this.cmd("CreateLabel", this.minID, "Min element", this.treeRoot.x, FibonacciHeap.TMP_PTR_Y);
+ this.minElement = this.treeRoot;
+ this.cmd("Connect", this.minID,
+ this.minElement.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", this.minID,
+ this.minElement.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ }
+ else
+ {
+ var tmp;
+ var prev;
+
+ if (this.minElement == this.treeRoot) {
+ insertNode.rightSib = this.treeRoot;
+ this.treeRoot = insertNode;
+
+ this.cmd("Connect", this.treeRoot.internalGraphicID,
+ this.treeRoot.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", this.treeRoot.rightSib.internalGraphicID,
+ this.treeRoot.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Step");
+ this.setPositions(this.treeRoot, FibonacciHeap.STARTING_X, FibonacciHeap.STARTING_Y);
+ if (this.minElement.data > insertNode.data)
+ {
+ this.cmd("Disconnect", this.minID, this.minElement.graphicID);
+ this.cmd("Disconnect", this.minID, this.minElement.internalGraphicID);
+ this.minElement = insertNode;
+ this.cmd("Connect", this.minID,
+ this.minElement.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", this.minID,
+ this.minElement.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ }
+ this.cmd("Move", this.minID, this.minElement.x, FibonacciHeap.TMP_PTR_Y);
+ this.moveTree(this.treeRoot);
+
+ }
+ else
+ {
+ for (prev = this.treeRoot; prev.rightSib != this.minElement; prev = prev.rightSib) ;
+
+
+ this.cmd("Disconnect", prev.internalGraphicID, prev.rightSib.internalGraphicID);
+ this.cmd("Disconnect", prev.rightSib.internalGraphicID, prev.internalGraphicID);
+
+ insertNode.rightSib = prev.rightSib;
+ prev.rightSib = insertNode;
+
+ this.cmd("Connect", prev.internalGraphicID,
+ prev.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", prev.rightSib.internalGraphicID,
+ prev.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ if (prev.rightSib.rightSib != null)
+ {
+
+ this.cmd("Connect", prev.rightSib.internalGraphicID,
+ prev.rightSib.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", prev.rightSib.rightSib.internalGraphicID,
+ prev.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+
+
+ this.cmd("Step");
+ this.setPositions(this.treeRoot, FibonacciHeap.STARTING_X, FibonacciHeap.STARTING_Y);
+ if (this.minElement.data > insertNode.data)
+ {
+ this.cmd("Disconnect", this.minID, this.minElement.graphicID);
+ this.cmd("Disconnect", this.minID, this.minElement.internalGraphicID);
+ this.minElement = insertNode;
+ this.cmd("Connect", this.minID,
+ this.minElement.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", this.minID,
+ this.minElement.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ this.cmd("Move", this.minID, this.minElement.x, FibonacciHeap.TMP_PTR_Y);
+
+ this.moveTree(this.treeRoot);
+
+ }
+
+
+
+
+
+ }
+
+ return this.commands;
+}
+
+
+
+
+
+FibonacciHeap.prototype.fixAfterRemoveMin = function()
+{
+ if (this.treeRoot == null)
+ return;
+ var degreeArray = new Array(FibonacciHeap.MAX_DEGREE);
+ var degreeGraphic = new Array(FibonacciHeap.MAX_DEGREE);
+ var indexID = new Array(FibonacciHeap.MAX_DEGREE);
+ var tmpPtrID = this.nextIndex++;
+
+ var i;
+ for (i = 0 ; i <= FibonacciHeap.MAX_DEGREE; i++)
+ {
+ degreeArray[i] = null;
+ degreeGraphic[i] = this.nextIndex++;
+ indexID[i] = this.nextIndex++;
+ this.cmd("CreateRectangle",
+ degreeGraphic[i],
+ " ",
+ FibonacciHeap.DEGREE_ARRAY_ELEM_WIDTH,
+ FibonacciHeap.DEGREE_ARRAY_ELEM_HEIGHT,
+ FibonacciHeap.DEGREE_ARRAY_START_X + i * FibonacciHeap.DEGREE_ARRAY_ELEM_WIDTH,
+ FibonacciHeap.INDEGREE_ARRAY_START_Y);
+ this.cmd("SetNull", degreeGraphic[i], 1);
+ this.cmd("CreateLabel", indexID[i], i, FibonacciHeap.DEGREE_ARRAY_START_X + i * FibonacciHeap.DEGREE_ARRAY_ELEM_WIDTH,
+ FibonacciHeap.INDEGREE_ARRAY_START_Y - FibonacciHeap.DEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("SetTextColod", indexID[i], FibonacciHeap.INDEX_COLOR);
+ }
+ var tmp = this.treeRoot;
+ // When remving w/ 1 tree. this.treeRoot == null?
+ this.cmd("CreateLabel", tmpPtrID, "NextElem", this.treeRoot.x, FibonacciHeap.TMP_PTR_Y);
+ while (this.treeRoot != null)
+ {
+ tmp = this.treeRoot;
+ this.cmd("Connect", tmpPtrID,
+ tmp.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", tmpPtrID,
+ tmp.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.treeRoot = this.treeRoot.rightSib;
+ if (tmp.rightSib != null)
+ {
+ this.cmd("Disconnect", tmp.internalGraphicID, tmp.rightSib.internalGraphicID);
+ this.cmd("Disconnect", tmp.rightSib.internalGraphicID, tmp.internalGraphicID);
+ }
+
+ this.cmd("Step");
+ tmp.rightSib = null;
+ while(degreeArray[tmp.degree] != null)
+ {
+ this.cmd("SetEdgeHighlight", tmpPtrID, tmp.graphicID, 1);
+ this.cmd("SetEdgeHighlight", tmpPtrID, tmp.internalGraphicID, 1);
+
+ this.cmd("SetEdgeHighlight", degreeGraphic[tmp.degree], degreeArray[tmp.degree].graphicID, 1);
+ this.cmd("SetEdgeHighlight", degreeGraphic[tmp.degree], degreeArray[tmp.degree].internalGraphicID, 1);
+ this.cmd("Step");
+ this.cmd("Disconnect", tmpPtrID, tmp.graphicID);
+ this.cmd("Disconnect", tmpPtrID, tmp.internalGraphicID);
+
+
+
+ this.cmd("Disconnect", degreeGraphic[tmp.degree], degreeArray[tmp.degree].graphicID);
+ this.cmd("Disconnect", degreeGraphic[tmp.degree], degreeArray[tmp.degree].internalGraphicID);
+ this.cmd("SetNull", degreeGraphic[tmp.degree], 1);
+ var tmp2 = degreeArray[tmp.degree];
+ degreeArray[tmp.degree] = null
+ tmp = this.combineTrees(tmp, tmp2);
+ this.cmd("Connect", tmpPtrID,
+ tmp.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", tmpPtrID,
+ tmp.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.SetAllTreePositions(this.treeRoot, degreeArray, tmp);
+ this.cmd("Move", tmpPtrID, tmp.x, FibonacciHeap.TMP_PTR_Y);
+ this.MoveAllTrees(this.treeRoot, degreeArray, tmp);
+ }
+ this.cmd("Disconnect", tmpPtrID, tmp.graphicID);
+ this.cmd("Disconnect", tmpPtrID, tmp.internalGraphicID);
+
+ degreeArray[tmp.degree] = tmp;
+ this.cmd("SetNull", degreeGraphic[tmp.degree], 0);
+ this.cmd("Connect", degreeGraphic[tmp.degree],
+ tmp.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", degreeGraphic[tmp.degree],
+ tmp.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Step");
+ this.SetAllTreePositions(this.treeRoot, degreeArray);
+ this.MoveAllTrees(this.treeRoot, degreeArray);
+ }
+ this.minElement = null;
+ for (i = FibonacciHeap.MAX_DEGREE; i >= 0; i--)
+ {
+ if (degreeArray[i] != null)
+ {
+ degreeArray[i].rightSib = this.treeRoot;
+ if (this.minElement == null || this.minElement.data > degreeArray[i].data)
+ {
+ this.minElement = degreeArray[i];
+ }
+ this.treeRoot = degreeArray[i];
+ if (this.treeRoot.rightSib != null)
+ {
+ this.cmd("Connect", this.treeRoot.internalGraphicID,
+ this.treeRoot.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", this.treeRoot.rightSib.internalGraphicID,
+ this.treeRoot.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ }
+
+ this.cmd("Delete", degreeGraphic[i]);
+ this.cmd("Delete", indexID[i]);
+
+ }
+ if (this.minElement != null)
+ {
+ this.cmd("CreateLabel", this.minID,"Min element", this.minElement.x,FibonacciHeap.TMP_PTR_Y);
+ this.cmd("Connect", this.minID,
+ this.minElement.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", this.minID,
+ this.minElement.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+ this.cmd("Delete", tmpPtrID);
+
+}
+
+FibonacciHeap.prototype.MoveAllTrees = function(tree, treeList, tree2)
+{
+ if (tree2 != null && tree2 != undefined)
+ {
+ this.moveTree(tree2);
+ }
+ if (tree != null)
+ {
+ this.moveTree(tree);
+ }
+ for (var i = 0; i < treeList.length; i++)
+ {
+ if (treeList[i] != null)
+ {
+ this.moveTree(treeList[i]);
+ }
+ }
+ this.cmd("Step");
+
+
+}
+
+
+FibonacciHeap.prototype.SetAllTreePositions = function(tree, treeList, tree2)
+{
+ var leftSize = FibonacciHeap.STARTING_X;
+ if (tree2 != null && tree2 != undefined)
+ {
+ leftSize = this.setPositions(tree2, leftSize, FibonacciHeap.STARTING_Y); // +FibonacciHeap.NODE_WIDTH;
+ }
+ if (tree != null)
+ {
+ leftSize = this.setPositions(tree, leftSize, FibonacciHeap.STARTING_Y); // + FibonacciHeap.NODE_WIDTH;
+
+ }
+ for (var i = 0; i < treeList.length; i++)
+ {
+ if (treeList[i] != null)
+ {
+ leftSize = this.setPositions(treeList[i], leftSize, FibonacciHeap.STARTING_Y); // + FibonacciHeap.NODE_WIDTH;
+ }
+ }
+}
+
+FibonacciHeap.prototype.combineTrees = function(tree1, tree2)
+{
+ if (tree2.data < tree1.data)
+ {
+ var tmp = tree2;
+ tree2 = tree1;
+ tree1 = tmp;
+ }
+ if (tree1.degree != tree2.degree)
+ {
+ return null;
+ }
+ tree2.rightSib = tree1.leftChild;
+ tree2.parent =tree1;
+ tree1.leftChild = tree2;
+ tree1.degree++;
+
+ if (tree1.leftChild.rightSib != null)
+ {
+ this.cmd("Disconnect", tree1.internalGraphicID, tree1.leftChild.rightSib.internalGraphicID);
+ this.cmd("Connect", tree1.leftChild.internalGraphicID,
+ tree1.leftChild.rightSib.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.3, // Curve
+ 1, // Directed
+ ""); // Label
+ this.cmd("Connect", tree1.leftChild.rightSib.internalGraphicID,
+ tree1.leftChild.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.3, // Curve
+ 1, // Directed
+ ""); // Label
+ }
+
+ this.cmd("Connect", tree1.internalGraphicID,
+ tree1.leftChild.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.15, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("Connect", tree1.leftChild.internalGraphicID,
+ tree1.internalGraphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0.0, // Curve
+ 1, // Directed
+ ""); // Label
+
+ this.cmd("SetText", tree1.degreeID, tree1.degree);
+ this.cmd("Connect", tree1.graphicID,
+ tree2.graphicID,
+ FibonacciHeap.FOREGROUND_COLOR,
+ 0, // Curve
+ 0, // Directed
+ ""); // Label
+ // TODO: Add all the internal links &etc
+
+ return tree1;
+
+}
+
+FibonacciHeap.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+FibonacciHeap.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new FibonacciHeap(animManag, canvas.width, canvas.height);
+}
+
+
+
+
+function BinomialNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.degree = 0;
+ this.leftChild = null;
+ this.rightSib = null;
+ this.parent = null;
+ this.internalGraphicID = -1;
+ this.degreeID = -1;
+}
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Floyd.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Floyd.js
new file mode 100644
index 0000000..7079bb7
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Floyd.js
@@ -0,0 +1,413 @@
+// 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 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
+
+
+
+function Floyd(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+Floyd.SMALL_COST_TABLE_WIDTH = 30;
+Floyd.SMALL_COST_TABLE_HEIGHT = 30;
+Floyd.SMALL_COST_TABLE_START_X = 40;
+Floyd.SMALL_COST_TABLE_START_Y = 70;
+
+Floyd.SMALL_PATH_TABLE_WIDTH = 30;
+Floyd.SMALL_PATH_TABLE_HEIGHT = 30;
+Floyd.SMALL_PATH_TABLE_START_X = 330;
+Floyd.SMALL_PATH_TABLE_START_Y = 70;
+
+
+Floyd.SMALL_NODE_1_X_POS = 50;
+Floyd.SMALL_NODE_1_Y_POS = 400;
+Floyd.SMALL_NODE_2_X_POS = 150;
+Floyd.SMALL_NODE_2_Y_POS = 350;
+Floyd.SMALL_NODE_3_X_POS = 250;
+Floyd.SMALL_NODE_3_Y_POS = 400;
+
+Floyd.SMALL_MESSAGE_X = 400;
+Floyd.SMALL_MESSAGE_Y = 350;
+
+Floyd.LARGE_COST_TABLE_WIDTH = 20;
+Floyd.LARGE_COST_TABLE_HEIGHT = 20;
+Floyd.LARGE_COST_TABLE_START_X = 40;
+Floyd.LARGE_COST_TABLE_START_Y = 50;
+
+Floyd.LARGE_PATH_TABLE_WIDTH = 20;
+Floyd.LARGE_PATH_TABLE_HEIGHT = 20;
+Floyd.LARGE_PATH_TABLE_START_X = 500;
+Floyd.LARGE_PATH_TABLE_START_Y = 50;
+
+Floyd.LARGE_NODE_1_X_POS = 50;
+Floyd.LARGE_NODE_1_Y_POS = 500;
+Floyd.LARGE_NODE_2_X_POS = 150;
+Floyd.LARGE_NODE_2_Y_POS = 450;
+Floyd.LARGE_NODE_3_X_POS = 250;
+Floyd.LARGE_NODE_3_Y_POS = 500;
+
+Floyd.LARGE_MESSAGE_X = 300;
+Floyd.LARGE_MESSAGE_Y = 450;
+
+Floyd.prototype = new Graph();
+Floyd.prototype.constructor = Floyd;
+Floyd.superclass = Graph.prototype;
+
+Floyd.prototype.addControls = function()
+{
+
+ this.startButton = addControlToAlgorithmBar("Button", "Run Floyd-Warshall");
+ this.startButton.onclick = this.startCallback.bind(this);
+
+ Floyd.superclass.addControls.call(this);
+ this.smallGraphButton.onclick = this.smallGraphCallback.bind(this);
+ this.largeGraphButton.onclick = this.largeGraphCallback.bind(this);
+}
+
+
+Floyd.prototype.init = function(am, w, h)
+{
+ this.showEdgeCosts = true;
+ Floyd.superclass.init.call(this, am, w, h, true, false); // TODO: add no edge label flag to this?
+ // Setup called in base class init function
+}
+
+Floyd.prototype.reset = function()
+{
+ for (var i = 0; i < this.size; i++)
+ {
+ for (var j = 0; j < this.size; j++)
+ {
+ this.costTable[i][j] = this.adj_matrix[i][j];
+ if (this.costTable[i][j] >= 0)
+ {
+ this.pathTable[i][j] = i;
+ }
+ else
+ {
+ this.pathTable[i][j] = -1
+ }
+
+ }
+
+ }
+
+}
+
+
+Floyd.prototype.smallGraphCallback = function (event)
+{
+ if (this.size != SMALL_SIZE)
+ {
+ this.animationManager.resetAll();
+ this.animationManager.setAllLayers([0,this.currentLayer]);
+ this.logicalButton.disabled = false;
+ this.adjacencyListButton.disabled = false;
+ this.adjacencyMatrixButton.disabled = false;
+ this.setup_small();
+ }
+}
+
+Graph.prototype.largeGraphCallback = function (event)
+{
+ if (this.size != LARGE_SIZE)
+ {
+ this.animationManager.resetAll();
+ //this.animationManager.setAllLayers([0]);
+ this.logicalButton.disabled = true;
+ this.adjacencyListButton.disabled = true;
+ this.adjacencyMatrixButton.disabled = true;
+ this.setup_large();
+ }
+}
+
+
+
+
+Floyd.prototype.getCostLabel = function(value, alwaysUseINF)
+{
+ alwaysUseINF = alwaysUseINF == undefined ? false : alwaysUseINF;
+ if (value >= 0)
+ {
+ return String(value);
+ }
+ else if (this.size == SMALL_SIZE || alwaysUseINF)
+ {
+ return "INF";
+ }
+ else
+ {
+ return ""
+ }
+}
+
+Floyd.prototype.setup_small = function()
+{
+ this.cost_table_width = Floyd.SMALL_COST_TABLE_WIDTH;
+ this.cost_table_height = Floyd.SMALL_COST_TABLE_HEIGHT;
+ this.cost_table_start_x = Floyd.SMALL_COST_TABLE_START_X;
+ this.cost_table_start_y = Floyd.SMALL_COST_TABLE_START_Y;
+
+ this.path_table_width = Floyd.SMALL_PATH_TABLE_WIDTH;
+ this.path_table_height = Floyd.SMALL_PATH_TABLE_HEIGHT;
+ this.path_table_start_x = Floyd.SMALL_PATH_TABLE_START_X;
+ this.path_table_start_y = Floyd.SMALL_PATH_TABLE_START_Y;
+
+ this.node_1_x_pos = Floyd.SMALL_NODE_1_X_POS;
+ this.node_1_y_pos = Floyd.SMALL_NODE_1_Y_POS;
+ this.node_2_x_pos = Floyd.SMALL_NODE_2_X_POS;
+ this.node_2_y_pos = Floyd.SMALL_NODE_2_Y_POS;
+ this.node_3_x_pos = Floyd.SMALL_NODE_3_X_POS;
+ this.node_3_y_pos = Floyd.SMALL_NODE_3_Y_POS;
+
+ this.message_x = Floyd.SMALL_MESSAGE_X;
+ this.message_y = Floyd.SMALL_MESSAGE_Y;
+ Floyd.superclass.setup_small.call(this);
+}
+
+Floyd.prototype.setup_large = function()
+{
+ this.cost_table_width = Floyd.LARGE_COST_TABLE_WIDTH;
+ this.cost_table_height = Floyd.LARGE_COST_TABLE_HEIGHT;
+ this.cost_table_start_x = Floyd.LARGE_COST_TABLE_START_X;
+ this.cost_table_start_y = Floyd.LARGE_COST_TABLE_START_Y;
+
+ this.path_table_width = Floyd.LARGE_PATH_TABLE_WIDTH;
+ this.path_table_height = Floyd.LARGE_PATH_TABLE_HEIGHT;
+ this.path_table_start_x = Floyd.LARGE_PATH_TABLE_START_X;
+ this.path_table_start_y = Floyd.LARGE_PATH_TABLE_START_Y;
+
+ this.node_1_x_pos = Floyd.LARGE_NODE_1_X_POS;
+ this.node_1_y_pos = Floyd.LARGE_NODE_1_Y_POS;
+ this.node_2_x_pos = Floyd.LARGE_NODE_2_X_POS;
+ this.node_2_y_pos = Floyd.LARGE_NODE_2_Y_POS;
+ this.node_3_x_pos = Floyd.LARGE_NODE_3_X_POS;
+ this.node_3_y_pos = Floyd.LARGE_NODE_3_Y_POS;
+
+ this.message_x = Floyd.LARGE_MESSAGE_X;
+ this.message_y = Floyd.LARGE_MESSAGE_Y;
+
+ Floyd.superclass.setup_large.call(this);
+}
+
+
+Floyd.prototype.setup = function()
+{
+ Floyd.superclass.setup.call(this);
+ this.commands = new Array();
+
+ this.costTable = new Array(this.size);
+ this.pathTable = new Array(this.size);
+ this.costTableID = new Array(this.size);
+ this.pathTableID = new Array(this.size);
+ this.pathIndexXID = new Array(this.size);
+ this.pathIndexYID = new Array(this.size);
+ this.costIndexXID = new Array(this.size);
+ this.costIndexYID = new Array(this.size);
+
+ this.node1ID = this.nextIndex++;
+ this.node2ID = this.nextIndex++;
+ this.node3ID = this.nextIndex++;
+
+ var i;
+ for (i = 0; i < this.size; i++)
+ {
+ this.costTable[i] = new Array(this.size);
+ this.pathTable[i] = new Array(this.size);
+ this.costTableID[i] = new Array(this.size);
+ this.pathTableID[i] = new Array(this.size);
+
+ }
+
+ var costTableHeader = this.nextIndex++;
+ var pathTableHeader = this.nextIndex++;
+
+ this.cmd("CreateLabel", costTableHeader, "Cost Table", this.cost_table_start_x, this.cost_table_start_y - 2*this.cost_table_height, 0);
+ this.cmd("CreateLabel", pathTableHeader, "Path Table", this.path_table_start_x, this.path_table_start_y - 2*this.path_table_height, 0);
+
+ for (i= 0; i < this.size; i++)
+ {
+ this.pathIndexXID[i] = this.nextIndex++;
+ this.pathIndexYID[i] = this.nextIndex++;
+ this.costIndexXID[i] = this.nextIndex++;
+ this.costIndexYID[i] = this.nextIndex++;
+ this.cmd("CreateLabel", this.pathIndexXID[i], i, this.path_table_start_x + i * this.path_table_width, this.path_table_start_y - this.path_table_height);
+ this.cmd("SetTextColor", this.pathIndexXID[i], "#0000FF");
+ this.cmd("CreateLabel", this.pathIndexYID[i], i, this.path_table_start_x - this.path_table_width, this.path_table_start_y + i * this.path_table_height);
+ this.cmd("SetTextColor", this.pathIndexYID[i], "#0000FF");
+
+ this.cmd("CreateLabel", this.costIndexXID[i], i, this.cost_table_start_x + i * this.cost_table_width, this.cost_table_start_y - this.cost_table_height);
+ this.cmd("SetTextColor", this.costIndexXID[i], "#0000FF");
+ this.cmd("CreateLabel", this.costIndexYID[i], i, this.cost_table_start_x - this.cost_table_width, this.cost_table_start_y + i * this.cost_table_height);
+ this.cmd("SetTextColor", this.costIndexYID[i], "#0000FF");
+ for (var j = 0; j < this.size; j++)
+ {
+ this.costTable[i][j] = this.adj_matrix[i][j];
+ if (this.costTable[i][j] >= 0)
+ {
+ this.pathTable[i][j] = i;
+ }
+ else
+ {
+ this.pathTable[i][j] = -1
+ }
+ this.costTableID[i][j] = this.nextIndex++;
+ this.pathTableID[i][j] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.costTableID[i][j], this.getCostLabel(this.costTable[i][j], true), this.cost_table_width, this.cost_table_height, this.cost_table_start_x + j* this.cost_table_width, this.cost_table_start_y + i*this.cost_table_height);
+ this.cmd("CreateRectangle", this.pathTableID[i][j], this.pathTable[i][j], this.path_table_width, this.path_table_height, this.path_table_start_x + j* this.path_table_width, this.path_table_start_y + i*this.path_table_height);
+ }
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ if (this.size == LARGE_SIZE)
+ {
+ this.animationManager.setAllLayers([0]);
+ }
+
+}
+
+Floyd.prototype.startCallback = function(event)
+{
+ this.implementAction(this.doFloydWarshall.bind(this),"");
+}
+
+
+Floyd.prototype.doFloydWarshall = function(ignored)
+{
+ this.commands = new Array();
+
+ var oldIndex= this.nextIndex;
+ var messageID = this.nextIndex++;
+ var moveLabel1ID = this.nextIndex++;
+ var moveLabel2ID = this.nextIndex++;
+
+ this.cmd("CreateCircle", this.node1ID, "", this.node_1_x_pos, this.node_1_y_pos);
+ this.cmd("CreateCircle", this.node2ID, "", this.node_2_x_pos, this.node_2_y_pos);
+ this.cmd("CreateCircle", this.node3ID, "", this.node_3_x_pos, this.node_3_y_pos);
+ this.cmd("CreateLabel", messageID, "", this.message_x, this.message_y, 0);
+
+ for (var k = 0; k < this.size; k++)
+ {
+ for (var i = 0; i < this.size; i++)
+ {
+ for (var j = 0; j < this.size; j++)
+ {
+ if (i != j && j != k && i != k)
+ {
+ this.cmd("SetText", this.node1ID, i);
+ this.cmd("SetText", this.node2ID, k);
+ this.cmd("SetText", this.node3ID, j);
+ this.cmd("Connect",this.node1ID, this.node2ID, "#009999", -0.1, 1, this.getCostLabel(this.costTable[i][k], true))
+ this.cmd("Connect",this.node2ID, this.node3ID, "#9900CC", -0.1, 1, this.getCostLabel(this.costTable[k][j], true))
+ this.cmd("Connect",this.node1ID, this.node3ID, "#CC0000", 0, 1, this.getCostLabel(this.costTable[i][j], true))
+ this.cmd("SetHighlight", this.costTableID[i][k], 1);
+ this.cmd("SetHighlight", this.costTableID[k][j], 1);
+ this.cmd("SetHighlight", this.costTableID[i][j], 1);
+ this.cmd("SetTextColor", this.costTableID[i][k], "#009999");
+ this.cmd("SetTextColor", this.costTableID[k][j], "#9900CC");
+ this.cmd("SetTextColor", this.costTableID[i][j], "#CC0000");
+ if (this.costTable[i][k] >= 0 && this.costTable[k][j] >= 0)
+ {
+ if (this.costTable[i][j] < 0 || this.costTable[i][k] + this.costTable[k][j] < this.costTable[i][j])
+ {
+ this.cmd("SetText", messageID, this.getCostLabel(this.costTable[i][k], true) + " + " + this.getCostLabel(this.costTable[k][j], true) + " < " + this.getCostLabel(this.costTable[i][j], true));
+ this.cmd("Step");
+ this.costTable[i][j] = this.costTable[i][k] + this.costTable[k][j];
+ this.cmd("SetText", this.pathTableID[i][j], "");
+ this.cmd("SetText", this.costTableID[i][j], "");
+ this.cmd("CreateLabel", moveLabel1ID, this.pathTable[k][j], this.path_table_start_x + j* this.path_table_width, this.path_table_start_y + k*this.path_table_height);
+ this.cmd("Move", moveLabel1ID, this.path_table_start_x + j* this.path_table_width, this.path_table_start_y + i*this.path_table_height)
+ this.cmd("CreateLabel", moveLabel2ID,this.costTable[i][j], this.message_x, this.message_y);
+ this.cmd("SetHighlight", moveLabel2ID, 1);
+ this.cmd("Move", moveLabel2ID, this.cost_table_start_x + j* this.cost_table_width, this.cost_table_start_y + i*this.cost_table_height)
+ this.pathTable[i][j] = this.pathTable[k][j];
+ this.cmd("Step");
+ this.cmd("SetText", this.costTableID[i][j], this.costTable[i][j]);
+ this.cmd("SetText", this.pathTableID[i][j], this.pathTable[i][j]);
+ this.cmd("Delete", moveLabel1ID);
+ this.cmd("Delete", moveLabel2ID);
+ }
+ else
+ {
+ this.cmd("SetText", messageID, "!("+this.getCostLabel(this.costTable[i][k], true) + " + " + this.getCostLabel(this.costTable[k][j], true) + " < " + this.getCostLabel(this.costTable[i][j], true) + ")");
+ this.cmd("Step");
+
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", messageID, "!("+this.getCostLabel(this.costTable[i][k], true) + " + " + this.getCostLabel(this.costTable[k][j], true) + " < " + this.getCostLabel(this.costTable[i][j], true) + ")");
+ this.cmd("Step");
+ }
+ this.cmd("SetTextColor", this.costTableID[i][k], "#000000");
+ this.cmd("SetTextColor", this.costTableID[k][j], "#000000");
+ this.cmd("SetTextColor", this.costTableID[i][j], "#000000");
+ this.cmd("Disconnect",this.node1ID, this.node2ID)
+ this.cmd("Disconnect",this.node2ID, this.node3ID)
+ this.cmd("Disconnect",this.node1ID, this.node3ID)
+ this.cmd("SetHighlight", this.costTableID[i][k], 0);
+ this.cmd("SetHighlight", this.costTableID[k][j], 0);
+ this.cmd("SetHighlight", this.costTableID[i][j], 0);
+ }
+ }
+
+
+ }
+ }
+ this.cmd("Delete", this.node1ID);
+ this.cmd("Delete", this.node2ID);
+ this.cmd("Delete", this.node3ID);
+ this.cmd("Delete", messageID);
+ this.nextIndex = oldIndex;
+
+
+
+ return this.commands
+}
+
+
+Floyd.prototype.enableUI = function(event)
+{
+ this.startButton.disabled = false;
+ Floyd.superclass.enableUI.call(this,event);
+}
+Floyd.prototype.disableUI = function(event)
+{
+ this.startButton.disabled = true;
+ Floyd.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Floyd(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Graph.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Graph.js
new file mode 100644
index 0000000..ecffd3b
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Graph.js
@@ -0,0 +1,721 @@
+// 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 ``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 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
+
+// TODO: UNDO (all the way) is BROKEN. Redo reset ...
+
+
+function Graph(am, w, h, dir, dag)
+{
+ if (am == undefined)
+ {
+ return;
+ }
+ this.init(am, w, h, dir,dag);
+}
+
+Graph.prototype = new Algorithm();
+Graph.prototype.constructor = Graph;
+Graph.superclass = Algorithm.prototype;
+
+var LARGE_ALLOWED = [[false, true, true, false, true, false, false, true, false, false, false, false, false, false, true, false, false, false],
+ [true, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false],
+ [true, true, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false],
+ [false, false, true, false, false,false, true, false, false, false, true, false, false, false, false, false, false, true],
+ [true, true, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false],
+ [false, true, true, false, true, false, true, false, true, true, false, false, false, false, false, false, false, false],
+ [false, false, true, true, false, true, false, false, false, true, true, false, false, false, false, false, false, false],
+ [true, false, false, false, true, false, false, false, true, false, false, true, false, false, true, false, false, false],
+ [false, false, false, false, true, true, false, true, false, true, false, true, true, false, false, false, false, false],
+ [false, false, false, false, false, true, true, false, true, false, true, false, true, true, false, false, false, false],
+ [false, false, false, true, false, false, true, false, false, true, false, false, false, true, false, false, false, true],
+ [false, false, false, false, false, false, false, true, true, false, false, false, true, false, true, true, false, false],
+ [false, false, false, false, false, false, false, false, true, true, false, true, false, true, false, true, true, false],
+ [false, false, false, false, false, false, false, false, false, true, true, false, true, false, false, false, true, true],
+ [false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, true, false, false],
+ [false, false, false, false, false, false, false, false, false, false, false, true, true, false, true, false, true, true],
+ [false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, true, false, true],
+ [false, false, false, false, false, false, false, false, false, false, true, false, false, true, false, true, true, false]];
+
+var LARGE_CURVE = [[0, 0, -0.4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0.4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.25],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [-0.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.4],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 0.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.4, 0, 0]]
+
+
+
+var LARGE_X_POS_LOGICAL = [600, 700, 800, 900,
+ 650, 750, 850,
+ 600, 700, 800, 900,
+ 650, 750, 850,
+ 600, 700, 800, 900];
+
+
+var LARGE_Y_POS_LOGICAL = [50, 50, 50, 50,
+ 150, 150, 150,
+ 250, 250, 250, 250,
+ 350, 350, 350,
+ 450, 450, 450, 450];
+
+
+var SMALL_ALLLOWED = [[false, true, true, true, true, false, false, false],
+ [true, false, true, true, false, true, true, false],
+ [true, true, false, false, true, true, true, false],
+ [true, true, false, false, false, true, false, true],
+ [true, false, true, false, false, false, true, true],
+ [false, true, true, true, false, false, true, true],
+ [false, true, true, false, true, true, false, true],
+ [false, false, false, true, true, true, true, false]];
+
+var SMALL_CURVE = [[0, 0.001, 0, 0.5, -0.5, 0, 0, 0],
+ [0, 0, 0, 0.001, 0, 0.001, -0.2, 0],
+ [0, 0.001, 0, 0, 0, 0.2, 0, 0],
+ [-0.5, 0, 0, 0, 0, 0.001, 0, 0.5],
+ [0.5, 0, 0, 0, 0, 0, 0, -0.5],
+ [0, 0, -0.2, 0, 0, 0, 0.001, 0.001],
+ [0, 0.2, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, -0.5, 0.5, 0, 0, 0]]
+
+var SMALL_X_POS_LOGICAL = [800, 725, 875, 650, 950, 725, 875, 800];
+var SMALL_Y_POS_LOGICAL = [25, 125, 125, 225, 225, 325, 325, 425];
+
+
+var SMALL_ADJ_MATRIX_X_START = 700;
+var SMALL_ADJ_MATRIX_Y_START = 40;
+var SMALL_ADJ_MATRIX_WIDTH = 30;
+var SMALL_ADJ_MATRIX_HEIGHT = 30;
+
+var SMALL_ADJ_LIST_X_START = 600;
+var SMALL_ADJ_LIST_Y_START = 30;
+
+var SMALL_ADJ_LIST_ELEM_WIDTH = 50;
+var SMALL_ADJ_LIST_ELEM_HEIGHT = 30;
+
+var SMALL_ADJ_LIST_HEIGHT = 36;
+var SMALL_ADJ_LIST_WIDTH = 36;
+
+var SMALL_ADJ_LIST_SPACING = 10;
+
+
+var LARGE_ADJ_MATRIX_X_START = 575;
+var LARGE_ADJ_MATRIX_Y_START = 30;
+var LARGE_ADJ_MATRIX_WIDTH = 23;
+var LARGE_ADJ_MATRIX_HEIGHT = 23;
+
+var LARGE_ADJ_LIST_X_START = 600;
+var LARGE_ADJ_LIST_Y_START = 30;
+
+var LARGE_ADJ_LIST_ELEM_WIDTH = 50;
+var LARGE_ADJ_LIST_ELEM_HEIGHT = 26;
+
+var LARGE_ADJ_LIST_HEIGHT = 30;
+var LARGE_ADJ_LIST_WIDTH = 30;
+
+var LARGE_ADJ_LIST_SPACING = 10;
+
+
+
+var VERTEX_INDEX_COLOR ="#0000FF";
+var EDGE_COLOR = "#000000";
+
+var SMALL_SIZE = 8;
+var LARGE_SIZE = 18;
+
+var HIGHLIGHT_COLOR = "#0000FF";
+
+
+
+
+
+Graph.prototype.init = function(am, w, h, directed, dag)
+{
+ directed = (directed == undefined) ? true : directed;
+ dag = (dag == undefined) ? false : dag;
+
+ Graph.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+
+ this.currentLayer = 1;
+ this.isDAG = dag;
+ this.directed = directed;
+ this.currentLayer = 1;
+ this.addControls();
+
+ this.setup_small();
+}
+
+Graph.prototype.addControls = function(addDirection)
+{
+ if (addDirection == undefined)
+ {
+ addDirection = true;
+ }
+ this.newGraphButton = addControlToAlgorithmBar("Button", "New Graph");
+ this.newGraphButton.onclick = this.newGraphCallback.bind(this);
+
+ if (addDirection)
+ {
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Directed Graph", "Undirected Graph"], "GraphType");
+ this.directedGraphButton = radioButtonList[0];
+ this.directedGraphButton.onclick = this.directedGraphCallback.bind(this, true);
+ this.undirectedGraphButton = radioButtonList[1];
+ this.undirectedGraphButton.onclick = this.directedGraphCallback.bind(this, false);
+ this.directedGraphButton.checked = this.directed;
+ this.undirectedGraphButton.checked = !this.directed;
+ }
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Small Graph", "Large Graph"], "GraphSize");
+ this.smallGraphButton = radioButtonList[0];
+ this.smallGraphButton.onclick = this.smallGraphCallback.bind(this);
+ this.largeGraphButton = radioButtonList[1];
+ this.largeGraphButton.onclick = this.largeGraphCallback.bind(this);
+ this.smallGraphButton.checked = true;
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Logical Representation",
+ "Adjacency List Representation",
+ "Adjacency Matrix Representation"
+ ],
+ "GraphRepresentation");
+ this.logicalButton = radioButtonList[0];
+ this.logicalButton.onclick = this.graphRepChangedCallback.bind(this,1);
+ this.adjacencyListButton = radioButtonList[1];
+ this.adjacencyListButton.onclick = this.graphRepChangedCallback.bind(this,2);
+ this.adjacencyMatrixButton = radioButtonList[2];
+ this.adjacencyMatrixButton.onclick = this.graphRepChangedCallback.bind(this,3);
+ this.logicalButton.checked = true;
+
+}
+
+Graph.prototype.directedGraphCallback = function (newDirected, event)
+{
+ if (newDirected != this.directed)
+ {
+ this.directed =newDirected;
+ this.animationManager.resetAll();
+ this.setup();
+ }
+}
+
+
+
+Graph.prototype.smallGraphCallback = function (event)
+{
+ if (this.size != SMALL_SIZE)
+ {
+ this.animationManager.resetAll();
+ this.setup_small();
+ }
+}
+
+Graph.prototype.largeGraphCallback = function (event)
+{
+ if (this.size != LARGE_SIZE)
+ {
+ this.animationManager.resetAll();
+ this.setup_large();
+ }
+}
+
+
+Graph.prototype.newGraphCallback = function(event)
+{
+ this.animationManager.resetAll();
+ this.setup();
+}
+
+
+
+Graph.prototype.graphRepChangedCallback = function(newLayer, event)
+{
+ this.animationManager.setAllLayers([0,newLayer]);
+ this.currentLayer = newLayer;
+}
+
+
+Graph.prototype.recolorGraph = function()
+{
+ for (var i = 0; i < this.size; i++)
+ {
+ for (var j = 0; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] >= 0)
+ {
+ this.setEdgeColor(i, j, EDGE_COLOR);
+ }
+ }
+ }
+}
+
+Graph.prototype.highlightEdge = function(i,j, highlightVal)
+{
+ this.cmd("SetHighlight", this.adj_list_edges[i][j], highlightVal);
+ this.cmd("SetHighlight", this.adj_matrixID[i][j], highlightVal);
+ this.cmd("SetEdgeHighlight", this.circleID[i], this.circleID[j], highlightVal);
+ if (!this.directed)
+ {
+ this.cmd("SetEdgeHighlight", this.circleID[j], this.circleID[i], highlightVal);
+ }
+}
+
+Graph.prototype.setEdgeColor = function(i,j, color)
+{
+ this.cmd("SetForegroundColor", this.adj_list_edges[i][j], color);
+ this.cmd("SetTextColor", this.adj_matrixID[i][j], color);
+ this.cmd("SetEdgeColor", this.circleID[i], this.circleID[j], color);
+ if (!this.directed)
+ {
+ this.cmd("SetEdgeColor", this.circleID[j], this.circleID[i], color);
+ }
+}
+
+
+
+Graph.prototype.clearEdges = function()
+{
+ for (var i = 0; i < this.size; i++)
+ {
+ for (var j = 0; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] >= 0)
+ {
+ this.cmd("Disconnect", this.circleID[i], this.circleID[j]);
+ }
+ }
+ }
+}
+
+
+Graph.prototype.rebuildEdges = function()
+{
+ this.clearEdges();
+ this.buildEdges();
+}
+
+
+
+Graph.prototype.buildEdges = function()
+{
+
+ for (var i = 0; i < this.size; i++)
+ {
+ for (var j = 0; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] >= 0)
+ {
+ var edgeLabel;
+ if (this.showEdgeCosts)
+ {
+ edgeLabel = String(this.adj_matrix[i][j]);
+ }
+ else
+ {
+ edgeLabel = "";
+ }
+ if (this.directed)
+ {
+ this.cmd("Connect", this.circleID[i], this.circleID[j], EDGE_COLOR, this.adjustCurveForDirectedEdges(this.curve[i][j], this.adj_matrix[j][i] >= 0), 1, edgeLabel);
+ }
+ else if (i < j)
+ {
+ this.cmd("Connect", this.circleID[i], this.circleID[j], EDGE_COLOR, this.curve[i][j], 0, edgeLabel);
+ }
+ }
+ }
+ }
+
+}
+
+Graph.prototype.setup_small = function()
+{
+ this.allowed = SMALL_ALLLOWED;
+ this.curve = SMALL_CURVE;
+ this. x_pos_logical = SMALL_X_POS_LOGICAL;
+ this. y_pos_logical = SMALL_Y_POS_LOGICAL;
+ this.adj_matrix_x_start = SMALL_ADJ_MATRIX_X_START;
+ this.adj_matrix_y_start = SMALL_ADJ_MATRIX_Y_START;
+ this.adj_matrix_width = SMALL_ADJ_MATRIX_WIDTH;
+ this.adj_matrix_height = SMALL_ADJ_MATRIX_HEIGHT;
+ this.adj_list_x_start = SMALL_ADJ_LIST_X_START;
+ this.adj_list_y_start = SMALL_ADJ_LIST_Y_START;
+ this.adj_list_elem_width = SMALL_ADJ_LIST_ELEM_WIDTH;
+ this.adj_list_elem_height = SMALL_ADJ_LIST_ELEM_HEIGHT;
+ this.adj_list_height = SMALL_ADJ_LIST_HEIGHT;
+ this.adj_list_width = SMALL_ADJ_LIST_WIDTH;
+ this.adj_list_spacing = SMALL_ADJ_LIST_SPACING;
+ this.size = SMALL_SIZE;
+ this.setup();
+}
+
+Graph.prototype.setup_large = function()
+{
+ this.allowed = LARGE_ALLOWED;
+ this.curve = LARGE_CURVE;
+ this. x_pos_logical = LARGE_X_POS_LOGICAL;
+ this. y_pos_logical = LARGE_Y_POS_LOGICAL;
+ this.adj_matrix_x_start = LARGE_ADJ_MATRIX_X_START;
+ this.adj_matrix_y_start = LARGE_ADJ_MATRIX_Y_START;
+ this.adj_matrix_width = LARGE_ADJ_MATRIX_WIDTH;
+ this.adj_matrix_height = LARGE_ADJ_MATRIX_HEIGHT;
+ this.adj_list_x_start = LARGE_ADJ_LIST_X_START;
+ this.adj_list_y_start = LARGE_ADJ_LIST_Y_START;
+ this.adj_list_elem_width = LARGE_ADJ_LIST_ELEM_WIDTH;
+ this.adj_list_elem_height = LARGE_ADJ_LIST_ELEM_HEIGHT;
+ this.adj_list_height = LARGE_ADJ_LIST_HEIGHT;
+ this.adj_list_width = LARGE_ADJ_LIST_WIDTH;
+ this.adj_list_spacing = LARGE_ADJ_LIST_SPACING;
+ this.size = LARGE_SIZE;
+ this.setup();
+}
+
+Graph.prototype.adjustCurveForDirectedEdges = function(curve, bidirectional)
+{
+ if (!bidirectional || Math.abs(curve) > 0.01)
+ {
+ return curve;
+ }
+ else
+ {
+ return 0.1;
+ }
+
+}
+
+Graph.prototype.setup = function()
+{
+ this.commands = new Array();
+ this.circleID = new Array(this.size);
+ for (var i = 0; i < this.size; i++)
+ {
+ this.circleID[i] = this.nextIndex++;
+ this.cmd("CreateCircle", this.circleID[i], i, this. x_pos_logical[i], this. y_pos_logical[i]);
+ this.cmd("SetTextColor", this.circleID[i], VERTEX_INDEX_COLOR, 0);
+
+ this.cmd("SetLayer", this.circleID[i], 1);
+ }
+
+ this.adj_matrix = new Array(this.size);
+ this.adj_matrixID = new Array(this.size);
+ for (i = 0; i < this.size; i++)
+ {
+ this.adj_matrix[i] = new Array(this.size);
+ this.adj_matrixID[i] = new Array(this.size);
+ }
+
+ var edgePercent;
+ if (this.size == SMALL_SIZE)
+ {
+ if (this.directed)
+ {
+ edgePercent = 0.4;
+ }
+ else
+ {
+ edgePercent = 0.5;
+ }
+
+ }
+ else
+ {
+ if (this.directed)
+ {
+ edgePercent = 0.35;
+ }
+ else
+ {
+ edgePercent = 0.6;
+ }
+
+ }
+
+ var lowerBound = 0;
+
+ if (this.directed)
+ {
+ for (i = 0; i < this.size; i++)
+ {
+ for (var j = 0; j < this.size; j++)
+ {
+ this.adj_matrixID[i][j] = this.nextIndex++;
+ if ((this.allowed[i][j]) && Math.random() <= edgePercent && (i < j || Math.abs(this.curve[i][j]) < 0.01 || this.adj_matrixID[j][i] == -1) && (!this.isDAG || (i < j)))
+ {
+ if (this.showEdgeCosts)
+ {
+ this.adj_matrix[i][j] = Math.floor(Math.random()* 9) + 1;
+ }
+ else
+ {
+ this.adj_matrix[i][j] = 1;
+ }
+
+ }
+ else
+ {
+ this.adj_matrix[i][j] = -1;
+ }
+
+ }
+ }
+ this.buildEdges();
+
+ }
+ else
+ {
+ for (i = 0; i < this.size; i++)
+ {
+ for (j = i+1; j < this.size; j++)
+ {
+
+ this.adj_matrixID[i][j] = this.nextIndex++;
+ this.adj_matrixID[j][i] = this.nextIndex++;
+
+ if ((this.allowed[i][j]) && Math.random() <= edgePercent)
+ {
+ if (this.showEdgeCosts)
+ {
+ this.adj_matrix[i][j] = Math.floor(Math.random()* 9) + 1;
+ }
+ else
+ {
+ this.adj_matrix[i][j] = 1;
+ }
+ this.adj_matrix[j][i] = this.adj_matrix[i][j];
+ if (this.showEdgeCosts)
+ {
+ var edgeLabel = String(this.adj_matrix[i][j]);
+ }
+ else
+ {
+ edgeLabel = "";
+ }
+ this.cmd("Connect", this.circleID[i], this.circleID[j], EDGE_COLOR, this.curve[i][j], 0, edgeLabel);
+ }
+ else
+ {
+ this.adj_matrix[i][j] = -1;
+ this.adj_matrix[j][i] = -1;
+ }
+
+ }
+ }
+
+ this.buildEdges();
+
+
+ for (i=0; i < this.size; i++)
+ {
+ this.adj_matrix[i][i] = -1;
+ }
+
+ }
+
+
+ // Craate Adj List
+
+
+ this.buildAdjList();
+
+
+ // Create Adj Matrix
+
+ this.buildAdjMatrix();
+
+
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.clearHistory();
+}
+
+Graph.prototype.resetAll = function()
+{
+
+}
+
+
+Graph.prototype.buildAdjMatrix = function()
+{
+
+ this.adj_matrix_index_x = new Array(this.size);
+ this.adj_matrix_index_y = new Array(this.size);
+ for (var i = 0; i < this.size; i++)
+ {
+ this.adj_matrix_index_x[i] = this.nextIndex++;
+ this.adj_matrix_index_y[i] = this.nextIndex++;
+ this.cmd("CreateLabel", this.adj_matrix_index_x[i], i, this.adj_matrix_x_start + i*this.adj_matrix_width, this.adj_matrix_y_start - this.adj_matrix_height);
+ this.cmd("SetForegroundColor", this.adj_matrix_index_x[i], VERTEX_INDEX_COLOR);
+ this.cmd("CreateLabel", this.adj_matrix_index_y[i], i, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + i* this.adj_matrix_height);
+ this.cmd("SetForegroundColor", this.adj_matrix_index_y[i], VERTEX_INDEX_COLOR);
+ this.cmd("SetLayer", this.adj_matrix_index_x[i], 3);
+ this.cmd("SetLayer", this.adj_matrix_index_y[i], 3);
+
+ for (var j = 0; j < this.size; j++)
+ {
+ this.adj_matrixID[i][j] = this.nextIndex++;
+ if (this.adj_matrix[i][j] < 0)
+ {
+ var lab = ""
+ }
+ else
+ {
+ lab = String(this.adj_matrix[i][j])
+ }
+ this.cmd("CreateRectangle", this.adj_matrixID[i][j], lab, this.adj_matrix_width, this.adj_matrix_height,
+ this.adj_matrix_x_start + j*this.adj_matrix_width,this.adj_matrix_y_start + i * this.adj_matrix_height);
+ this.cmd("SetLayer", this.adj_matrixID[i][j], 3);
+
+
+ }
+ }
+}
+
+
+
+Graph.prototype.removeAdjList = function()
+{
+ for (var i = 0; i < this.size; i++)
+ {
+ this.cmd("Delete", this.adj_list_list[i], "RAL1");
+ this.cmd("Delete", this.adj_list_index[i], "RAL2");
+ for (var j = 0; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] > 0)
+ {
+ this.cmd("Delete", this.adj_list_edges[i][j], "RAL3");
+ }
+ }
+ }
+
+}
+
+
+Graph.prototype.buildAdjList = function()
+{
+ this.adj_list_index = new Array(this.size);
+ this.adj_list_list = new Array(this.size);
+ this.adj_list_edges = new Array(this.size);
+
+ for (var i = 0; i < this.size; i++)
+ {
+ this.adj_list_index[i] = this.nextIndex++;
+ this.adj_list_edges[i] = new Array(this.size);
+ this.adj_list_index[i] = this.nextIndex++;
+ this.adj_list_list[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.adj_list_list[i], "", this.adj_list_width, this.adj_list_height, this.adj_list_x_start, this.adj_list_y_start + i*this.adj_list_height);
+ this.cmd("SetLayer", this.adj_list_list[i], 2);
+ this.cmd("CreateLabel", this.adj_list_index[i], i, this.adj_list_x_start - this.adj_list_width , this.adj_list_y_start + i*this.adj_list_height);
+ this.cmd("SetForegroundColor", this.adj_list_index[i], VERTEX_INDEX_COLOR);
+ this.cmd("SetLayer", this.adj_list_index[i], 2);
+ var lastElem = this.adj_list_list[i];
+ var nextXPos = this.adj_list_x_start + this.adj_list_width + this.adj_list_spacing;
+ var hasEdges = false;
+ for (var j = 0; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] > 0)
+ {
+ hasEdges = true;
+ this.adj_list_edges[i][j] = this.nextIndex++;
+ this.cmd("CreateLinkedList",this.adj_list_edges[i][j], j,this.adj_list_elem_width, this.adj_list_elem_height,
+ nextXPos, this.adj_list_y_start + i*this.adj_list_height, 0.25, 0, 1, 2);
+ this.cmd("SetNull", this.adj_list_edges[i][j], 1);
+ this.cmd("SetText", this.adj_list_edges[i][j], this.adj_matrix[i][j], 1);
+ this.cmd("SetTextColor", this.adj_list_edges[i][j], VERTEX_INDEX_COLOR, 0);
+ this.cmd("SetLayer", this.adj_list_edges[i][j], 2);
+
+ nextXPos = nextXPos + this.adj_list_elem_width + this.adj_list_spacing;
+ this.cmd("Connect", lastElem, this.adj_list_edges[i][j]);
+ this.cmd("SetNull", lastElem, 0);
+ lastElem = this.adj_list_edges[i][j];
+ }
+ }
+ if (!hasEdges)
+ {
+ this.cmd("SetNull", this.adj_list_list[i], 1);
+ }
+ }
+}
+
+
+
+
+// NEED TO OVERRIDE IN PARENT
+Graph.prototype.reset = function()
+{
+ // Throw an error?
+}
+
+
+Graph.prototype.disableUI = function(event)
+{
+ this.newGraphButton.disabled = true;
+ if (this.directedGraphButton != null && this.directedGraphButton != undefined)
+ this.directedGraphButton.disabled = true;
+ if (this.undirectedGraphButton != null && this.undirectedGraphButton != undefined)
+ this.undirectedGraphButton.disabled = true;
+ this.smallGraphButton.disabled = true;
+ this.largeGraphButton.disabled = true;
+}
+
+
+
+Graph.prototype.enableUI = function(event)
+{
+
+ this.newGraphButton.disabled = false;
+ if (this.directedGraphButton != null && this.directedGraphButton != undefined)
+ this.directedGraphButton.disabled = false;
+ if (this.undirectedGraphButton != null && this.undirectedGraphButton != undefined)
+ this.undirectedGraphButton.disabled = false;
+ this.smallGraphButton.disabled = false;
+ this.largeGraphButton.disabled = false;
+}
+
+
+
+/* no init, this is only a base class! */
+ var currentAlg;
+ function init()
+ {
+ var animManag = initCanvas();
+ currentAlg = new Graph(animManag, canvas.width, canvas.height);
+}
+
+
+
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Hash.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Hash.js
new file mode 100644
index 0000000..71c40cb
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Hash.js
@@ -0,0 +1,460 @@
+// 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 ``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 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
+
+
+function Hash(am, w, h)
+{
+ if (am == undefined)
+ {
+ return;
+ }
+ this.init(am, w, h);
+}
+
+Hash.prototype = new Algorithm();
+Hash.prototype.constructor = Hash;
+Hash.superclass = Algorithm.prototype;
+
+var MAX_HASH_LENGTH = 10;
+
+
+var HASH_NUMBER_START_X = 200;
+var HASH_X_DIFF = 7;
+var HASH_NUMBER_START_Y = 10;
+var HASH_ADD_START_Y = 30;
+var HASH_INPUT_START_X = 60;
+var HASH_INPUT_X_DIFF = 7;
+var HASH_INPUT_START_Y = 45;
+var HASH_ADD_LINE_Y = 42;
+var HASH_RESULT_Y = 50;
+var ELF_HASH_SHIFT = 10;
+
+var HASH_LABEL_X = 300;
+var HASH_LABEL_Y = 30;
+var HASH_LABEL_DELTA_X = 50;
+
+var HIGHLIGHT_COLOR = "#0000FF";
+
+
+
+Hash.prototype.init = function(am, w, h)
+{
+ var sc = Hash.superclass;
+ var fn = sc.init;
+ fn.call(this,am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.hashingIntegers = true;
+
+}
+
+Hash.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.size = MAX_HASH_LENGTH;
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), MAX_HASH_LENGTH, true);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.size = MAX_HASH_LENGTH;
+ this.deleteField.onkeydown = this.returnSubmit(this.insertField, this.deleteCallback.bind(this), MAX_HASH_LENGTH, true);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+
+
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.size = MAX_HASH_LENGTH;
+ this.findField.onkeydown = this.returnSubmit(this.insertField, this.findCallback.bind(this), MAX_HASH_LENGTH, true);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Hash Integer", "Hash Strings"], "HashType");
+ this.hashIntegerButton = radioButtonList[0];
+ this.hashIntegerButton.onclick = this.changeHashTypeCallback.bind(this, true);
+// this.hashIntegerButton.onclick = this.hashIntegerCallback.bind(this);
+ this.hashStringButton = radioButtonList[1];
+ this.hashStringButton.onclick = this.changeHashTypeCallback.bind(this, false);
+
+// this.hashStringButton.onclick = this.hashStringCallback.bind(this);
+ this.hashIntegerButton.checked = true;
+}
+
+
+// Do this extra level of wrapping to get undo to work properly.
+// (also, so that we only implement the action if we are changing the
+// radio button)
+Hash.prototype.changeHashTypeCallback = function(newHashingIntegers, event)
+{
+ if (this.hashingIntegers != newHashingIntegers)
+ {
+ this.implementAction(this.changeHashType.bind(this), newHashingIntegers);
+ }
+
+}
+
+Hash.prototype.changeHashType = function(newHashingIntegerValue)
+{
+ this.hashingIntegers = newHashingIntegerValue;
+ if (this.hashingIntegers)
+ {
+ this.hashIntegerButton.checked = true;
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), MAX_HASH_LENGTH, true);
+ this.deleteField.onkeydown = this.returnSubmit(this.insertField, this.deleteCallback.bind(this), MAX_HASH_LENGTH, true);
+ this.findField.onkeydown = this.returnSubmit(this.insertField, this.findCallback.bind(this), MAX_HASH_LENGTH, true);
+ }
+ else
+ {
+ this.hashStringButton.checked = true;
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), MAX_HASH_LENGTH, false);
+ this.deleteField.onkeydown = this.returnSubmit(this.insertField, this.deleteCallback.bind(this), MAX_HASH_LENGTH, false);
+ this.findField.onkeydown = this.returnSubmit(this.insertField, this.findCallback.bind(this), MAX_HASH_LENGTH, false);
+ }
+ return this.resetAll();
+}
+
+
+Hash.prototype.doHash = function(input)
+{
+ if (this.hashingIntegers)
+ {
+ var labelID1 = this.nextIndex++;
+ var labelID2 = this.nextIndex++;
+ var highlightID = this.nextIndex++;
+ var index = parseInt(input) % this.table_size;
+ this.currHash = parseInt(input);
+
+ this.cmd("CreateLabel", labelID1, input + " % " + String(this.table_size) + " = " , HASH_LABEL_X, HASH_LABEL_Y);
+ this.cmd("CreateLabel", labelID2,index, HASH_LABEL_X + HASH_LABEL_DELTA_X, HASH_LABEL_Y);
+ this.cmd("Step");
+ this.cmd("CreateHighlightCircle", highlightID, HIGHLIGHT_COLOR, HASH_LABEL_X + HASH_LABEL_DELTA_X, HASH_LABEL_Y);
+ this.cmd("Move", highlightID, this.indexXPos[index], this.indexYPos[index]);
+ this.cmd("Step");
+ this.cmd("Delete", labelID1);
+ this.cmd("Delete", labelID2);
+ this.cmd("Delete", highlightID);
+ this.nextIndex -= 3;
+
+ return index;
+
+ }
+ else
+ {
+ var oldnextIndex = this.nextIndex;
+ var label1= this.nextIndex++;
+ this.cmd("CreateLabel", label1, "Hashing:" , 10, 45, 0);
+ var wordToHashID = new Array(input.length);
+ var wordToHash = new Array(input.length);
+ for (var i = 0; i < input.length; i++)
+ {
+ wordToHashID[i] = this.nextIndex++;
+ wordToHash[i] = input.charAt(i);
+ this.cmd("CreateLabel", wordToHashID[i], wordToHash[i], HASH_INPUT_START_X + i * HASH_INPUT_X_DIFF, HASH_INPUT_START_Y, 0);
+ }
+ var digits = new Array(32);
+ var hashValue = new Array(32);
+ var nextByte = new Array(8);
+ var nextByteID = new Array(8);
+ var resultDigits = new Array(32);
+ var floatingDigits = new Array(4);
+ var floatingVals = new Array(4);
+
+ var operatorID = this.nextIndex++;
+ var barID = this.nextIndex++;
+ for (i = 0; i < 32; i++)
+ {
+ hashValue[i] = 0;
+ digits[i] = this.nextIndex++;
+ resultDigits[i] = this.nextIndex++;
+ }
+ for (i=0; i<8; i++)
+ {
+ nextByteID[i] = this.nextIndex++;
+ }
+ for (i = 0; i < 4; i++)
+ {
+ floatingDigits[i] = this.nextIndex++;
+ }
+ this.cmd("Step");
+ for (i = wordToHash.length-1; i >= 0; i--)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ this.cmd("CreateLabel", digits[j],hashValue[j], HASH_NUMBER_START_X + j * HASH_X_DIFF, HASH_NUMBER_START_Y, 0);
+ }
+ this.cmd("Delete", wordToHashID[i]);
+ var nextChar = wordToHash[i].charCodeAt(0);
+ for (var j = 7; j >= 0; j--)
+ {
+ nextByte[j] = nextChar % 2;
+ nextChar = Math.floor((nextChar / 2));
+ this.cmd("CreateLabel", nextByteID[j], nextByte[j], HASH_INPUT_START_X + i*HASH_INPUT_X_DIFF, HASH_INPUT_START_Y, 0);
+ this.cmd("Move", nextByteID[j], HASH_NUMBER_START_X + (j + 24) * HASH_X_DIFF, HASH_ADD_START_Y);
+ }
+ this.cmd("Step");
+ this.cmd("CreateRectangle", barID, "", 32 * HASH_X_DIFF, 0, HASH_NUMBER_START_X, HASH_ADD_LINE_Y,"left","bottom");
+ this.cmd("CreateLabel", operatorID, "+", HASH_NUMBER_START_X, HASH_ADD_START_Y, 0);
+ this.cmd("Step");
+
+ var carry = 0;
+ for (j = 7; j>=0; j--)
+ {
+ hashValue[j+24] = hashValue[j+24] + nextByte[j] + carry;
+ if (hashValue[j+24] > 1)
+ {
+ hashValue[j+24] = hashValue[j+24] - 2;
+ carry = 1;
+ }
+ else
+ {
+ carry = 0;
+ }
+ }
+ for (j = 23; j>=0; j--)
+ {
+ hashValue[j] = hashValue[j] + carry;
+ if (hashValue[j] > 1)
+ {
+ hashValue[j] = hashValue[j] - 2;
+ carry = 1;
+ }
+ else
+ {
+ carry = 0;
+ }
+ }
+ for (j = 0; j < 32; j++)
+ {
+ this.cmd("CreateLabel", resultDigits[j], hashValue[j], HASH_NUMBER_START_X + j * HASH_X_DIFF, HASH_RESULT_Y, 0);
+ }
+
+ this.cmd("Step");
+ for (j=0; j<8; j++)
+ {
+ this.cmd("Delete", nextByteID[j]);
+ }
+ this.cmd("Delete", barID);
+ this.cmd("Delete", operatorID);
+ for (j = 0; j<32; j++)
+ {
+ this.cmd("Delete", digits[j]);
+ this.cmd("Move", resultDigits[j], HASH_NUMBER_START_X + j * HASH_X_DIFF, HASH_NUMBER_START_Y)
+ }
+ this.cmd("Step");
+ if (i > 0)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ this.cmd("Move", resultDigits[j], HASH_NUMBER_START_X + (j - 4) * HASH_X_DIFF, HASH_NUMBER_START_Y)
+ }
+ this.cmd("Step");
+ for (j = 0; j < 28; j++)
+ {
+ floatingVals[j] = hashValue[j];
+ hashValue[j] = hashValue[j+4];
+ }
+
+ for (j = 0; j < 4; j++)
+ {
+ this.cmd("Move", resultDigits[j], HASH_NUMBER_START_X + (j + ELF_HASH_SHIFT) * HASH_X_DIFF, HASH_ADD_START_Y);
+ hashValue[j+28] = 0;
+ this.cmd("CreateLabel", floatingDigits[j],0, HASH_NUMBER_START_X + (j + 28) * HASH_X_DIFF, HASH_NUMBER_START_Y,0);
+ if (floatingVals[j])
+ {
+ hashValue[j + ELF_HASH_SHIFT] = 1 - hashValue[j + ELF_HASH_SHIFT];
+ }
+ }
+ this.cmd("CreateRectangle", barID, "", 32 * HASH_X_DIFF, 0, HASH_NUMBER_START_X, HASH_ADD_LINE_Y,"left","bottom");
+ this.cmd("CreateLabel", operatorID, "XOR", HASH_NUMBER_START_X, HASH_ADD_START_Y, 0);
+ this.cmd("Step");
+ for (j = 0; j < 32; j++)
+ {
+ this.cmd("CreateLabel", digits[j], hashValue[j], HASH_NUMBER_START_X + j * HASH_X_DIFF, HASH_RESULT_Y, 0);
+ }
+ this.cmd("Step");
+
+ this.cmd("Delete", operatorID);
+ this.cmd("Delete", barID);
+ for (j = 0; j<32; j++)
+ {
+ this.cmd("Delete", resultDigits[j]);
+ this.cmd("Move", digits[j], HASH_NUMBER_START_X + j * HASH_X_DIFF, HASH_NUMBER_START_Y)
+ }
+ for (j = 0; j < 4; j++)
+ {
+ this.cmd("Delete", floatingDigits[j]);
+ }
+ this.cmd("Step");
+ for (j = 0; j<32; j++)
+ {
+ this.cmd("Delete", digits[j]);
+ }
+ }
+ else
+ {
+ for (j = 0; j<32; j++)
+ {
+ this.cmd("Delete", resultDigits[j]);
+ }
+ }
+
+ }
+ this.cmd("Delete", label1);
+ for (j = 0; j < 32; j++)
+ {
+ this.cmd("CreateLabel", digits[j],hashValue[j], HASH_NUMBER_START_X + j * HASH_X_DIFF, HASH_NUMBER_START_Y, 0);
+ }
+ this.currHash = 0;
+ for (j=0; j < 32; j++)
+ {
+ this.currHash = this.currHash * 2 + hashValue[j];
+ }
+ this.cmd("CreateLabel", label1, " = " + String(this.currHash), HASH_NUMBER_START_X + 32*HASH_X_DIFF, HASH_NUMBER_START_Y, 0);
+ this.cmd("Step");
+ for (j = 0; j < 32; j++)
+ {
+ this.cmd("Delete", digits[j]);
+ }
+
+ var label2 = this.nextIndex++;
+ this.cmd("SetText", label1, String(this.currHash) + " % " + String(this.table_size) + " = ");
+ index = this.currHash % this.table_size;
+ this.cmd("CreateLabel", label2, index, HASH_NUMBER_START_X + 32*HASH_X_DIFF + 105, HASH_NUMBER_START_Y, 0);
+ this.cmd("Step");
+ highlightID = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", highlightID, HIGHLIGHT_COLOR, HASH_NUMBER_START_X + 30*HASH_X_DIFF + 120, HASH_NUMBER_START_Y+ 15);
+ this.cmd("Move", highlightID, this.indexXPos[index], this.indexYPos[index]);
+ this.cmd("Step");
+ this.cmd("Delete", highlightID);
+ this.cmd("Delete", label1);
+ this.cmd("Delete", label2);
+ //this.nextIndex = oldnextIndex;
+
+ return index;
+ }
+}
+
+
+
+
+Hash.prototype.resetAll =function()
+{
+ this.insertField.value = "";
+ this.deleteField.value = "";
+ this.findField.value = "";
+ return [];
+
+}
+Hash.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value;
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+Hash.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value
+ if (deletedValue != "")
+ {
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+Hash.prototype.findCallback = function(event)
+{
+ var findValue = this.findField.value;
+ if (findValue != "")
+ {
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+ }
+}
+
+
+
+
+
+
+Hash.prototype.insertElement = function(elem)
+{
+
+}
+
+Hash.prototype.deleteElement = function(elem)
+{
+
+
+}
+Hash.prototype.findElement = function(elem)
+{
+
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+Hash.prototype.reset = function()
+{
+ this.hashIntegerButton.checked = true;
+}
+
+
+Hash.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+}
+
+Hash.prototype.enableUI = function(event)
+{
+
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+}
+
+
+/* no init, this is only a base class!
+var currentAlg;
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Hash(animManag, canvas.width, canvas.height);
+}
+*/
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Heap.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Heap.js
new file mode 100644
index 0000000..8af9167
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Heap.js
@@ -0,0 +1,404 @@
+// 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 ``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 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
+
+
+function Heap(am)
+{
+ this.init(am);
+
+}
+
+Heap.prototype = new Algorithm();
+Heap.prototype.constructor = Heap;
+Heap.superclass = Algorithm.prototype;
+
+
+
+var ARRAY_SIZE = 32;
+var ARRAY_ELEM_WIDTH = 30;
+var ARRAY_ELEM_HEIGHT = 25;
+var ARRAY_INITIAL_X = 30;
+
+var ARRAY_Y_POS = 50;
+var ARRAY_LABEL_Y_POS = 70;
+
+
+Heap.prototype.init = function(am)
+{
+ var sc = Heap.superclass;
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.HeapXPositions = [0, 450, 250, 650, 150, 350, 550, 750, 100, 200, 300, 400, 500, 600,
+ 700, 800, 075, 125, 175, 225, 275, 325, 375, 425, 475, 525, 575,
+ 625, 675, 725, 775, 825];
+ this.HeapYPositions = [0, 100, 170, 170, 240, 240, 240, 240, 310, 310, 310, 310, 310, 310,
+ 310, 310, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+ 380, 380, 380, 380, 380];
+ this.commands = [];
+ this.createArray();
+
+
+ /*this.nextIndex = 0;
+ this.this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 50, 0);
+ this.animationManager.StartNewAnimation(this.this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory(); */
+
+}
+
+Heap.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4, true);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.removeSmallestButton = addControlToAlgorithmBar("Button", "Remove Smallest");
+ this.removeSmallestButton.onclick = this.removeSmallestCallback.bind(this);
+ this.clearHeapButton = addControlToAlgorithmBar("Button", "Clear Heap");
+ this.clearHeapButton.onclick = this.clearCallback.bind(this);
+ this.buildHeapButton = addControlToAlgorithmBar("Button", "BuildHeap");
+ this.buildHeapButton.onclick = this.buildHeapCallback.bind(this);
+}
+
+
+
+Heap.prototype.createArray = function()
+{
+ this.arrayData = new Array(ARRAY_SIZE);
+ this.arrayLabels = new Array(ARRAY_SIZE);
+ this.arrayRects = new Array(ARRAY_SIZE);
+ this.circleObjs = new Array(ARRAY_SIZE);
+ this.ArrayXPositions = new Array(ARRAY_SIZE);
+ this.currentHeapSize = 0;
+
+ for (var i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.ArrayXPositions[i] = ARRAY_INITIAL_X + i *ARRAY_ELEM_WIDTH;
+ this.arrayLabels[i] = this.nextIndex++;
+ this.arrayRects[i] = this.nextIndex++;
+ this.circleObjs[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.arrayRects[i], "", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, this.ArrayXPositions[i] , ARRAY_Y_POS)
+ this.cmd("CreateLabel", this.arrayLabels[i], i, this.ArrayXPositions[i], ARRAY_LABEL_Y_POS);
+ this.cmd("SetForegroundColor", this.arrayLabels[i], "#0000FF");
+ }
+ this.cmd("SetText", this.arrayRects[0], "-INF");
+ this.swapLabel1 = this.nextIndex++;
+ this.swapLabel2 = this.nextIndex++;
+ this.swapLabel3 = this.nextIndex++;
+ this.swapLabel4 = this.nextIndex++;
+ this.descriptLabel1 = this.nextIndex++;
+ this.descriptLabel2 = this.nextIndex++;
+ this.cmd("CreateLabel", this.descriptLabel1, "", 20, 10, 0);
+ //this.cmd("CreateLabel", this.descriptLabel2, "", this.nextIndex, 40, 120, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+Heap.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+//TODO: Make me undoable!!
+Heap.prototype.clearCallback = function(event)
+{
+ this.commands = new Array();
+ this.implementAction(this.clear.bind(this),"");
+}
+
+//TODO: Make me undoable!!
+Heap.prototype.clear = function()
+{
+
+ while (this.currentHeapSize > 0)
+ {
+ this.cmd("Delete", this.circleObjs[this.currentHeapSize]);
+ this.cmd("SetText", this.arrayRects[this.currentHeapSize], "");
+ this.currentHeapSize--;
+ }
+ return this.commands;
+}
+
+
+Heap.prototype.reset = function()
+{
+ this.currentHeapSize = 0;
+}
+
+Heap.prototype.removeSmallestCallback = function(event)
+{
+ this.implementAction(this.removeSmallest.bind(this),"");
+}
+
+
+Heap.prototype.swap = function(index1, index2)
+{
+ this.cmd("SetText", this.arrayRects[index1], "");
+ this.cmd("SetText", this.arrayRects[index2], "");
+ this.cmd("SetText", this.circleObjs[index1], "");
+ this.cmd("SetText", this.circleObjs[index2], "");
+ this.cmd("CreateLabel", this.swapLabel1, this.arrayData[index1], this.ArrayXPositions[index1],ARRAY_Y_POS);
+ this.cmd("CreateLabel", this.swapLabel2, this.arrayData[index2], this.ArrayXPositions[index2],ARRAY_Y_POS);
+ this.cmd("CreateLabel", this.swapLabel3, this.arrayData[index1], this.HeapXPositions[index1],this.HeapYPositions[index1]);
+ this.cmd("CreateLabel", this.swapLabel4, this.arrayData[index2], this.HeapXPositions[index2],this.HeapYPositions[index2]);
+ this.cmd("Move", this.swapLabel1, this.ArrayXPositions[index2],ARRAY_Y_POS)
+ this.cmd("Move", this.swapLabel2, this.ArrayXPositions[index1],ARRAY_Y_POS)
+ this.cmd("Move", this.swapLabel3, this.HeapXPositions[index2],this.HeapYPositions[index2])
+ this.cmd("Move", this.swapLabel4, this.HeapXPositions[index1],this.HeapYPositions[index1])
+ var tmp = this.arrayData[index1];
+ this.arrayData[index1] = this.arrayData[index2];
+ this.arrayData[index2] = tmp;
+ this.cmd("Step")
+ this.cmd("SetText", this.arrayRects[index1], this.arrayData[index1]);
+ this.cmd("SetText", this.arrayRects[index2], this.arrayData[index2]);
+ this.cmd("SetText", this.circleObjs[index1], this.arrayData[index1]);
+ this.cmd("SetText", this.circleObjs[index2], this.arrayData[index2]);
+ this.cmd("Delete", this.swapLabel1);
+ this.cmd("Delete", this.swapLabel2);
+ this.cmd("Delete", this.swapLabel3);
+ this.cmd("Delete", this.swapLabel4);
+
+
+}
+
+
+Heap.prototype.setIndexHighlight = function(index, highlightVal)
+{
+ this.cmd("SetHighlight", this.circleObjs[index], highlightVal);
+ this.cmd("SetHighlight", this.arrayRects[index], highlightVal);
+}
+
+Heap.prototype.pushDown = function(index)
+{
+ var smallestIndex;
+
+ while(true)
+ {
+ if (index*2 > this.currentHeapSize)
+ {
+ return;
+ }
+
+ smallestIndex = 2*index;
+
+ if (index*2 + 1 <= this.currentHeapSize)
+ {
+ this.setIndexHighlight(2*index, 1);
+ this.setIndexHighlight(2*index + 1, 1);
+ this.cmd("Step");
+ this.setIndexHighlight(2*index, 0);
+ this.setIndexHighlight(2*index + 1, 0);
+ if (this.arrayData[2*index + 1] < this.arrayData[2*index])
+ {
+ smallestIndex = 2*index + 1;
+ }
+ }
+ this.setIndexHighlight(index, 1);
+ this.setIndexHighlight(smallestIndex, 1);
+ this.cmd("Step");
+ this.setIndexHighlight(index, 0);
+ this.setIndexHighlight(smallestIndex, 0);
+
+ if (this.arrayData[smallestIndex] < this.arrayData[index])
+ {
+ this.swap(smallestIndex, index);
+ index = smallestIndex;
+ }
+ else
+ {
+ return;
+ }
+
+
+
+ }
+}
+
+Heap.prototype.removeSmallest = function(dummy)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.descriptLabel1, "");
+
+ if (this.currentHeapSize == 0)
+ {
+ this.cmd("SetText", this.descriptLabel1, "Heap is empty, cannot remove smallest element");
+ return this.commands;
+ }
+
+ this.cmd("SetText", this.descriptLabel1, "Removing element:");
+ this.cmd("CreateLabel", this.descriptLabel2, this.arrayData[1], this.HeapXPositions[1], this.HeapYPositions[1], 0);
+ this.cmd("SetText", this.circleObjs[1], "");
+ this.cmd("Move", this.descriptLabel2, 120, 40)
+ this.cmd("Step");
+ this.cmd("Delete", this.descriptLabel2);
+ this.cmd("SetText", this.descriptLabel1, "Removing element: " + this.arrayData[1]);
+ this.arrayData[1] = "";
+ if (this.currentHeapSize > 1)
+ {
+ this.cmd("SetText", this.arrayRects[1], "");
+ this.cmd("SetText", this.arrayRects[this.currentHeapSize], "");
+ this.swap(1,this.currentHeapSize);
+ this.cmd("Delete", this.circleObjs[this.currentHeapSize]);
+ this.currentHeapSize--;
+ this.pushDown(1);
+ } else {
+ this.cmd("SetText", this.arrayRects[1], "");
+ this.cmd("Delete", this.circleObjs[this.currentHeapSize]);
+ this.currentHeapSize--;
+
+ }
+ return this.commands;
+
+}
+
+Heap.prototype.buildHeapCallback = function(event)
+{
+ this.implementAction(this.buildHeap.bind(this),"");
+}
+
+Heap.prototype.buildHeap = function(ignored)
+{
+ this.commands = [];
+ this.clear();
+ for (var i = 1; i 1)
+ {
+ this.cmd("Connect", this.circleObjs[Math.floor(i/2)], this.circleObjs[i]);
+ }
+
+ }
+ this.cmd("Step");
+ this.currentHeapSize = ARRAY_SIZE - 1;
+ var nextElem = this.currentHeapSize;
+ while(nextElem > 0)
+ {
+ this.pushDown(nextElem);
+ nextElem = nextElem - 1;
+ }
+ return this.commands;
+}
+
+Heap.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+
+ if (this.currentHeapSize >= ARRAY_SIZE - 1)
+ {
+ this.cmd("SetText", this.descriptLabel1, "Heap Full!");
+ return this.commands;
+ }
+
+ this.cmd("SetText", this.descriptLabel1, "Inserting Element: " + insertedValue);
+ this.cmd("Step");
+ this.cmd("SetText", this.descriptLabel1, "Inserting Element: ");
+ this.currentHeapSize++;
+ this.arrayData[this.currentHeapSize] = insertedValue;
+ this.cmd("CreateCircle",this.circleObjs[this.currentHeapSize], "", this.HeapXPositions[this.currentHeapSize], this.HeapYPositions[this.currentHeapSize]);
+ this.cmd("CreateLabel", this.descriptLabel2, insertedValue, 120, 45, 1);
+ if (this.currentHeapSize > 1)
+ {
+ this.cmd("Connect", this.circleObjs[Math.floor(this.currentHeapSize / 2)], this.circleObjs[this.currentHeapSize]);
+ }
+
+ this.cmd("Move", this.descriptLabel2, this.HeapXPositions[this.currentHeapSize], this.HeapYPositions[this.currentHeapSize]);
+ this.cmd("Step");
+ this.cmd("SetText", this.circleObjs[this.currentHeapSize], insertedValue);
+ this.cmd("delete", this.descriptLabel2);
+ this.cmd("SetText", this.arrayRects[this.currentHeapSize], insertedValue);
+
+ var currentIndex = this.currentHeapSize;
+ var parentIndex = Math.floor(currentIndex / 2);
+
+ if (currentIndex > 1)
+ {
+ this.setIndexHighlight(currentIndex, 1);
+ this.setIndexHighlight(parentIndex, 1);
+ this.cmd("Step");
+ this.setIndexHighlight(currentIndex, 0);
+ this.setIndexHighlight(parentIndex, 0);
+ }
+
+ while (currentIndex > 1 && this.arrayData[currentIndex] < this.arrayData[parentIndex])
+ {
+ this.swap(currentIndex, parentIndex);
+ currentIndex = parentIndex;
+ parentIndex = Math.floor(parentIndex / 2);
+ if (currentIndex > 1)
+ {
+ this.setIndexHighlight(currentIndex, 1);
+ this.setIndexHighlight(parentIndex, 1);
+ this.cmd("Step");
+ this.setIndexHighlight(currentIndex, 0);
+ this.setIndexHighlight(parentIndex, 0);
+ }
+ }
+ this.cmd("SetText", this.descriptLabel1, "");
+
+ return this.commands;
+}
+
+Heap.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.removeSmallestButton.disabled = true;
+ this.clearHeapButton.disabled = true;
+ this.buildHeapButton.disabled = true;
+}
+
+Heap.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.removeSmallestButton.disabled = false;
+ this.clearHeapButton.disabled = false;
+ this.buildHeapButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Heap(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/HeapSort.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/HeapSort.js
new file mode 100644
index 0000000..d753d4e
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/HeapSort.js
@@ -0,0 +1,305 @@
+// 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 ``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 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
+
+
+function HeapSort(am)
+{
+ this.init(am);
+
+}
+
+HeapSort.prototype = new Algorithm();
+HeapSort.prototype.constructor = HeapSort;
+HeapSort.superclass = Algorithm.prototype;
+
+
+
+var ARRAY_SIZE = 32;
+var ARRAY_ELEM_WIDTH = 30;
+var ARRAY_ELEM_HEIGHT = 25;
+var ARRAY_INITIAL_X = 30;
+
+var ARRAY_Y_POS = 50;
+var ARRAY_LABEL_Y_POS = 70;
+
+
+HeapSort.prototype.init = function(am)
+{
+ var sc = HeapSort.superclass;
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.HeapXPositions = [0, 450, 250, 650, 150, 350, 550, 750, 100, 200, 300, 400, 500, 600,
+ 700, 800, 075, 125, 175, 225, 275, 325, 375, 425, 475, 525, 575,
+ 625, 675, 725, 775, 825];
+ this.HeapYPositions = [0, 100, 170, 170, 240, 240, 240, 240, 310, 310, 310, 310, 310, 310,
+ 310, 310, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+ 380, 380, 380, 380, 380];
+ this.commands = [];
+ this.createArray();
+
+
+ /*this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 50, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory(); */
+
+}
+
+
+
+HeapSort.prototype.addControls = function()
+{
+ this.randomizeArrayButton = addControlToAlgorithmBar("Button", "Randomize Array");
+ this.randomizeArrayButton.onclick = this.randomizeCallback.bind(this);
+ this.heapsortButton = addControlToAlgorithmBar("Button", "Heap Sort");
+ this.heapsortButton.onclick = this.heapsortCallback.bind(this);
+}
+
+
+HeapSort.prototype.createArray = function()
+{
+ this.arrayData = new Array(ARRAY_SIZE);
+ this.arrayLabels = new Array(ARRAY_SIZE);
+ this.arrayRects = new Array(ARRAY_SIZE);
+ this.circleObjs = new Array(ARRAY_SIZE);
+ this.ArrayXPositions = new Array(ARRAY_SIZE);
+ this.oldData = new Array(ARRAY_SIZE);
+ this.currentHeapSize = 0;
+
+ for (var i = 1; i < ARRAY_SIZE; i++)
+ {
+ this.arrayData[i] = Math.floor(1 + Math.random()*999);
+ this.oldData[i] = this.arrayData[i];
+
+ this.ArrayXPositions[i] = ARRAY_INITIAL_X + i *ARRAY_ELEM_WIDTH;
+ this.arrayLabels[i] = this.nextIndex++;
+ this.arrayRects[i] = this.nextIndex++;
+ this.circleObjs[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.arrayRects[i], this.arrayData[i], ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, this.ArrayXPositions[i] , ARRAY_Y_POS)
+ this.cmd("CreateLabel", this.arrayLabels[i], i - 1, this.ArrayXPositions[i], ARRAY_LABEL_Y_POS);
+ this.cmd("SetForegroundColor", this.arrayLabels[i], "#0000FF");
+ }
+ this.swapLabel1 = this.nextIndex++;
+ this.swapLabel2 = this.nextIndex++;
+ this.swapLabel3 = this.nextIndex++;
+ this.swapLabel4 = this.nextIndex++;
+ this.descriptLabel1 = this.nextIndex++;
+ this.descriptLabel2 = this.nextIndex++;
+ this.cmd("CreateLabel", this.descriptLabel1, "", 20, 40, 0);
+ //this.cmd("CreateLabel", this.descriptLabel2, "", this.nextIndex, 40, 120, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+
+HeapSort.prototype.heapsortCallback = function(event)
+{
+ this.commands = this.buildHeap("");
+ for (var i = ARRAY_SIZE - 1; i > 1; i--)
+ {
+ this.swap(i, 1);
+ this.cmd("SetAlpha", this.arrayRects[i], 0.2);
+ this.cmd("Delete", this.circleObjs[i]);
+ this.currentHeapSize = i-1;
+ this.pushDown(1);
+ }
+ for (i = 1; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("SetAlpha", this.arrayRects[i], 1);
+ }
+ this.cmd("Delete", this.circleObjs[1]);
+ this.animationManager.StartNewAnimation(this.commands);
+}
+
+
+HeapSort.prototype.randomizeCallback = function(ignored)
+{
+ this.randomizeArray();
+}
+
+HeapSort.prototype.randomizeArray = function()
+{
+ this.commands = new Array();
+ for (var i = 1; i < ARRAY_SIZE; i++)
+ {
+ this.arrayData[i] = Math.floor(1 + Math.random()*999);
+ this.cmd("SetText", this.arrayRects[i], this.arrayData[i]);
+ this.oldData[i] = this.arrayData[i];
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+
+HeapSort.prototype.reset = function()
+{
+ for (var i = 1; i < ARRAY_SIZE; i++)
+ {
+
+ this.arrayData[i]= this.oldData[i];
+ this.cmd("SetText", this.arrayRects[i],this.arrayData[i]);
+ }
+ this.commands = new Array();
+}
+
+
+HeapSort.prototype.swap = function(index1, index2)
+{
+ this.cmd("SetText", this.arrayRects[index1], "");
+ this.cmd("SetText", this.arrayRects[index2], "");
+ this.cmd("SetText", this.circleObjs[index1], "");
+ this.cmd("SetText", this.circleObjs[index2], "");
+ this.cmd("CreateLabel", this.swapLabel1, this.arrayData[index1], this.ArrayXPositions[index1],ARRAY_Y_POS);
+ this.cmd("CreateLabel", this.swapLabel2, this.arrayData[index2], this.ArrayXPositions[index2],ARRAY_Y_POS);
+ this.cmd("CreateLabel", this.swapLabel3, this.arrayData[index1], this.HeapXPositions[index1],this.HeapYPositions[index1]);
+ this.cmd("CreateLabel", this.swapLabel4, this.arrayData[index2], this.HeapXPositions[index2],this.HeapYPositions[index2]);
+ this.cmd("Move", this.swapLabel1, this.ArrayXPositions[index2],ARRAY_Y_POS)
+ this.cmd("Move", this.swapLabel2, this.ArrayXPositions[index1],ARRAY_Y_POS)
+ this.cmd("Move", this.swapLabel3, this.HeapXPositions[index2],this.HeapYPositions[index2])
+ this.cmd("Move", this.swapLabel4, this.HeapXPositions[index1],this.HeapYPositions[index1])
+ var tmp = this.arrayData[index1];
+ this.arrayData[index1] = this.arrayData[index2];
+ this.arrayData[index2] = tmp;
+ this.cmd("Step")
+ this.cmd("SetText", this.arrayRects[index1], this.arrayData[index1]);
+ this.cmd("SetText", this.arrayRects[index2], this.arrayData[index2]);
+ this.cmd("SetText", this.circleObjs[index1], this.arrayData[index1]);
+ this.cmd("SetText", this.circleObjs[index2], this.arrayData[index2]);
+ this.cmd("Delete", this.swapLabel1);
+ this.cmd("Delete", this.swapLabel2);
+ this.cmd("Delete", this.swapLabel3);
+ this.cmd("Delete", this.swapLabel4);
+
+
+}
+
+
+HeapSort.prototype.setIndexHighlight = function(index, highlightVal)
+{
+ this.cmd("SetHighlight", this.circleObjs[index], highlightVal);
+ this.cmd("SetHighlight", this.arrayRects[index], highlightVal);
+}
+
+HeapSort.prototype.pushDown = function(index)
+{
+ var smallestIndex;
+
+ while(true)
+ {
+ if (index*2 > this.currentHeapSize)
+ {
+ return;
+ }
+
+ smallestIndex = 2*index;
+
+ if (index*2 + 1 <= this.currentHeapSize)
+ {
+ this.setIndexHighlight(2*index, 1);
+ this.setIndexHighlight(2*index + 1, 1);
+ this.cmd("Step");
+ this.setIndexHighlight(2*index, 0);
+ this.setIndexHighlight(2*index + 1, 0);
+ if (this.arrayData[2*index + 1] > this.arrayData[2*index])
+ {
+ smallestIndex = 2*index + 1;
+ }
+ }
+ this.setIndexHighlight(index, 1);
+ this.setIndexHighlight(smallestIndex, 1);
+ this.cmd("Step");
+ this.setIndexHighlight(index, 0);
+ this.setIndexHighlight(smallestIndex, 0);
+
+ if (this.arrayData[smallestIndex] > this.arrayData[index])
+ {
+ this.swap(smallestIndex, index);
+ index = smallestIndex;
+ }
+ else
+ {
+ return;
+ }
+
+
+
+ }
+}
+
+HeapSort.prototype.buildHeap = function(ignored)
+{
+ this.commands = new Array();
+ for (var i = 1; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("CreateCircle", this.circleObjs[i], this.arrayData[i], this.HeapXPositions[i], this.HeapYPositions[i]);
+ this.cmd("SetText", this.arrayRects[i], this.arrayData[i]);
+ if (i > 1)
+ {
+ this.cmd("Connect", this.circleObjs[Math.floor(i/2)], this.circleObjs[i]);
+ }
+
+ }
+ this.cmd("Step");
+ this.currentHeapSize = ARRAY_SIZE - 1;
+ var nextElem = this.currentHeapSize;
+ while(nextElem > 0)
+ {
+ this.pushDown(nextElem);
+ nextElem = nextElem - 1;
+ }
+ return this.commands;
+}
+
+
+
+HeapSort.prototype.disableUI = function(event)
+{
+ this.heapsortButton.disabled = true;
+ this.randomizeArrayButton.disabled = true;
+}
+
+HeapSort.prototype.enableUI = function(event)
+{
+ this.heapsortButton.disabled = false;
+ this.randomizeArrayButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new HeapSort(animManag, canvas.width, canvas.height);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Kruskal.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Kruskal.js
new file mode 100644
index 0000000..9c542a6
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Kruskal.js
@@ -0,0 +1,356 @@
+// 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 ``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 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
+
+
+
+function Kruskal(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+Kruskal.HIGHLIGHT_CIRCLE_COLOR = "#000000";
+
+ Kruskal.SET_ARRAY_ELEM_WIDTH = 25;
+ Kruskal.SET_ARRAY_ELEM_HEIGHT = 25;
+ Kruskal.SET_ARRAY_START_X = 50;
+ Kruskal.SET_ARRAY_START_Y = 130;
+
+ Kruskal.EDGE_LIST_ELEM_WIDTH = 40;
+ Kruskal.EDGE_LIST_ELEM_HEIGHT = 40;
+ Kruskal.EDGE_LIST_COLUMN_WIDTH = 100;
+ Kruskal.EDGE_LIST_MAX_PER_COLUMN = 10;
+
+ Kruskal.EDGE_LIST_START_X = 150;
+ Kruskal.EDGE_LIST_START_Y = 130;
+
+
+ Kruskal.FIND_LABEL_1_X = 30;
+ Kruskal.FIND_LABEL_2_X = 100;
+ Kruskal.FIND_LABEL_1_Y = 30;
+ Kruskal.FIND_LABEL_2_Y = Kruskal.FIND_LABEL_1_Y;
+
+ Kruskal.MESSAGE_LABEL_X = 30;
+ Kruskal.MESSAGE_LABEL_Y = 50;
+
+ Kruskal.HIGHLIGHT_CIRCLE_COLOR_1 = "#FFAAAA";
+ Kruskal.HIGHLIGHT_CIRCLE_COLOR_2 = "#FF0000";
+
+
+Kruskal.prototype = new Graph();
+Kruskal.prototype.constructor = Kruskal;
+Kruskal.superclass = Graph.prototype;
+
+Kruskal.prototype.addControls = function()
+{
+
+ this.startButton = addControlToAlgorithmBar("Button", "Run Kruskal");
+ this.startButton.onclick = this.startCallback.bind(this);
+
+ Kruskal.superclass.addControls.call(this, false);
+}
+
+
+Kruskal.prototype.init = function(am, w, h)
+{
+ this.showEdgeCosts = true;
+ Kruskal.superclass.init.call(this, am, w, h, false, false); // TODO: add no edge label flag to this?
+ // Setup called in base class init function
+}
+
+
+
+Kruskal.prototype.setup = function()
+{
+ Kruskal.superclass.setup.call(this);
+ this.messageID = new Array();
+ this.commands = new Array();
+ this.setID = new Array(this.size);
+ this.setIndexID = new Array(this.size);
+ this.setData = new Array(this.size);
+
+ var i;
+ for (i = 0; i < this.size; i++)
+ {
+ this.setID[i] = this.nextIndex++;
+ this.setIndexID[i] = this.nextIndex++;
+ this.cmd("CreateRectangle", this.setID[i], "-1", Kruskal.SET_ARRAY_ELEM_WIDTH, Kruskal.SET_ARRAY_ELEM_HEIGHT, Kruskal.SET_ARRAY_START_X, Kruskal.SET_ARRAY_START_Y + i*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("CreateLabel", this.setIndexID[i], i, Kruskal.SET_ARRAY_START_X - Kruskal.SET_ARRAY_ELEM_WIDTH ,Kruskal.SET_ARRAY_START_Y + i*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", this.setIndexID[i], VERTEX_INDEX_COLOR);
+ }
+ this.cmd("CreateLabel", this.nextIndex++, "Disjoint Set", Kruskal.SET_ARRAY_START_X - 1 * Kruskal.SET_ARRAY_ELEM_WIDTH, Kruskal.SET_ARRAY_START_Y - Kruskal.SET_ARRAY_ELEM_HEIGHT * 1.5, 0);
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+Kruskal.prototype.startCallback = function(event)
+{
+
+ this.implementAction(this.doKruskal.bind(this),"");
+
+}
+
+
+
+Kruskal.prototype.disjointSetFind = function(valueToFind, highlightCircleID)
+{
+ this.cmd("SetTextColor", this.setID[valueToFind], "#FF0000");
+ this.cmd("Step");
+ while (this.setData[valueToFind] >= 0)
+ {
+ this.cmd("SetTextColor", this.setID[valueToFind], "#000000");
+ this.cmd("Move", highlightCircleID, Kruskal.SET_ARRAY_START_X - Kruskal.SET_ARRAY_ELEM_WIDTH ,Kruskal.SET_ARRAY_START_Y + this.setData[valueToFind]*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+ valueToFind = this.setData[valueToFind];
+ this.cmd("SetTextColor", this.setID[valueToFind], "#FF0000");
+ this.cmd("Step");
+ }
+ this.cmd("SetTextColor", this.setID[valueToFind], "#000000");
+ return valueToFind;
+}
+
+
+
+Kruskal.prototype.doKruskal = function(ignored)
+{
+ this.commands = new Array();
+
+ this.edgesListLeftID = new Array();
+ this.edgesListRightID = new Array();
+ this.edgesListLeft = new Array();
+ this.edgesListRight = new Array();
+
+ var i;
+ var j;
+ for (i = 0; i < this.size; i++)
+ {
+ this.setData[i] = -1;
+ this.cmd("SetText", this.setID[i], "-1");
+ }
+
+ this.recolorGraph();
+
+ // Create Edge List
+ var top;
+ for (i = 0; i < this.size; i++)
+ {
+ for (j = i+1; j < this.size; j++)
+ {
+ if (this.adj_matrix[i][j] >= 0)
+ {
+ this.edgesListLeftID.push(this.nextIndex++);
+ this.edgesListRightID.push(this.nextIndex++);
+ top = this.edgesListLeftID.length - 1;
+ this.edgesListLeft.push(i);
+ this.edgesListRight.push(j);
+ this.cmd("CreateLabel", this.edgesListLeftID[top], i, Kruskal.EDGE_LIST_START_X + Math.floor(top / Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_COLUMN_WIDTH,
+ Kruskal.EDGE_LIST_START_Y + (top % Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_ELEM_HEIGHT);
+ this.cmd("CreateLabel", this.edgesListRightID[top], j, Kruskal.EDGE_LIST_START_X +Kruskal.EDGE_LIST_ELEM_WIDTH + Math.floor(top / Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_COLUMN_WIDTH,
+ Kruskal.EDGE_LIST_START_Y + (top % Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_ELEM_HEIGHT);
+ this.cmd("Connect", this.edgesListLeftID[top], this.edgesListRightID[top], EDGE_COLOR, 0, 0, this.adj_matrix[i][j])
+ }
+ }
+ }
+ this.cmd("Step");
+
+ // Sort edge list based on edge cost
+ var edgeCount = this.edgesListLeftID.length;
+ var tmpLeftID;
+ var tmpRightID;
+ var tmpLeft;
+ var tmpRight;
+ for (i = 1; i < edgeCount; i++)
+ {
+ tmpLeftID = this.edgesListLeftID[i];
+ tmpRightID = this.edgesListRightID[i];
+ tmpLeft = this.edgesListLeft[i];
+ tmpRight = this.edgesListRight[i];
+ j = i;
+ while (j > 0 && this.adj_matrix[this.edgesListLeft[j-1]][this.edgesListRight[j-1]] > this.adj_matrix[tmpLeft][tmpRight])
+ {
+ this.edgesListLeft[j] = this.edgesListLeft[j-1];
+ this.edgesListRight[j] = this.edgesListRight[j-1];
+ this.edgesListLeftID[j] = this.edgesListLeftID[j-1];
+ this.edgesListRightID[j] = this.edgesListRightID[j-1];
+ j = j -1
+ }
+ this.edgesListLeft[j] = tmpLeft;
+ this.edgesListRight[j] = tmpRight;
+ this.edgesListLeftID[j] = tmpLeftID;
+ this.edgesListRightID[j] = tmpRightID;
+ }
+ for (i = 0; i < edgeCount; i++)
+ {
+ this.cmd("Move", this.edgesListLeftID[i], Kruskal.EDGE_LIST_START_X + Math.floor(i / Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_COLUMN_WIDTH,
+ Kruskal.EDGE_LIST_START_Y + (i % Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_ELEM_HEIGHT);
+ this.cmd("Move", this.edgesListRightID[i], Kruskal.EDGE_LIST_START_X +Kruskal.EDGE_LIST_ELEM_WIDTH + Math.floor(i / Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_COLUMN_WIDTH,
+ Kruskal.EDGE_LIST_START_Y + (i % Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_ELEM_HEIGHT);
+
+ }
+
+ this.cmd("Step");
+
+ var findLabelLeft = this.nextIndex++;
+ var findLabelRight = this.nextIndex++;
+ var highlightCircle1 = this.nextIndex++;
+ var highlightCircle2 = this.nextIndex++;
+ var moveLabelID = this.nextIndex++;
+ var messageLabelID = this.nextIndex++;
+
+ var edgesAdded = 0;
+ var nextListIndex = 0;
+ this.cmd("CreateLabel", findLabelLeft, "", Kruskal.FIND_LABEL_1_X, Kruskal.FIND_LABEL_1_Y, 0);
+ this.cmd("CreateLabel", findLabelRight, "", Kruskal.FIND_LABEL_2_X, Kruskal.FIND_LABEL_2_Y, 0);
+
+ while (edgesAdded < this.size - 1 && nextListIndex < edgeCount)
+ {
+ this.cmd("SetEdgeHighlight", this.edgesListLeftID[nextListIndex],this.edgesListRightID[nextListIndex], 1);
+
+ this.highlightEdge(this.edgesListLeft[nextListIndex], this.edgesListRight[nextListIndex], 1)
+ this.highlightEdge(this.edgesListRight[nextListIndex], this.edgesListLeft[nextListIndex], 1)
+
+ this.cmd("SetText", findLabelLeft, "find(" + String(this.edgesListLeft[nextListIndex]) + ") = ");
+
+
+ this.cmd("CreateHighlightCircle", highlightCircle1, Kruskal.HIGHLIGHT_CIRCLE_COLOR_1, Kruskal.EDGE_LIST_START_X + Math.floor(nextListIndex / Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_COLUMN_WIDTH,
+ Kruskal.EDGE_LIST_START_Y + (nextListIndex % Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_ELEM_HEIGHT, 15);
+ this.cmd("Move", highlightCircle1, Kruskal.SET_ARRAY_START_X - Kruskal.SET_ARRAY_ELEM_WIDTH ,Kruskal.SET_ARRAY_START_Y + this.edgesListLeft[nextListIndex]*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+
+ var left = this.disjointSetFind(this.edgesListLeft[nextListIndex], highlightCircle1);
+ this.cmd("SetText", findLabelLeft, "find(" + String(this.edgesListLeft[nextListIndex]) + ") = " + String(left));
+
+
+ this.cmd("SetText", findLabelRight, "find(" + String(this.edgesListRight[nextListIndex]) + ") = ");
+
+ this.cmd("CreateHighlightCircle", highlightCircle2, Kruskal.HIGHLIGHT_CIRCLE_COLOR_2, Kruskal.EDGE_LIST_START_X +Kruskal.EDGE_LIST_ELEM_WIDTH + Math.floor(nextListIndex / Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_COLUMN_WIDTH,
+ Kruskal.EDGE_LIST_START_Y + (nextListIndex % Kruskal.EDGE_LIST_MAX_PER_COLUMN) * Kruskal.EDGE_LIST_ELEM_HEIGHT, 15);
+
+
+ this.cmd("Move", highlightCircle2, Kruskal.SET_ARRAY_START_X - Kruskal.SET_ARRAY_ELEM_WIDTH ,Kruskal.SET_ARRAY_START_Y + this.edgesListRight[nextListIndex]*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+
+ var right = this.disjointSetFind(this.edgesListRight[nextListIndex], highlightCircle2);
+ this.cmd("SetText", findLabelRight, "find(" + String(this.edgesListRight[nextListIndex]) + ") = " + String(right));
+
+ this.cmd("Step");
+
+ if (left != right)
+ {
+ this.cmd("CreateLabel", messageLabelID, "Vertices in different trees. Add edge to tree: Union(" + String(left) + "," + String(right) + ")", Kruskal.MESSAGE_LABEL_X, Kruskal.MESSAGE_LABEL_Y, 0);
+ this.cmd("Step");
+ this.highlightEdge(this.edgesListLeft[nextListIndex], this.edgesListRight[nextListIndex], 1)
+ this.highlightEdge(this.edgesListRight[nextListIndex], this.edgesListLeft[nextListIndex], 1)
+ edgesAdded++;
+ this.setEdgeColor(this.edgesListLeft[nextListIndex], this.edgesListRight[nextListIndex], "#FF0000");
+ this.setEdgeColor( this.edgesListRight[nextListIndex], this.edgesListLeft[nextListIndex], "#FF0000");
+ if (this.setData[left] < this.setData[right])
+ {
+ this.cmd("SetText", this.setID[right], "")
+ this.cmd("CreateLabel", moveLabelID, this.setData[right], Kruskal.SET_ARRAY_START_X, Kruskal.SET_ARRAY_START_Y + right*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Move", moveLabelID, Kruskal.SET_ARRAY_START_X, Kruskal.SET_ARRAY_START_Y + left*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+ this.cmd("Delete", moveLabelID);
+ this.setData[left] = this.setData[left] + this.setData[right]
+ this.setData[right] = left;
+ }
+ else
+ {
+ this.cmd("SetText", this.setID[left], "")
+ this.cmd("CreateLabel", moveLabelID, this.setData[left], Kruskal.SET_ARRAY_START_X, Kruskal.SET_ARRAY_START_Y + left*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Move", moveLabelID, Kruskal.SET_ARRAY_START_X, Kruskal.SET_ARRAY_START_Y + right*Kruskal.SET_ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+ this.cmd("Delete", moveLabelID);
+ this.setData[right] = this.setData[right] + this.setData[left]
+ this.setData[left] = right;
+ }
+ this.cmd("SetText", this.setID[left], this.setData[left]);
+ this.cmd("SetText", this.setID[right], this.setData[right]);
+ }
+ else
+ {
+ this.cmd("CreateLabel", messageLabelID, "Vertices in the same tree. Skip edge", Kruskal.MESSAGE_LABEL_X, Kruskal.MESSAGE_LABEL_Y, 0);
+ this.cmd("Step");
+
+ }
+
+ this.highlightEdge(this.edgesListLeft[nextListIndex], this.edgesListRight[nextListIndex], 0)
+ this.highlightEdge(this.edgesListRight[nextListIndex], this.edgesListLeft[nextListIndex], 0)
+
+ this.cmd("Delete", messageLabelID);
+ this.cmd("Delete", highlightCircle1);
+ this.cmd("Delete", highlightCircle2);
+
+
+ this.cmd("Delete", this.edgesListLeftID[nextListIndex]);
+ this.cmd("Delete", this.edgesListRightID[nextListIndex]);
+ this.cmd("SetText", findLabelLeft, "");
+ this.cmd("SetText", findLabelRight, "");
+ nextListIndex++;
+
+ }
+ this.cmd("Delete", findLabelLeft);
+ this.cmd("Delete", findLabelRight);
+
+
+
+ return this.commands
+
+}
+
+
+
+Kruskal.prototype.reset = function()
+{
+ this.messageID = new Array();
+}
+
+
+
+Kruskal.prototype.enableUI = function(event)
+{
+ this.startButton.disabled = false;
+
+
+ Kruskal.superclass.enableUI.call(this,event);
+}
+Kruskal.prototype.disableUI = function(event)
+{
+ this.startButton.disabled = true;
+
+ Kruskal.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Kruskal(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/LeftistHeap.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/LeftistHeap.js
new file mode 100644
index 0000000..ca7e1b7
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/LeftistHeap.js
@@ -0,0 +1,568 @@
+// 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 ``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 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
+
+
+
+function LeftistHeap(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+LeftistHeap.prototype = new Algorithm();
+LeftistHeap.prototype.constructor = LeftistHeap;
+LeftistHeap.superclass = Algorithm.prototype;
+
+LeftistHeap.LINK_COLOR = "#007700";
+LeftistHeap.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+LeftistHeap.FOREGROUND_COLOR = "#007700";
+LeftistHeap.BACKGROUND_COLOR = "#EEFFEE";
+
+LeftistHeap.WIDTH_DELTA = 50;
+LeftistHeap.HEIGHT_DELTA = 50;
+LeftistHeap.STARTING_Y = 85;
+
+LeftistHeap.INSERT_X = 50;
+LeftistHeap.INSERT_Y = 45;
+LeftistHeap.BACKGROUND_ALPHA = 0.5;
+
+LeftistHeap.MESSAGE_X = 20;
+LeftistHeap.MESSAGE_Y = 10;
+
+
+LeftistHeap.NPL_OFFSET_X = 20;
+LeftistHeap.NPL_OFFSET_Y = 20;
+LeftistHeap.NPL_COLOR = "#0000FF";
+
+LeftistHeap.MESSAGE_ID = 0;
+
+LeftistHeap.prototype.init = function(am, w, h)
+{
+ LeftistHeap.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.treeRoot = null;
+ this.secondaryRoot = null;
+ this.animationManager.setAllLayers([0, 1]);
+ this.nextIndex = 1;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", LeftistHeap.MESSAGE_X, LeftistHeap.MESSAGE_Y, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.commands = [];
+}
+
+
+LeftistHeap.prototype.addControls = function()
+{
+ this.controls = [];
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.controls.push(this.insertField);
+
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.controls.push(this.insertButton);
+
+ this.removeSmallestButton = addControlToAlgorithmBar("Button", "Remove Smallest");
+ this.removeSmallestButton.onclick = this.removeSmallestCallback.bind(this);
+ this.controls.push(this.removeSmallestButton);
+
+ this.clearHeapButton = addControlToAlgorithmBar("Button", "Clear Heap");
+ this.clearHeapButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearHeapButton);
+
+ this.showNPLBox = addCheckboxToAlgorithmBar("Show Null Path Lengths");
+ this.showNPLBox.checked = true;
+
+ this.showNPLBox.onclick = this.NPLChangedHandler.bind(this);
+}
+
+
+LeftistHeap.prototype.NPLChangedHandler = function(logicalRep, event)
+{
+ if (this.showNPLBox.checked)
+ {
+ this.animationManager.setAllLayers([0,1]);
+ }
+ else
+ {
+ this.animationManager.setAllLayers([0]);
+ }
+}
+
+
+
+
+LeftistHeap.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+LeftistHeap.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clear.bind(this, ""));
+}
+
+LeftistHeap.prototype.clear = function(ignored)
+{
+ this.commands = new Array();
+ this.clearTree(this.treeRoot);
+ this.treeRoot = null;
+ this.nexIndex = 1;
+ return this.commands;
+}
+
+LeftistHeap.prototype.clearTree = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Delete", tree.nplID);
+ this.clearTree(tree.left);
+ this.clearTree(tree.right);
+ }
+
+}
+
+LeftistHeap.prototype.reset = function()
+{
+ this.treeRoot = null;
+ this.secondaryRoot = null;
+ this.nextIndex = 1;
+}
+
+LeftistHeap.prototype.removeSmallestCallback = function(event)
+{
+ this.implementAction(this.removeSmallest.bind(this),"");
+}
+
+
+
+LeftistHeap.prototype.removeSmallest = function(dummy)
+{
+
+ this.commands = new Array();
+
+ if (this.treeRoot != null)
+ {
+ this.highlightLeft = this.nextIndex++;
+ this.highlightRight = this.nextIndex++;
+
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Remove root element, leaving two subtrees");
+ if (this.treeRoot.left != null)
+ {
+ this.cmd("Disconnect", this.treeRoot.graphicID, this.treeRoot.left.graphicID);
+ }
+ if (this.treeRoot.right != null)
+ {
+ this.cmd("Disconnect", this.treeRoot.graphicID, this.treeRoot.right.graphicID);
+ }
+ var oldElem = this.treeRoot.graphicID;
+ this.cmd("Delete", this.treeRoot.nplID);
+ this.cmd("Move", this.treeRoot.graphicID, LeftistHeap.INSERT_X, LeftistHeap.INSERT_Y);
+ this.cmd("Step");
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Merge the two subtrees");
+
+ if (this.treeRoot.left == null)
+ {
+ this.treeRoot = null;
+ }
+ else if (this.treeRoot.right == null)
+ {
+ this.treeRoot = this.treeRoot.left;
+ this.resizeTrees();
+ }
+ else
+ {
+ var secondTree = this.treeRoot.right;
+ this.secondaryRoot = secondTree;
+ this.treeRoot = this.treeRoot.left;
+ this.resizeTrees();
+ //this.secondaryRoot = null;
+ this.cmd("CreateHighlightCircle", this.highlightLeft, LeftistHeap.HIGHLIGHT_CIRCLE_COLOR, this.treeRoot.x, this.treeRoot.y);
+
+ this.cmd("CreateHighlightCircle", this.highlightRight, LeftistHeap.HIGHLIGHT_CIRCLE_COLOR, secondTree.x, secondTree.y);
+ this.treeRoot = this.merge(this.treeRoot, secondTree);
+ this.secondaryRoot = null;
+ }
+ this.resizeTrees();
+ this.cmd("Delete", oldElem);
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "");
+
+
+ }
+ // Clear for real
+ return this.commands;
+
+}
+
+
+
+LeftistHeap.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Create a heap with one node, merge with existing heap.");
+
+ this.secondaryRoot = new LeftistHeapNode(insertedValue, this.nextIndex++, this.nextIndex++, LeftistHeap.INSERT_X, LeftistHeap.INSERT_Y);
+ this.cmd("CreateCircle", this.secondaryRoot.graphicID, insertedValue, this.secondaryRoot.x, this.secondaryRoot.y);
+ this.cmd("CreateLabel", this.secondaryRoot.nplID, 0, LeftistHeap.INSERT_X -LeftistHeap.NPL_OFFSET_X, LeftistHeap.INSERT_Y - LeftistHeap.NPL_OFFSET_Y);
+ this.cmd("SetForegroundColor", this.secondaryRoot.nplID, LeftistHeap.NPL_COLOR);
+ this.cmd("SetLayer", this.secondaryRoot.nplID, 1);
+ this.cmd("SetForegroundColor", this.secondaryRoot.graphicID, LeftistHeap.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.secondaryRoot.graphicID, LeftistHeap.BACKGROUND_COLOR);
+
+
+ if (this.treeRoot != null)
+ {
+ this.resizeTrees();
+ this.highlightLeft = this.nextIndex++;
+ this.highlightRight = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", this.highlightLeft, LeftistHeap.HIGHLIGHT_CIRCLE_COLOR, this.treeRoot.x, this.treeRoot.y);
+
+ this.cmd("CreateHighlightCircle", this.highlightRight, LeftistHeap.HIGHLIGHT_CIRCLE_COLOR, this.secondaryRoot.x, this.secondaryRoot.y);
+
+
+ var rightTree = this.secondaryRoot;
+ this.secondaryRoot = null;
+
+ this.treeRoot = this.merge(this.treeRoot, rightTree);
+
+ this.resizeTrees();
+ }
+ else
+ {
+ this.treeRoot = this.secondaryRoot;
+ this.secondaryRoot = null;
+ this.resizeTrees();
+ }
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "");
+
+
+ return this.commands;
+}
+
+
+LeftistHeap.prototype.merge = function(tree1, tree2)
+{
+ if (tree1 == null)
+ {
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Merging right heap with empty heap, return right heap");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightRight);
+ this.cmd("Delete", this.highlightLeft);
+
+ return tree2;
+ }
+ if (tree2 == null)
+ {
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Merging left heap with empty heap, return left heap");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightRight);
+ this.cmd("Delete", this.highlightLeft);
+
+ return tree1;
+ }
+ var tmp;
+ this.cmd("SetHighlight", tree1.graphicID, 1);
+ this.cmd("SetHighlight", tree2.graphicID, 1);
+ if (tree2.data < tree1.data)
+ {
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Min element is in right heap. Recursively merge right subtree of right heap with left heap");
+ tmp = tree1;
+ tree1 = tree2;
+ tree2 = tmp;
+ tmp = this.highlightRight;
+ this.highlightRight = this.highlightLeft;
+ this.highlightLeft = tmp;
+ }
+ else
+ {
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Min element is in left heap. Recursively merge right subtree of left heap with right heap");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree1.graphicID, 0);
+ this.cmd("SetHighlight", tree2.graphicID, 0);
+ if (tree1.right == null)
+ {
+ this.cmd("Move", this.highlightLeft, tree1.x + LeftistHeap.WIDTH_DELTA / 2, tree1.y + LeftistHeap.HEIGHT_DELTA);
+ }
+ else
+ {
+ this.cmd("Move", this.highlightLeft, tree1.right.x, tree1.right.y);
+
+ }
+ this.cmd("Step");
+ if (tree1.right != null)
+ {
+ this.cmd("Disconnect", tree1.graphicID, tree1.right.graphicID, LeftistHeap.LINK_COLOR);
+ }
+ var next = tree1.right;
+ this.cmd("SetAlpha", tree1.graphicID, LeftistHeap.BACKGROUND_ALPHA);
+ this.cmd("SetAlpha", tree1.nplID, LeftistHeap.BACKGROUND_ALPHA);
+ if (tree1.left != null)
+ {
+ this.cmd("SetEdgeAlpha", tree1.graphicID, tree1.left.graphicID, LeftistHeap.BACKGROUND_ALPHA);
+ this.setTreeAlpha(tree1.left, LeftistHeap.BACKGROUND_ALPHA);
+
+ }
+ this.cmd("Step");
+ tree1.right = this.merge(next, tree2);
+ if (this.secondaryRoot == tree1.right)
+ {
+ this.secondaryRoot = null;
+ }
+ if (this.treeRoot == tree1.right)
+ {
+ this.treeRoot = null;
+ }
+ if (tree1.right.parent != tree1)
+ {
+ tree1.right.disconnectFromParent();
+ }
+ tree1.right.parent = tree1;
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Reconnecting tree after merge");
+
+ this.cmd("Connect", tree1.graphicID, tree1.right.graphicID, LeftistHeap.LINK_COLOR);
+ this.cmd("SetAlpha", tree1.graphicID, 1);
+ this.cmd("SetAlpha", tree1.nplID, 1);
+
+ this.resizeTrees();
+ if (tree1.left != null)
+ {
+ this.cmd("SetEdgeAlpha", tree1.graphicID, tree1.left.graphicID, 1);
+ this.setTreeAlpha(tree1.left, 1);
+ this.cmd("Step");
+ }
+
+ if (tree1.left == null || (tree1.left.npl < tree1.right.npl))
+ {
+ this.cmd("SetHighlight", tree1.graphicID, 1);
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Right subtree has larger Null Path Length than left subtree. Swapping ...");
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree1.graphicID, 0);
+ var tmp = tree1.left;
+ tree1.left = tree1.right;
+ tree1.right = tmp;
+ this.resizeTrees();
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree1.graphicID, 1);
+ this.cmd("SetText", LeftistHeap.MESSAGE_ID, "Left subtree has Null Path Length at least as large as right subtree. No swap required ...");
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree1.graphicID, 0);
+
+ }
+ if (tree1.right == null)
+ {
+ tree1.npl = 0;
+ }
+ else
+ {
+ tree1.npl = Math.min(tree1.left.npl, tree1.right.npl) + 1;
+ }
+ this.cmd("SetText", tree1.nplID, tree1.npl);
+
+ return tree1;
+}
+
+
+
+LeftistHeap.prototype.setTreeAlpha = function(tree, newAlpha)
+{
+ if (tree != null)
+ {
+ this.cmd("SetAlpha", tree.graphicID, newAlpha);
+ this.cmd("SetAlpha", tree.nplID, newAlpha);
+ if (tree.left != null)
+ {
+ this.cmd("SetEdgeAlpha", tree.graphicID, tree.left.graphicID, newAlpha);
+ this.setTreeAlpha(tree.left, newAlpha);
+ }
+ if (tree.right != null)
+ {
+ this.cmd("SetEdgeAlpha", tree.graphicID, tree.right.graphicID, newAlpha);
+ this.setTreeAlpha(tree.right, newAlpha);
+ }
+ }
+}
+
+LeftistHeap.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = Math.max(this.resizeWidths(tree.left), LeftistHeap.WIDTH_DELTA / 2);
+ tree.rightWidth = Math.max(this.resizeWidths(tree.right), LeftistHeap.WIDTH_DELTA / 2);
+ return tree.leftWidth + tree.rightWidth;
+}
+
+
+
+LeftistHeap.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+LeftistHeap.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+LeftistHeap.prototype.resizeTrees = function()
+{
+ var firstTreeStart;
+ var secondTreeStart;
+ this.resizeWidths(this.treeRoot);
+ this.resizeWidths(this.secondaryRoot);
+
+ if (this.treeRoot != null)
+ {
+ startingPoint = this.treeRoot.leftWidth;
+ this.setNewPositions(this.treeRoot, startingPoint, LeftistHeap.STARTING_Y, 0);
+ this.animateNewPositions(this.treeRoot);
+ if (this.secondaryRoot != null)
+ {
+ secondTreeStart = this.treeRoot.leftWidth + this.treeRoot.rightWidth + this.secondaryRoot.leftWidth + 50;
+ this.setNewPositions(this.secondaryRoot, secondTreeStart, LeftistHeap.STARTING_Y, 0);
+ this.animateNewPositions(this.secondaryRoot);
+ }
+
+ this.cmd("Step");
+ }
+ else if (this.secondaryRoot != null)
+ {
+ startingPoint = this.secondaryRoot.leftWidth;
+ this.setNewPositions(this.secondaryRoot, startingPoint, LeftistHeap.STARTING_Y, 0);
+ this.animateNewPositions(this.secondaryRoot);
+ }
+
+}
+
+LeftistHeap.prototype.setNewPositions = function(tree, xPosition, yPosition, side)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ if (side == -1)
+ {
+ xPosition = xPosition - tree.rightWidth;
+ tree.npX = xPosition - LeftistHeap.NPL_OFFSET_X;
+ }
+ else if (side == 1)
+ {
+ xPosition = xPosition + tree.leftWidth;
+ tree.npX = xPosition + LeftistHeap.NPL_OFFSET_X;
+ }
+ else
+ {
+ tree.heightLabelX = xPosition - LeftistHeap.NPL_OFFSET_Y;;
+ tree.npX = xPosition + LeftistHeap.NPL_OFFSET_X;
+ }
+ tree.x = xPosition;
+ tree.npY = tree.y - LeftistHeap.NPL_OFFSET_Y;
+ this.setNewPositions(tree.left, xPosition, yPosition + LeftistHeap.HEIGHT_DELTA, -1)
+ this.setNewPositions(tree.right, xPosition, yPosition + LeftistHeap.HEIGHT_DELTA, 1)
+ }
+
+}
+
+
+LeftistHeap.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.cmd("Move", tree.nplID, tree.npX, tree.npY);
+ this.animateNewPositions(tree.left);
+ this.animateNewPositions(tree.right);
+ }
+}
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new LeftistHeap(animManag, canvas.width, canvas.height);
+}
+
+
+
+
+function LeftistHeapNode(val, id, nplID, initialX, initialY)
+{
+ this.data = val;
+ this.x = (initialX == undefined) ? 0 : initialX;
+ this.y = (initialY == undefined) ? 0 : initialY;
+ this.npX = initialX - LeftistHeap.NPL_OFFSET_X;
+ this.npY = initialY - LeftistHeap.NPL_OFFSET_Y;
+
+ this.graphicID = id;
+ this.nplID = nplID;
+ this.npl = 0;
+ this.left = null;
+ this.right = null;
+ this.leftWidth = 0;
+ this.rightWidth = 0;
+ this.parent = null;
+}
+
+LeftistHeapNode.prototype.disconnectFromParent = function()
+{
+ if (this.parent != null)
+ {
+ if (this.parent.right == this)
+ {
+ this.parent.right = null;
+ }
+ else if (this.parent.left === this)
+ {
+ this.parent.left == null;
+ }
+ }
+}
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/MyAlgorithm.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/MyAlgorithm.js
new file mode 100644
index 0000000..6f3e414
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/MyAlgorithm.js
@@ -0,0 +1,207 @@
+// 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 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
+
+
+
+function MyAlgorithm(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+MyAlgorithm.prototype = new Algorithm();
+MyAlgorithm.prototype.constructor = MyAlgorithm;
+MyAlgorithm.superclass = Algorithm.prototype;
+
+MyAlgorithm.prototype.init = function(am, w, h)
+{
+ // Call the unit function of our "superclass", which adds a couple of
+ // listeners, and sets up the undo stack
+ MyAlgorithm.superclass.init.call(this, am, w, h);
+
+ this.addControls();
+
+ // Useful for memory management
+ this.nextIndex = 0;
+
+ // TODO: Add any code necessary to set up your own algorithm. Initialize data
+ // structures, etc.
+
+}
+
+MyAlgorithm.prototype.addControls = function()
+{
+ this.controls = [];
+
+ // Add any necessary controls for your algorithm.
+ // There are libraries that help with text entry, buttons, check boxes, radio groups
+ //
+ // To add a button myButton:
+ // this.mybytton = addControlToAlgorithmBar("Button", "MyButtonText");
+ // this.mybytton.onclick = this.myCallback.bind(this);
+ // this.controls.push(this.mybutton);
+ // where myCallback is a method on this function that implemnts the callback
+ //
+ // To add a text field myField:
+ // this.myField = addControlToAlgorithmBar("Text", "");
+ // this.myField.onkeydown = this.returnSubmit(this.myField,
+ // this.anotherCallback.bind(this), // callback to make when return is pressed
+ // maxFieldLen, // integer, max number of characters allowed in field
+ // intOnly); // boolean, true of only digits can be entered.
+ // this.controls.push(this.myField);
+ //
+ // To add a textbox:
+ // this.myCheckbox = addCheckboxToAlgorithmBar("Checkbox Label");
+ // this.myCheckbox.onclick = this.checkboxCallback.bind(this);
+ // this.controls.push(myCheckbox);
+ //
+ // To add a radio button group:
+ // this.radioButtonList = addRadioButtonGroupToAlgorithmBar(["radio button label 1",
+ // "radio button label 2",
+ // "radio button label 3"],
+ // "MyButtonGroupName");
+ // this.radioButtonList[0].onclick = this.firstRadioButtonCallback.bind(this);
+ // this.controls.push(this.radioButtonList[0]);
+ // this.radioButtonList[1].onclick = this.secondRadioButtonCallback.bind(this);
+ // this.controls.push(this.radioButtonList[1]);
+ // this.radioButtonList[2].onclick = this.thirdRadioButtonCallback.bind(this);
+ // this.controls.push(this.radioButtonList[1]);
+ //
+ // Note that we are adding the controls to the controls array so that they can be enabled / disabled
+ // by the animation manager (see enableUI / disableUI below)
+}
+
+MyAlgorithm.prototype.reset = function()
+{
+ // Reset all of your data structures to *exactly* the state they have immediately after the init
+ // function is called. This method is called whenever an "undo" is performed. Your data
+ // structures are completely cleaned, and then all of the actions *up to but not including* the
+ // last action are then redone. If you implement all of your actions through the "implementAction"
+ // method below, then all of this work is done for you in the Animation "superclass"
+
+ // Reset the (very simple) memory manager
+ this.nextIndex = 0;
+
+}
+
+//////////////////////////////////////////////
+// Callbacks:
+//////////////////////////////////////////////
+//
+// All of your callbacks should *not* do any work directly, but instead should go through the
+// implement action command. That way, undos are handled by ths system "behind the scenes"
+//
+// A typical example:
+//
+//MyAlgorithm.prototype.insertCallback = function(event)
+//{
+// // Get value to insert from textfield (created in addControls above)
+// var insertedValue = this.insertField.value;
+//
+// // If you want numbers to all have leading zeroes, you can add them like this:
+// insertedValue = this.normalizeNumber(insertedValue, 4);
+//
+// // Only do insertion if the text field is not empty ...
+// if (insertedValue != "")
+// {
+// // Clear text field after operation
+// this.insertField.value = "";
+// // Do the actual work. The function implementAction is defined in the algorithm superclass
+// this.implementAction(this.insertElement.bind(this), insertedValue);
+// }
+//}
+// Note that implementAction takes as parameters a function and an argument, and then calls that
+// function using that argument (while also storing the function/argument pair for future undos)
+
+//////////////////////////////////////////////
+// Doing actual work
+//////////////////////////////////////////////
+// The functions that are called by implementAction (like insertElement in the comments above) need to:
+//
+// 1. Create an array of strings that represent commands to give to the animation manager
+// 2. Return this array of commands
+//
+// We strongly recommend that you use the this.cmd function, which is a handy utility function that
+// appends commands onto the instance variable this.commands
+//
+// A simple example:
+//
+//MyAlgorithm.simpleAction(input)
+//{
+// this.commands = []; // Empty out our commands variable, so it isn't corrupted by previous actions
+//
+// // Get a new memory ID for the circle that we are going to create
+// var circleID = nextIndex++;
+// var circleX = 50;
+// var circleY = 50;
+//
+// // Create a circle
+// this.cmd("CreateCircle", circleID, "Label", circleX, circleY);
+// circleX = 100;
+// // Move the circle
+// this.cmd("Move", circleID, circleX, circleY);
+// // First Animation step done
+// this.cmd("Step");
+// circleX = 50;
+// circleY = 100;
+// // Move the circle again
+// this.cmd("Move", circleID, circleX, circleY);
+// // Next Animation step done
+// this.cmd("Step");
+// // Return the commands that were generated by the "cmd" calls:
+// return this.commands;
+//}
+
+
+
+// Called by our superclass when we get an animation started event -- need to wait for the
+// event to finish before we start doing anything
+MyAlgorithm.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+// Called by our superclass when we get an animation completed event -- we can
+/// now interact again.
+MyAlgorithm.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new MyAlgorithm(animManag, canvas.width, canvas.height);
+
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/OpenHash.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/OpenHash.js
new file mode 100644
index 0000000..fef5637
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/OpenHash.js
@@ -0,0 +1,361 @@
+// 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 ``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 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
+
+
+
+function OpenHash(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+
+var POINTER_ARRAY_ELEM_WIDTH = 70;
+var POINTER_ARRAY_ELEM_HEIGHT = 30;
+var POINTER_ARRAY_ELEM_START_X = 50;
+
+var LINKED_ITEM_HEIGHT = 30;
+var LINKED_ITEM_WIDTH = 65;
+
+var LINKED_ITEM_Y_DELTA = 50;
+var LINKED_ITEM_POINTER_PERCENT = 0.25;
+
+var MAX_DATA_VALUE = 999;
+
+var HASH_TABLE_SIZE = 13;
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+OpenHash.prototype = new Hash();
+OpenHash.prototype.constructor = OpenHash;
+OpenHash.superclass = Hash.prototype;
+
+
+OpenHash.prototype.init = function(am, w, h)
+{
+ var sc = OpenHash.superclass;
+ var fn = sc.init;
+ fn.call(this,am, w, h);
+ this.nextIndex = 0;
+ this.POINTER_ARRAY_ELEM_Y = h - POINTER_ARRAY_ELEM_WIDTH;
+ this.setup();
+}
+
+OpenHash.prototype.addControls = function()
+{
+ OpenHash.superclass.addControls.call(this);
+
+ // Add new controls
+
+}
+
+OpenHash.prototype.insertElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "Inserting element: " + String(elem));
+ var index = this.doHash(elem);
+ var node = new LinkedListNode(elem,this.nextIndex++, 100, 75);
+ this.cmd("CreateLinkedList", node.graphicID, elem, LINKED_ITEM_WIDTH, LINKED_ITEM_HEIGHT, 100, 75);
+ if (this.hashTableValues[index] != null && this.hashTableValues[index] != undefined)
+ {
+ this.cmd("connect", node.graphicID, this.hashTableValues[index].graphicID);
+ this.cmd("disconnect", this.hashTableVisual[index], this.hashTableValues[index].graphicID);
+ }
+ else
+ {
+ this.cmd("SetNull", node.graphicID, 1);
+ this.cmd("SetNull", this.hashTableVisual[index], 0);
+ }
+ this.cmd("connect", this.hashTableVisual[index], node.graphicID);
+ node.next = this.hashTableValues[index];
+ this.hashTableValues[index] = node;
+
+ this.repositionList(index);
+
+ this.cmd("SetText", this.ExplainLabel, "");
+
+ return this.commands;
+
+}
+
+
+OpenHash.prototype.repositionList = function(index)
+{
+ var startX = POINTER_ARRAY_ELEM_START_X + index *POINTER_ARRAY_ELEM_WIDTH;
+ var startY = this.POINTER_ARRAY_ELEM_Y - LINKED_ITEM_Y_DELTA;
+ var tmp = this.hashTableValues[index];
+ while (tmp != null)
+ {
+ tmp.x = startX;
+ tmp.y = startY;
+ this.cmd("Move", tmp.graphicID, tmp.x, tmp.y);
+ startY = startY - LINKED_ITEM_Y_DELTA;
+ tmp = tmp.next;
+ }
+}
+
+
+OpenHash.prototype.deleteElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem);
+ var index = this.doHash(elem);
+ if (this.hashTableValues[index] == null)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " Element not in table");
+ return this.commands;
+ }
+ this.cmd("SetHighlight", this.hashTableValues[index].graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableValues[index].graphicID, 0);
+ if (this.hashTableValues[index].data == elem)
+ {
+ if (this.hashTableValues[index].next != null)
+ {
+ this.cmd("Connect", this.hashTableVisual[index], this.hashTableValues[index].next.graphicID);
+ }
+ else
+ {
+ this.cmd("SetNull", this.hashTableVisual[index], 1);
+ }
+ this.cmd("Delete", this.hashTableValues[index].graphicID);
+ this.hashTableValues[index] = this.hashTableValues[index].next;
+ this.repositionList(index);
+ return this.commands;
+ }
+ var tmpPrev = this.hashTableValues[index];
+ var tmp = this.hashTableValues[index].next;
+ var found = false;
+ while (tmp != null && !found)
+ {
+ this.cmd("SetHighlight", tmp.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tmp.graphicID, 0);
+ if (tmp.data == elem)
+ {
+ found = true;
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " 元素已删除");
+ if (tmp.next != null)
+ {
+ this.cmd("Connect", tmpPrev.graphicID, tmp.next.graphicID);
+ }
+ else
+ {
+ this.cmd("SetNull", tmpPrev.graphicID, 1);
+ }
+ tmpPrev.next = tmpPrev.next.next;
+ this.cmd("Delete", tmp.graphicID);
+ this.repositionList(index);
+ }
+ else
+ {
+ tmpPrev = tmp;
+ tmp = tmp.next;
+ }
+ }
+ if (!found)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " Element not in table");
+ }
+ return this.commands;
+
+}
+OpenHash.prototype.findElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem);
+
+ var index = this.doHash(elem);
+ var compareIndex = this.nextIndex++;
+ var found = false;
+ var tmp = this.hashTableValues[index];
+ this.cmd("CreateLabel", compareIndex, "", 10, 40, 0);
+ while (tmp != null && !found)
+ {
+ this.cmd("SetHighlight", tmp.graphicID, 1);
+ if (tmp.data == elem)
+ {
+ this.cmd("SetText", compareIndex, tmp.data + "==" + elem)
+ found = true;
+ }
+ else
+ {
+ this.cmd("SetText", compareIndex, tmp.data + "!=" + elem)
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tmp.graphicID, 0);
+ tmp = tmp.next;
+ }
+ if (found)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem+ " 已找到!")
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem+ " 未找到!")
+
+ }
+ this.cmd("Delete", compareIndex);
+ this.nextIndex--;
+ return this.commands;
+}
+
+
+
+
+OpenHash.prototype.setup = function()
+{
+ this.hashTableVisual = new Array(HASH_TABLE_SIZE);
+ this.hashTableIndices = new Array(HASH_TABLE_SIZE);
+ this.hashTableValues = new Array(HASH_TABLE_SIZE);
+
+ this.indexXPos = new Array(HASH_TABLE_SIZE);
+ this.indexYPos = new Array(HASH_TABLE_SIZE);
+
+ this.ExplainLabel = this.nextIndex++;
+
+ this.table_size = HASH_TABLE_SIZE;
+
+ this.commands = [];
+ for (var i = 0; i < HASH_TABLE_SIZE; i++)
+ {
+ var nextID = this.nextIndex++;
+
+ this.cmd("CreateRectangle", nextID, "", POINTER_ARRAY_ELEM_WIDTH, POINTER_ARRAY_ELEM_HEIGHT, POINTER_ARRAY_ELEM_START_X + i *POINTER_ARRAY_ELEM_WIDTH, this.POINTER_ARRAY_ELEM_Y)
+ this.hashTableVisual[i] = nextID;
+ this.cmd("SetNull", this.hashTableVisual[i], 1);
+
+ nextID = this.nextIndex++;
+ this.hashTableIndices[i] = nextID;
+ this.indexXPos[i] = POINTER_ARRAY_ELEM_START_X + i *POINTER_ARRAY_ELEM_WIDTH;
+ this.indexYPos[i] = this.POINTER_ARRAY_ELEM_Y + POINTER_ARRAY_ELEM_HEIGHT
+ this.hashTableValues[i] = null;
+
+ this.cmd("CreateLabel", nextID, i,this.indexXPos[i],this.indexYPos[i] );
+ this.cmd("SetForegroundColor", nextID, INDEX_COLOR);
+ }
+ this.cmd("CreateLabel", this.ExplainLabel, "", 10, 25, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.resetIndex = this.nextIndex;
+}
+
+
+
+OpenHash.prototype.resetAll = function()
+{
+ var tmp;
+ this.commands = OpenHash.superclass.resetAll.call(this);
+ for (var i = 0; i < this.hashTableValues.length; i++)
+ {
+ tmp = this.hashTableValues[i];
+ if (tmp != null)
+ {
+ while (tmp != null)
+ {
+ this.cmd("Delete", tmp.graphicID);
+ tmp = tmp.next;
+ }
+ this.hashTableValues[i] = null;
+ this.cmd("SetNull", this.hashTableVisual[i], 1);
+ }
+ }
+ return this.commands;
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+OpenHash.prototype.reset = function()
+{
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.hashTableValues[i] = null;
+ }
+ this.nextIndex = this.resetIndex;
+ OpenHash.superclass.reset.call(this);
+}
+
+
+OpenHash.prototype.resetCallback = function(event)
+{
+
+}
+
+
+
+/*this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 50, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory(); */
+
+
+
+
+
+OpenHash.prototype.disableUI = function(event)
+{
+ var sc = OpenHash.superclass;
+ var fn = sc.disableUI;
+ fn.call(this);
+}
+
+OpenHash.prototype.enableUI = function(event)
+{
+ OpenHash.superclass.enableUI.call(this);
+}
+
+
+
+
+function LinkedListNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.graphicID = id;
+ this.x = initialX;
+ this.y = initialY;
+ this.next = null;
+
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new OpenHash(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/QueueArray.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/QueueArray.js
new file mode 100644
index 0000000..1bf7d19
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/QueueArray.js
@@ -0,0 +1,324 @@
+// 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 ``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 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 = 100;
+var ARRAY_START_Y = 200;
+var ARRAY_ELEM_WIDTH = 50;
+var ARRAY_ELEM_HEIGHT = 50;
+
+var ARRRAY_ELEMS_PER_LINE = 15;
+var ARRAY_LINE_SPACING = 130;
+
+var HEAD_POS_X = 180;
+var HEAD_POS_Y = 100;
+var HEAD_LABEL_X = 130;
+var HEAD_LABEL_Y = 100;
+
+var TAIL_POS_X = 280;
+var TAIL_POS_Y = 100;
+var TAIL_LABEL_X = 230;
+var TAIL_LABEL_Y = 100;
+
+var QUEUE_LABEL_X = 50;
+var QUEUE_LABEL_Y = 30;
+var QUEUE_ELEMENT_X = 120;
+var QUEUE_ELEMENT_Y = 30;
+
+var INDEX_COLOR = "#0000FF"
+
+var SIZE = 15;
+
+function QueueArray(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+QueueArray.prototype = new Algorithm();
+QueueArray.prototype.constructor = QueueArray;
+QueueArray.superclass = Algorithm.prototype;
+
+
+QueueArray.prototype.init = function(am, w, h)
+{
+ QueueArray.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ //this.tail_pos_y = h - LINKED_LIST_ELEM_HEIGHT;
+// this.tail_label_y = this.tail_pos_y;
+ this.setup();
+ this.initialIndex = this.nextIndex;
+}
+
+
+QueueArray.prototype.addControls = function()
+{
+ this.controls = [];
+ this.enqueueField = addControlToAlgorithmBar("Text", "");
+ this.enqueueField.onkeydown = this.returnSubmit(this.enqueueField, this.enqueueCallback.bind(this), 6);
+ this.enqueueButton = addControlToAlgorithmBar("Button", "Enqueue");
+ this.enqueueButton.onclick = this.enqueueCallback.bind(this);
+ this.controls.push(this.enqueueField);
+ this.controls.push(this.enqueueButton);
+
+ this.dequeueButton = addControlToAlgorithmBar("Button", "Dequeue");
+ this.dequeueButton.onclick = this.dequeueCallback.bind(this);
+ this.controls.push(this.dequeueButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "Clear Queue");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+}
+
+QueueArray.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+QueueArray.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+QueueArray.prototype.setup = function()
+{
+
+ this.nextIndex = 0;
+
+ this.arrayID = new Array(SIZE);
+ this.arrayLabelID = new Array(SIZE);
+ for (var i = 0; i < SIZE; i++)
+ {
+
+ this.arrayID[i]= this.nextIndex++;
+ this.arrayLabelID[i]= this.nextIndex++;
+ }
+ this.headID = this.nextIndex++;
+ headLabelID = this.nextIndex++;
+ this.tailID = this.nextIndex++;
+ tailLabelID = this.nextIndex++;
+
+ this.arrayData = new Array(SIZE);
+ this.head = 0;
+ this.tail = 0;
+ this.leftoverLabelID = this.nextIndex++;
+
+
+ for (var i = 0; i < SIZE; i++)
+ {
+ var xpos = (i % ARRRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ var ypos = Math.floor(i / ARRRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y;
+ this.cmd("CreateRectangle", this.arrayID[i],"", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT,xpos, ypos);
+ this.cmd("CreateLabel",this.arrayLabelID[i], i, xpos, ypos + ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", this.arrayLabelID[i], INDEX_COLOR);
+
+ }
+ this.cmd("CreateLabel", headLabelID, "Head", HEAD_LABEL_X, HEAD_LABEL_Y);
+ this.cmd("CreateRectangle", this.headID, 0, ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, HEAD_POS_X, HEAD_POS_Y);
+
+ this.cmd("CreateLabel", tailLabelID, "Tail", TAIL_LABEL_X, TAIL_LABEL_Y);
+ this.cmd("CreateRectangle", this.tailID, 0, ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, TAIL_POS_X, TAIL_POS_Y);
+
+
+
+ this.cmd("CreateLabel", this.leftoverLabelID, "", QUEUE_LABEL_X, QUEUE_LABEL_Y);
+
+
+ this.initialIndex = this.nextIndex;
+
+ this.highlight1ID = this.nextIndex++;
+ this.highlight2ID = this.nextIndex++;
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+
+}
+
+
+QueueArray.prototype.reset = function()
+{
+ this.top = 0;
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+QueueArray.prototype.enqueueCallback = function(event)
+{
+ if ((this.tail + 1) % SIZE != this.head && this.enqueueField.value != "")
+ {
+ var pushVal = this.enqueueField.value;
+ this.enqueueField.value = ""
+ this.implementAction(this.enqueue.bind(this), pushVal);
+ }
+}
+
+
+QueueArray.prototype.dequeueCallback = function(event)
+{
+ if (this.tail != this.head)
+ {
+ this.implementAction(this.dequeue.bind(this), "");
+ }
+}
+
+
+QueueArray.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clearAll.bind(this), "");
+}
+
+
+
+QueueArray.prototype.enqueue = function(elemToEnqueue)
+{
+ this.commands = new Array();
+
+ var labEnqueueID = this.nextIndex++;
+ var labEnqueueValID = this.nextIndex++;
+ this.arrayData[this.tail] = elemToEnqueue;
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+ this.cmd("CreateLabel", labEnqueueID, "Enqueuing Value: ", QUEUE_LABEL_X, QUEUE_LABEL_Y);
+ this.cmd("CreateLabel", labEnqueueValID,elemToEnqueue, QUEUE_ELEMENT_X, QUEUE_ELEMENT_Y);
+
+ this.cmd("Step");
+ this.cmd("CreateHighlightCircle", this.highlight1ID, INDEX_COLOR, TAIL_POS_X, TAIL_POS_Y);
+ this.cmd("Step");
+
+ var xpos = (this.tail % ARRRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ var ypos = Math.floor(this.tail / ARRRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y;
+
+ this.cmd("Move", this.highlight1ID, xpos, ypos + ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+
+ this.cmd("Move", labEnqueueValID, xpos, ypos);
+ this.cmd("Step");
+
+ this.cmd("Settext", this.arrayID[this.tail], elemToEnqueue);
+ this.cmd("Delete", labEnqueueValID);
+
+ this.cmd("Delete", this.highlight1ID);
+
+ this.cmd("SetHighlight", this.tailID, 1);
+ this.cmd("Step");
+ this.tail = (this.tail + 1) % SIZE;
+ this.cmd("SetText", this.tailID, this.tail)
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.tailID, 0);
+ this.cmd("Delete", labEnqueueID);
+
+ return this.commands;
+}
+
+QueueArray.prototype.dequeue = function(ignored)
+{
+ this.commands = new Array();
+
+ var labDequeueID = this.nextIndex++;
+ var labDequeueValID = this.nextIndex++;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+
+ this.cmd("CreateLabel", labDequeueID, "Dequeued Value: ", QUEUE_LABEL_X, QUEUE_LABEL_Y);
+
+ this.cmd("CreateHighlightCircle", this.highlight1ID, INDEX_COLOR, HEAD_POS_X, HEAD_POS_Y);
+ this.cmd("Step");
+
+ var xpos = (this.head % ARRRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ var ypos = Math.floor(this.head / ARRRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y;
+
+ this.cmd("Move", this.highlight1ID, xpos, ypos + ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+
+ this.cmd("Delete", this.highlight1ID);
+
+
+ var dequeuedVal = this.arrayData[this.head]
+ this.cmd("CreateLabel", labDequeueValID,dequeuedVal, xpos, ypos);
+ this.cmd("Settext", this.arrayID[this.head], "");
+ this.cmd("Move", labDequeueValID, QUEUE_ELEMENT_X, QUEUE_ELEMENT_Y);
+ this.cmd("Step");
+
+ this.cmd("SetHighlight", this.headID, 1);
+ this.cmd("Step");
+ this.head = (this.head + 1 ) % SIZE;
+ this.cmd("SetText", this.headID, this.head)
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.headID, 0);
+
+ this.cmd("SetText", this.leftoverLabelID, "Dequeued Value: " + dequeuedVal);
+
+
+ this.cmd("Delete", labDequeueID)
+ this.cmd("Delete", labDequeueValID);
+
+
+
+ return this.commands;
+}
+
+
+
+QueueArray.prototype.clearAll = function()
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+ for (var i = 0; i < SIZE; i++)
+ {
+ this.cmd("SetText", this.arrayID[i], "");
+ }
+ this.head = 0;
+ this.tail = 0;
+ this.cmd("SetText", this.headID, "0");
+ this.cmd("SetText", this.tailID, "0");
+ return this.commands;
+
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new QueueArray(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/QueueLL.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/QueueLL.js
new file mode 100644
index 0000000..4f34d81
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/QueueLL.js
@@ -0,0 +1,331 @@
+// 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 ``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 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 LINKED_LIST_START_X = 100;
+var LINKED_LIST_START_Y = 200;
+var LINKED_LIST_ELEM_WIDTH = 70;
+var LINKED_LIST_ELEM_HEIGHT = 30;
+
+
+var LINKED_LIST_INSERT_X = 250;
+var LINKED_LIST_INSERT_Y = 50;
+
+var LINKED_LIST_ELEMS_PER_LINE = 8;
+var LINKED_LIST_ELEM_SPACING = 100;
+var LINKED_LIST_LINE_SPACING = 100;
+
+var TOP_POS_X = 180;
+var TOP_POS_Y = 100;
+var TOP_LABEL_X = 130;
+var TOP_LABEL_Y = 100;
+
+var TOP_ELEM_WIDTH = 30;
+var TOP_ELEM_HEIGHT = 30;
+
+var TAIL_POS_X = 180;
+var TAIL_LABEL_X = 130;
+
+var PUSH_LABEL_X = 50;
+var PUSH_LABEL_Y = 30;
+var PUSH_ELEMENT_X = 120;
+var PUSH_ELEMENT_Y = 30;
+
+var SIZE = 32;
+
+function QueueLL(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+QueueLL.prototype = new Algorithm();
+QueueLL.prototype.constructor = QueueLL;
+QueueLL.superclass = Algorithm.prototype;
+
+
+QueueLL.prototype.init = function(am, w, h)
+{
+ QueueLL.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.tail_pos_y = h - LINKED_LIST_ELEM_HEIGHT;
+ this.tail_label_y = this.tail_pos_y;
+ this.setup();
+ this.initialIndex = this.nextIndex;
+}
+
+
+QueueLL.prototype.addControls = function()
+{
+ this.controls = [];
+ this.enqueueField = addControlToAlgorithmBar("Text", "");
+ this.enqueueField.onkeydown = this.returnSubmit(this.enqueueField, this.enqueueCallback.bind(this), 6);
+ this.enqueueButton = addControlToAlgorithmBar("Button", "Enqueue");
+ this.enqueueButton.onclick = this.enqueueCallback.bind(this);
+ this.controls.push(this.enqueueField);
+ this.controls.push(this.enqueueButton);
+
+ this.dequeueButton = addControlToAlgorithmBar("Button", "Dequeue");
+ this.dequeueButton.onclick = this.dequeueCallback.bind(this);
+ this.controls.push(this.dequeueButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "Clear Queue");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+}
+
+QueueLL.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+QueueLL.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+QueueLL.prototype.setup = function()
+{
+
+ this.linkedListElemID = new Array(SIZE);
+ for (var i = 0; i < SIZE; i++)
+ {
+
+ this.linkedListElemID[i]= this.nextIndex++;
+ }
+ this.headID = this.nextIndex++;
+ this.headLabelID = this.nextIndex++;
+
+ this.tailID = this.nextIndex++;
+ this.tailLabelID = this.nextIndex++;
+
+
+ this.arrayData = new Array(SIZE);
+ this.top = 0;
+ this.leftoverLabelID = this.nextIndex++;
+
+ this.cmd("CreateLabel", this.headLabelID, "Head", TOP_LABEL_X, TOP_LABEL_Y);
+ this.cmd("CreateRectangle", this.headID, "", TOP_ELEM_WIDTH, TOP_ELEM_HEIGHT, TOP_POS_X, TOP_POS_Y);
+ this.cmd("SetNull", this.headID, 1);
+
+
+ this.cmd("CreateLabel", this.tailLabelID, "Tail", TAIL_LABEL_X, this.tail_label_y);
+ this.cmd("CreateRectangle", this.tailID, "", TOP_ELEM_WIDTH, TOP_ELEM_HEIGHT, TAIL_POS_X, this.tail_pos_y);
+ this.cmd("SetNull", this.tailID, 1);
+
+ this.cmd("CreateLabel", this.leftoverLabelID, "", 5, PUSH_LABEL_Y,0);
+
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+QueueLL.prototype.resetLinkedListPositions = function()
+{
+ for (var i = this.top - 1; i >= 0; i--)
+ {
+ var nextX = (this.top - 1 - i) % LINKED_LIST_ELEMS_PER_LINE * LINKED_LIST_ELEM_SPACING + LINKED_LIST_START_X;
+ var nextY = Math.floor((this.top - 1 - i) / LINKED_LIST_ELEMS_PER_LINE) * LINKED_LIST_LINE_SPACING + LINKED_LIST_START_Y;
+ this.cmd("Move", this.linkedListElemID[i], nextX, nextY);
+ }
+
+}
+
+
+
+
+QueueLL.prototype.reset = function()
+{
+ this.top = 0;
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+QueueLL.prototype.enqueueCallback = function(event)
+{
+ if (this.top < SIZE && this.enqueueField.value != "")
+ {
+ var pushVal = this.enqueueField.value;
+ this.enqueueField.value = ""
+ this.implementAction(this.enqueue.bind(this), pushVal);
+ }
+}
+
+
+QueueLL.prototype.dequeueCallback = function(event)
+{
+ if (this.top > 0)
+ {
+ this.implementAction(this.dequeue.bind(this), "");
+ }
+}
+
+
+QueueLL.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clearData.bind(this), "");
+}
+
+
+
+QueueLL.prototype.enqueue = function(elemToPush)
+{
+ this.commands = new Array();
+
+ this.arrayData[this.top] = elemToPush;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+ for (var i = this.top; i > 0; i--)
+ {
+ this.arrayData[i] = this.arrayData[i-1];
+ this.linkedListElemID[i] =this.linkedListElemID[i-1];
+ }
+ this.arrayData[0] = elemToPush;
+ this.linkedListElemID[0] = this.nextIndex++;
+
+ var labPushID = this.nextIndex++;
+ var labPushValID = this.nextIndex++;
+ this.cmd("CreateLinkedList",this.linkedListElemID[0], "" ,LINKED_LIST_ELEM_WIDTH, LINKED_LIST_ELEM_HEIGHT,
+ LINKED_LIST_INSERT_X, LINKED_LIST_INSERT_Y, 0.25, 0, 1, 1);
+
+ this.cmd("SetNull", this.linkedListElemID[0], 1);
+ this.cmd("CreateLabel", labPushID, "Enqueuing Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPushValID,elemToPush, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+
+ this.cmd("Step");
+
+
+
+ this.cmd("Move", labPushValID, LINKED_LIST_INSERT_X, LINKED_LIST_INSERT_Y);
+
+ this.cmd("Step");
+ this.cmd("SetText", this.linkedListElemID[0], elemToPush);
+ this.cmd("Delete", labPushValID);
+
+ if (this.top == 0)
+ {
+ this.cmd("SetNull", this.headID, 0);
+ this.cmd("SetNull", this.tailID, 0);
+ this.cmd("connect", this.headID, this.linkedListElemID[this.top]);
+ this.cmd("connect", this.tailID, this.linkedListElemID[this.top]);
+ }
+ else
+ {
+ this.cmd("SetNull", this.linkedListElemID[1], 0);
+ this.cmd("Connect", this.linkedListElemID[1], this.linkedListElemID[0]);
+ this.cmd("Step");
+ this.cmd("Disconnect", this.tailID, this.linkedListElemID[1]);
+ }
+ this.cmd("Connect", this.tailID, this.linkedListElemID[0]);
+
+ this.cmd("Step");
+ this.top = this.top + 1;
+ this.resetLinkedListPositions();
+ this.cmd("Delete", labPushID);
+ this.cmd("Step");
+
+ return this.commands;
+}
+
+QueueLL.prototype.dequeue = function(ignored)
+{
+ this.commands = new Array();
+
+ var labPopID = this.nextIndex++;
+ var labPopValID = this.nextIndex++;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+
+ this.cmd("CreateLabel", labPopID, "Dequeued Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPopValID,this.arrayData[this.top - 1], LINKED_LIST_START_X, LINKED_LIST_START_Y);
+
+ this.cmd("Move", labPopValID, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+ this.cmd("Step");
+ this.cmd("Disconnect", this.headID, this.linkedListElemID[this.top - 1]);
+
+ if (this.top == 1)
+ {
+ this.cmd("SetNull", this.headID, 1);
+ this.cmd("SetNull", this.tailID, 1);
+ this.cmd("Disconnect", this.tailID, this.linkedListElemID[this.top-1]);
+ }
+ else
+ {
+ this.cmd("Connect", this.headID, this.linkedListElemID[this.top-2]);
+ }
+ this.cmd("Step");
+ this.cmd("Delete", this.linkedListElemID[this.top - 1]);
+ this.top = this.top - 1;
+ this.resetLinkedListPositions();
+
+ this.cmd("Delete", labPopValID)
+ this.cmd("Delete", labPopID);
+ this.cmd("SetText", this.leftoverLabelID, "Dequeued Value: " + this.arrayData[this.top]);
+
+
+
+ return this.commands;
+}
+
+
+
+QueueLL.prototype.clearAll = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < this.top; i++)
+ {
+ this.cmd("Delete", this.linkedListElemID[i]);
+ }
+ this.top = 0;
+ this.cmd("SetNull", this.headID, 1);
+ return this.commands;
+
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new QueueLL(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RadixSort.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RadixSort.js
new file mode 100644
index 0000000..ddd3865
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RadixSort.js
@@ -0,0 +1,387 @@
+// 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 ``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 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
+
+
+function RadixSort(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+
+var ARRAY_ELEM_WIDTH = 30;
+var ARRAY_ELEM_HEIGHT = 30;
+var ARRAY_ELEM_START_X = 20;
+
+var ARRAY_SIZE = 30;
+var COUNTER_ARRAY_SIZE = 10;
+
+
+var COUNTER_ARRAY_ELEM_WIDTH = 30;
+var COUNTER_ARRAY_ELEM_HEIGHT = 30;
+//var COUNTER_ARRAY_ELEM_START_X = 20;
+var COUNTER_ARRAY_ELEM_START_X = (ARRAY_ELEM_WIDTH * ARRAY_SIZE- COUNTER_ARRAY_ELEM_WIDTH * COUNTER_ARRAY_SIZE) / 2 + ARRAY_ELEM_START_X;
+var NUM_DIGITS = 3;
+
+
+var MAX_DATA_VALUE = 999;
+
+
+
+RadixSort.prototype = new Algorithm();
+RadixSort.prototype.constructor = RadixSort;
+RadixSort.superclass = Algorithm.prototype;
+
+RadixSort.prototype.init = function(am, w, h)
+{
+ this.ARRAY_ELEM_Y = 3 * COUNTER_ARRAY_ELEM_HEIGHT;
+ this.COUNTER_ARRAY_ELEM_Y = Math.floor(h / 2);
+ this.SWAP_ARRAY_ELEM_Y = h - 3 * COUNTER_ARRAY_ELEM_HEIGHT
+
+ var sc = RadixSort.superclass;
+ var fn = sc.init;
+ fn.call(this,am,w,h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.setup();
+}
+
+
+
+RadixSort.prototype.sizeChanged = function(newWidth, newHeight)
+{
+ this.ARRAY_ELEM_Y = 3 * COUNTER_ARRAY_ELEM_HEIGHT;
+ this.COUNTER_ARRAY_ELEM_Y = Math.floor(newHeight / 2);
+ this.SWAP_ARRAY_ELEM_Y = newHeight - 3 * COUNTER_ARRAY_ELEM_HEIGHT
+ this.setup();
+}
+
+
+RadixSort.prototype.addControls = function()
+{
+ this.resetButton = addControlToAlgorithmBar("Button", "Randomize List");
+ this.resetButton.onclick = this.resetCallback.bind(this);
+
+ this.radixSortButton = addControlToAlgorithmBar("Button", "Radix Sort");
+ this.radixSortButton.onclick = this.radixSortCallback.bind(this);
+
+}
+
+
+RadixSort.prototype.setup = function()
+{
+ this.arrayData = new Array(ARRAY_SIZE);
+ this.arrayRects= new Array(ARRAY_SIZE);
+ this.arrayIndices = new Array(ARRAY_SIZE);
+
+
+ this.counterData = new Array(COUNTER_ARRAY_SIZE);
+ this.counterRects= new Array(COUNTER_ARRAY_SIZE);
+ this.counterIndices = new Array(COUNTER_ARRAY_SIZE);
+
+ this.swapData = new Array(ARRAY_SIZE);
+ this.swapRects= new Array(ARRAY_SIZE);
+ this.swapIndices = new Array(ARRAY_SIZE);
+
+ this.commands = new Array();
+
+ for (var i = 0; i < ARRAY_SIZE; i++)
+ {
+ var nextID = this.nextIndex++;
+ this.arrayData[i] = Math.floor(Math.random()*MAX_DATA_VALUE);
+ this.cmd("CreateRectangle", nextID, this.arrayData[i], ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y)
+ this.arrayRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this.arrayIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y + ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+
+ nextID = this.nextIndex++;
+ this.cmd("CreateRectangle", nextID, "", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y)
+ this.swapRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this.swapIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y + ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+
+ }
+ for (i = COUNTER_ARRAY_SIZE - 1; i >= 0; i--)
+ {
+ nextID = this.nextIndex++;
+ this.cmd("CreateRectangle", nextID,"", COUNTER_ARRAY_ELEM_WIDTH, COUNTER_ARRAY_ELEM_HEIGHT, COUNTER_ARRAY_ELEM_START_X + i *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y)
+ this.counterRects[i] = nextID;
+ nextID = this.nextIndex++;
+ this.counterIndices[i] = nextID;
+ this.cmd("CreateLabel",nextID, i, COUNTER_ARRAY_ELEM_START_X + i *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", nextID, "#0000FF");
+ }
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+
+RadixSort.prototype.resetAll = function(small)
+{
+ this.animationManager.resetAll();
+ this.nextIndex = 0;
+}
+
+RadixSort.prototype.radixSortCallback = function(event)
+{
+ this.commands = new Array();
+ var animatedCircleID = this.nextIndex++;
+ var animatedCircleID2 = this.nextIndex++;
+ var animatedCircleID3 = this.nextIndex++;
+ var animatedCircleID4 = this.nextIndex++;
+
+ var digits = new Array(NUM_DIGITS);
+ for (var k = 0; k < NUM_DIGITS; k++)
+ {
+ digits[k] = this.nextIndex++;
+ }
+
+
+ for (var radix = 0; radix < NUM_DIGITS; radix++)
+ {
+ for (var i = 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.counterData[i] = 0;
+ this.cmd("SetText", this.counterRects[i], 0);
+ }
+ for (i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("CreateHighlightCircle", animatedCircleID, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("CreateHighlightCircle", animatedCircleID2, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+
+
+ this.cmd("SetText", this.arrayRects[i], "");
+
+ for (k = 0; k < NUM_DIGITS; k++)
+ {
+ var digitXPos = ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH - ARRAY_ELEM_WIDTH/2 + (NUM_DIGITS - k ) * (ARRAY_ELEM_WIDTH / NUM_DIGITS - 3);
+ var digitYPos = this.ARRAY_ELEM_Y;
+ this.cmd("CreateLabel", digits[k], Math.floor(this.arrayData[i] / Math.pow(10,k)) % 10, digitXPos, digitYPos);
+ if (k != radix)
+ {
+ this.cmd("SetAlpha", digits[k], 0.2);
+ }
+ // else
+ // {
+ // this.cmd("SetAlpha", digits[k], 0.2);
+ // }
+ }
+
+
+ var index = Math.floor(this.arrayData[i] / Math.pow(10,radix)) % 10;
+ this.cmd("Move", animatedCircleID, COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT)
+ this.cmd("Step");
+ this.counterData[index]++;
+ this.cmd("SetText", this.counterRects[index], this.counterData[index]);
+ this.cmd("Step");
+ // this.cmd("SetAlpha", this.arrayRects[i], 0.2);
+ this.cmd("Delete", animatedCircleID);
+ this.cmd("Delete", animatedCircleID2);
+ this.cmd("SetText", this.arrayRects[i], this.arrayData[i]);
+ for (k = 0; k < NUM_DIGITS; k++)
+ {
+ this.cmd("Delete", digits[k]);
+ }
+ }
+ for (i=1; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetHighlight", this.counterRects[i-1], 1);
+ this.cmd("SetHighlight", this.counterRects[i], 1);
+ this.cmd("Step")
+ this.counterData[i] = this.counterData[i] + this.counterData[i-1];
+ this.cmd("SetText", this.counterRects[i], this.counterData[i]);
+ this.cmd("Step")
+ this.cmd("SetHighlight", this.counterRects[i-1], 0);
+ this.cmd("SetHighlight", this.counterRects[i], 0);
+ }
+ // for (i=ARRAY_SIZE - 1; i >= 0; i--)
+ // {
+ // this.cmd("SetAlpha", this.arrayRects[i], 1.0);
+ // }
+ for (i=ARRAY_SIZE - 1; i >= 0; i--)
+ {
+ this.cmd("CreateHighlightCircle", animatedCircleID, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("CreateHighlightCircle", animatedCircleID2, "#0000FF", ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+
+
+ this.cmd("SetText", this.arrayRects[i], "");
+
+ for (k = 0; k < NUM_DIGITS; k++)
+ {
+ digits[k] = this.nextIndex++;
+ digitXPos = ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH - ARRAY_ELEM_WIDTH/2 + (NUM_DIGITS - k ) * (ARRAY_ELEM_WIDTH / NUM_DIGITS - 3);
+ digitYPos = this.ARRAY_ELEM_Y;
+ this.cmd("CreateLabel", digits[k], Math.floor(this.arrayData[i] / Math.pow(10,k)) % 10, digitXPos, digitYPos);
+ if (k != radix)
+ {
+ this.cmd("SetAlpha", digits[k], 0.2);
+ }
+ }
+
+
+
+
+ index = Math.floor(this.arrayData[i] / Math.pow(10,radix)) % 10;
+ this.cmd("Move", animatedCircleID2, COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT)
+ this.cmd("Step");
+
+ var insertIndex = --this.counterData[index];
+ this.cmd("SetText", this.counterRects[index], this.counterData[index]);
+ this.cmd("Step");
+
+
+ this.cmd("CreateHighlightCircle", animatedCircleID3, "#AAAAFF", COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y);
+ this.cmd("CreateHighlightCircle", animatedCircleID4, "#AAAAFF", COUNTER_ARRAY_ELEM_START_X + index *COUNTER_ARRAY_ELEM_WIDTH, this.COUNTER_ARRAY_ELEM_Y);
+
+ this.cmd("Move", animatedCircleID4, ARRAY_ELEM_START_X + insertIndex * ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y + COUNTER_ARRAY_ELEM_HEIGHT)
+ this.cmd("Step");
+
+ var moveLabel = this.nextIndex++;
+ this.cmd("SetText", this.arrayRects[i], "");
+ this.cmd("CreateLabel", moveLabel, this.arrayData[i], ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("Move", moveLabel, ARRAY_ELEM_START_X + insertIndex *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y);
+ this.swapData[insertIndex] = this.arrayData[i];
+
+ for (k = 0; k < NUM_DIGITS; k++)
+ {
+ this.cmd("Delete", digits[k]);
+ }
+ this.cmd("Step");
+ this.cmd("Delete", moveLabel);
+ this.nextIndex--; // Reuse index from moveLabel, now that it has been removed.
+ this.cmd("SetText", this.swapRects[insertIndex], this.swapData[insertIndex]);
+ this.cmd("Delete", animatedCircleID);
+ this.cmd("Delete", animatedCircleID2);
+ this.cmd("Delete", animatedCircleID3);
+ this.cmd("Delete", animatedCircleID4);
+
+ }
+ for (i= 0; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("SetText", this.arrayRects[i], "");
+ }
+
+ for (i= 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetAlpha", this.counterRects[i], 0.05);
+ this.cmd("SetAlpha", this.counterIndices[i], 0.05);
+ }
+
+ this.cmd("Step");
+ var startLab = this.nextIndex;
+ for (i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.cmd("CreateLabel", startLab+i, this.swapData[i], ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.SWAP_ARRAY_ELEM_Y);
+ this.cmd("Move", startLab+i, ARRAY_ELEM_START_X + i *ARRAY_ELEM_WIDTH, this.ARRAY_ELEM_Y);
+ this.cmd("SetText", this.swapRects[i], "");
+
+ }
+ this.cmd("Step");
+ for (i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.arrayData[i] = this.swapData[i];
+ this.cmd("SetText", this.arrayRects[i], this.arrayData[i]);
+ this.cmd("Delete", startLab + i);
+ }
+ for (i= 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetAlpha", this.counterRects[i], 1);
+ this.cmd("SetAlpha", this.counterIndices[i], 1);
+ }
+ }
+ animationManager.StartNewAnimation(this.commands);
+
+}
+
+
+
+RadixSort.prototype.randomizeArray = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < ARRAY_SIZE; i++)
+ {
+ this.arrayData[i] = Math.floor(1 + Math.random()*MAX_DATA_VALUE);
+ this.cmd("SetText", this.arrayRects[i], this.arrayData[i]);
+ }
+
+ for (i = 0; i < COUNTER_ARRAY_SIZE; i++)
+ {
+ this.cmd("SetText", this.counterRects[i], "");
+ }
+
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+
+
+
+
+
+// We want to (mostly) ignore resets, since we are disallowing undoing
+RadixSort.prototype.reset = function()
+{
+ this.commands = new Array();
+}
+
+
+RadixSort.prototype.resetCallback = function(event)
+{
+ this.randomizeArray();
+}
+
+
+
+RadixSort.prototype.disableUI = function(event)
+{
+ this.resetButton.disabled = true;
+ this.radixSortButton.disabled = true;
+}
+RadixSort.prototype.enableUI = function(event)
+{
+ this.resetButton.disabled = false;
+ this.radixSortButton.disabled = false;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+
+ currentAlg = new RadixSort(animManag, canvas.width, canvas.height);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RadixTree.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RadixTree.js
new file mode 100644
index 0000000..7cf1455
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RadixTree.js
@@ -0,0 +1,840 @@
+// Copyright 2016 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 LIIBTED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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
+
+
+// Constants.
+
+
+RadixTree.NODE_WIDTH = 60;
+
+RadixTree.LINK_COLOR = "#007700";
+RadixTree.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+RadixTree.FOREGROUND_COLOR = "#007700";
+RadixTree.BACKGROUND_COLOR = "#CCFFCC";
+RadixTree.PRINT_COLOR = RadixTree.FOREGROUND_COLOR;
+RadixTree.FALSE_COLOR = "#FFFFFF"
+RadixTree.WIDTH_DELTA = 50;
+RadixTree.HEIGHT_DELTA = 80;
+RadixTree.STARTING_Y = 80;
+RadixTree.LeftMargin = 300;
+RadixTree.NEW_NODE_Y = 100
+RadixTree.NEW_NODE_X = 50;
+RadixTree.FIRST_PRINT_POS_X = 50;
+RadixTree.PRINT_VERTICAL_GAP = 20;
+RadixTree.PRINT_HORIZONTAL_GAP = 50;
+
+
+
+function RadixTree(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+RadixTree.prototype = new Algorithm();
+RadixTree.prototype.constructor = RadixTree;
+RadixTree.superclass = Algorithm.prototype;
+
+RadixTree.prototype.init = function(am, w, h)
+{
+ var sc = RadixTree.superclass;
+ this.startingX = w / 2;
+ this.first_print_pos_y = h - 2 * RadixTree.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 10, 0);
+ this.cmd("CreateLabel", 1, "", 20, 10, 0);
+ this.cmd("CreateLabel", 2, "", 20, 30, 0);
+ this.nextIndex = 3;
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+
+RadixTree.prototype.findIndexDifference = function(s1, s2, id, wordIndex)
+{
+ var index = 0;
+ this.cmd("SetText", 2, "Comparing next letter in search term \n to next letter in prefix of current node");
+
+ while (index < s1.length && index < s2.length)
+ {
+ this.cmd("SetHighlightIndex", 1, index);
+ this.cmd("SetHighlightIndex", id, index);
+ this.cmd("Step");
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetHighlightIndex", id, -1);
+
+ if (s1.charAt(index) == s2.charAt(index))
+ {
+ index++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return index;
+}
+
+
+RadixTree.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeypress = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 12,false);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 12);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 12);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+}
+
+RadixTree.prototype.reset = function()
+{
+ this.nextIndex = 3;
+ this.root = null;
+}
+
+RadixTree.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value.toUpperCase()
+ insertedValue = insertedValue.replace(/[^a-z]/gi,'');
+
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.add.bind(this), insertedValue);
+ }
+}
+
+RadixTree.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value.toUpperCase();
+ deletedValue = deletedValue.replace(/[^a-z]/gi,'');
+ if (deletedValue != "")
+ {
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+
+RadixTree.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+
+
+RadixTree.prototype.printTree = function(unused)
+{
+
+ this.commands = [];
+
+ if (this.root != null)
+ {
+ this.highlightID = this.nextIndex++;
+ this.printLabel1 = this.nextIndex++;
+ this.printLabel2 = this.nextIndex++;
+ var firstLabel = this.nextIndex++;
+ this.cmd("CreateLabel", firstLabel, "Output: ", RadixTree.FIRST_PRINT_POS_X, this.first_print_pos_y);
+ this.cmd("CreateHighlightCircle", this.highlightID, RadixTree.HIGHLIGHT_CIRCLE_COLOR, this.root.x, this.root.y);
+ this.cmd("SetWidth", this.highlightID, RadixTree.NODE_WIDTH);
+ this.cmd("CreateLabel", this.printLabel1, "Current String: ", 20, 10, 0);
+ this.cmd("CreateLabel", this.printLabel2, "", 20, 10, 0);
+ this.cmd("AlignRight", this.printLabel2, this.printLabel1);
+ this.xPosOfNextLabel = RadixTree.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.root, "");
+
+// this.cmd("SetText", this.printLabel1, "About to delete");
+// this.cmd("Step")
+
+ this.cmd("Delete", this.highlightID);
+ this.cmd("Delete", this.printLabel1);
+ this.cmd("Delete", this.printLabel2);
+ this.cmd("Step")
+
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+
+}
+
+
+
+
+RadixTree.prototype.printTreeRec = function(tree, stringSoFar)
+{
+ if (tree.wordRemainder != "")
+ {
+ stringSoFar = stringSoFar + tree.wordRemainder;
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.wordRemainder, tree.x, tree.y, 0);
+ this.cmd("MoveToAlignRight", nextLabelID, this.printLabel2);
+ this.cmd("Step");
+ this.cmd("Delete", nextLabelID);
+ this.nextIndex--;
+ this.cmd("SetText", this.printLabel2, stringSoFar);
+ }
+ if (tree.isword)
+ {
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, stringSoFar + " ", 20, 10, 0);
+ this.cmd("SetForegroundColor", nextLabelID, RadixTree.PRINT_COLOR);
+ this.cmd("AlignRight", nextLabelID, this.printLabel1, RadixTree.PRINT_COLOR);
+ this.cmd("MoveToAlignRight", nextLabelID, nextLabelID - 1);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += RadixTree.PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = RadixTree.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += RadixTree.PRINT_VERTICAL_GAP;
+ }
+
+
+ }
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ this.cmd("Move", this.highlightID, tree.children[i].x, tree.children[i].y);
+ this.cmd("Step");
+ this.printTreeRec(tree.children[i], stringSoFar);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", this.printLabel2, stringSoFar);
+ this.cmd("Step");
+
+ }
+
+
+ }
+}
+
+RadixTree.prototype.findCallback = function(event)
+{
+ var findValue;
+
+ var findValue = this.insertField.value.toUpperCase()
+ findValue = findValue.replace(/[^a-z]/gi,'');
+ this.findField.value = "";
+
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+RadixTree.prototype.findElement = function(findValue)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "Seaching for: ");
+ this.cmd("SetText", 1, findValue);
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+ this.highlightID = this.nextIndex++;
+
+
+ var res = this.doFind(this.root, findValue);
+ if (res)
+ {
+ this.cmd("SetText", 0, "String " + findValue + " found");
+ }
+ else
+ {
+ this.cmd("SetText", 0, "String " + findValue + " 未找到");
+ }
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+
+ return this.commands;
+}
+
+
+RadixTree.prototype.doFind = function(tree, value)
+{
+ if (tree == null)
+ {
+ this.cmd("SetText", 2, "Empty tree found. String not in the tree");
+ this.cmd("step");
+ return null;
+ }
+
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ var remain = tree.wordRemainder
+
+ var indexDifference = this.findIndexDifference(value, remain, tree.graphicID, 0);
+
+ if (indexDifference == remain.length)
+ {
+ this.cmd("SetText", 2, "Reached the end of the prefix stored at this node");
+ this.cmd("Step");
+
+ if (value.length > indexDifference)
+ {
+ this.cmd("SetText", 2, "Recusively search remaining string \nin the '" +value.charAt(indexDifference) + "' child");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetText", 1, value.substring(indexDifference));
+
+ var index = value.charCodeAt(indexDifference) - "A".charCodeAt(0);
+ var noChild = tree.children[index] == null;
+
+
+ if (noChild)
+ {
+ this.cmd("SetText", 2, "Child '" +value.charAt(indexDifference) + "' does not exit. \nString is not in the tree.");
+ this.cmd("Step");
+ return null;
+
+ } else {
+
+
+ this.cmd("CreateHighlightCircle", this.highlightID, RadixTree.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, RadixTree.NODE_WIDTH);
+
+ this.cmd("Step")
+ this.cmd("Move", this.highlightID, tree.children[index].x, tree.children[index].y);
+ this.cmd("Step")
+
+ this.cmd("Delete", this.highlightID);
+
+ }
+
+
+ return this.doFind(tree.children[index], value.substring(indexDifference));
+ }
+
+ this.cmd("SetText", 2, "Reached the end of the string. Check if current node is \"True\"")
+ this.cmd("Step");
+ this.cmd("SetText", 2, "")
+
+ if (tree.isword)
+ {
+ this.cmd("SetText", 2, "Node is \"True\", string is in tree")
+ this.cmd("Step");
+ this.cmd("SetText", 2, "")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return tree;
+
+ }
+ else
+ {
+ this.cmd("SetText", 2, "Node is \"False\", string is not in tree")
+ this.cmd("Step");
+ this.cmd("SetText", 2, "")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null;
+
+ }
+ }
+ else
+ {
+ this.cmd("SetText", 2, "Reached end of search string, \nStill characters remaining at node\nString not in tree")
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetText", 2, "")
+ return null;
+
+
+ }
+
+}
+
+
+RadixTree.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "正在刪除: ");
+ this.cmd("SetText", 1, deletedValue);
+ this.cmd("AlignRight", 1, 0);
+
+ var node = this.doFind(this.root, deletedValue);
+
+ if (node == null)
+ {
+ this.cmd("SetText", 2, "String not in the tree, nothing to delete");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+ }
+ else
+ {
+ node.isword = false;
+ this.cmd("SetText", 2, "Found string to delete, setting node to \"False\"");
+ this.cmd("Step");
+ this.cmd("SetBackgroundColor", node.graphicID, RadixTree.FALSE_COLOR);
+ this.cmd("Step");
+ this.cleanupAfterDelete(node)
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+ }
+
+ return this.commands;
+}
+
+
+
+RadixTree.prototype.numChildren = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ var children = 0
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ children++;
+ }
+ }
+ return children;
+
+}
+
+
+RadixTree.prototype.isLeaf = function(tree)
+{
+ if (tree == null)
+ {
+ return false;
+ }
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+RadixTree.prototype.getParentIndex = function(tree)
+{
+ if (tree.parent == null)
+ {
+ return -1;
+ }
+ var par = tree.parent;
+ for (var i = 0; i < 26; i++)
+ {
+ if (par.children[i] == tree)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+RadixTree.prototype.cleanupAfterDelete = function(tree)
+{
+ var children = this.numChildren(tree)
+
+ if (children == 0 && !tree.isword)
+ {
+ this.cmd("SetText", 2, "Deletion left us with a \"False\" leaf\nRemoving false leaf");
+ this.cmd("SetHighlight" ,tree.graphicID , 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ if (tree.parent != null)
+ {
+ var index = 0
+ while (tree.parent.children[index] != tree)
+ {
+ index++;
+ }
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Delete", tree.graphicID , 0);
+ tree.parent.children[index] = null;
+ this.cleanupAfterDelete(tree.parent);
+ }
+ else
+ {
+ this.cmd("Delete", tree.graphicID , 0);
+ this.root = null;
+ }
+ }
+ else if (children == 1 && !tree.isword)
+ {
+ var childIndex = -1;
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ childIndex = i;
+ break;
+ }
+ }
+ this.cmd("SetText", 2, "Deletion left us with a \"False\" node\nContaining one child. Combining ...");
+ this.cmd("SetHighlight" ,tree.graphicID , 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+
+ var child = tree.children[childIndex];
+ child.wordRemainder = tree.wordRemainder + child.wordRemainder;
+ this.cmd("SetText", child.graphicID, child.wordRemainder);
+ this.cmd("Disconnect", tree.graphicID , child.graphicID);
+
+ if (tree.parent == null)
+ {
+ child.parent = null
+ this.root = child;
+ this.cmd("Delete", tree.graphicID);
+ }
+ else
+ {
+ var parIndex = this.getParentIndex(tree);
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ tree.parent.children[parIndex] = child;
+ child.parent = tree.parent
+ this.cmd("Connect", tree.parent.graphicID, child.graphicID, RadixTree.FOREGROUND_COLOR, 0, false, child.wordRemainder.charAt(0));
+ this.cmd("Delete", tree.graphicID);
+
+ }
+ this.resizeTree();
+
+ }
+
+
+}
+
+
+
+RadixTree.prototype.treeDelete = function(tree, valueToDelete)
+{
+
+}
+
+RadixTree.prototype.resizeTree = function()
+{
+ this.resizeWidths(this.root);
+ if (this.root != null)
+ {
+ var startingPoint = this.root.width / 2 + 1 + RadixTree.LeftMargin;
+ this.setNewPositions(this.root, startingPoint, RadixTree.STARTING_Y);
+ this.animateNewPositions(this.root);
+ this.cmd("Step");
+ }
+
+}
+
+
+RadixTree.prototype.add = function(word)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "Inserting; ");
+ this.cmd("SetText", 1, word);
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+ this.highlightID = this.nextIndex++;
+ this.root = this.addR(word.toUpperCase(), this.root, RadixTree.LEFT_MARGIN + RadixTree.NODE_WIDTH / 2 + 1, RadixTree.STARTING_Y, 0);
+ this.resizeTree();
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+
+ return this.commands;
+}
+
+
+RadixTree.prototype.addR = function(s, rt, startX, startY, wordIndex)
+{
+ if (rt == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, s, RadixTree.NEW_NODE_X, RadixTree.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, RadixTree.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, RadixTree.BACKGROUND_COLOR);
+ this.cmd("SetWidth", this.nextIndex, RadixTree.NODE_WIDTH);
+ this.cmd("SetText", 2, "Reached an empty tree. Creating a node containing " + s);
+ this.cmd("Step");
+ this.cmd("SetText", 2, "" );
+ rt = new RadixNode(s, this.nextIndex, startX, startY)
+ this.nextIndex += 1;
+ rt.isword = true;
+ return rt;
+ }
+
+ this.cmd("SetHighlight", rt.graphicID , 1);
+
+
+
+
+ var indexDifference = this.findIndexDifference(s, rt.wordRemainder, rt.graphicID, wordIndex);
+
+// this.cmd("CreateHighlightCircle", this.highlightID, BST.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+// this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+// this.cmd("Step");
+
+
+
+ if (indexDifference == rt.wordRemainder.length)
+ {
+
+ this.cmd("SetText", 2, "Reached the end of the prefix stored at this node");
+ this.cmd("Step");
+
+ if (s.length > indexDifference)
+ {
+ this.cmd("SetText", 2, "Recusively insert remaining string \ninto the '" +s.charAt(indexDifference) + "' child");
+ this.cmd("Step");
+ this.cmd("SetHighlight", rt.graphicID , 0);
+ this.cmd("SetText", 1, s.substring(indexDifference));
+
+
+
+ // TODO: HIGHLIGHT CIRCLE!
+
+ var index = s.charCodeAt(indexDifference) - "A".charCodeAt(0);
+ var noChild = rt.children[index] == null;
+
+
+ if (noChild)
+ {
+ this.cmd("SetText", 2, "Child '" +s.charAt(indexDifference) + "' does not exit. Creating ...");
+ this.cmd("Step");
+
+ } else {
+
+
+ this.cmd("CreateHighlightCircle", this.highlightID, RadixTree.HIGHLIGHT_CIRCLE_COLOR, rt.x, rt.y);
+ this.cmd("SetWidth", this.highlightID, RadixTree.NODE_WIDTH);
+
+ this.cmd("Step")
+ this.cmd("Move", this.highlightID, rt.children[index].x, rt.children[index].y);
+ this.cmd("Step")
+
+ this.cmd("Delete", this.highlightID);
+ // DO HIGHILIGHT CIRCLE THING HERE
+ }
+
+
+ var connect = rt.children[index] == null;
+ rt.children[index] = this.addR(s.substring(indexDifference), rt.children[index], rt.x, rt.y, wordIndex+indexDifference);
+ rt.children[index].parent = rt;
+ if (connect)
+ {
+ this.cmd("Connect", rt.graphicID, rt.children[index].graphicID, RadixTree.FOREGROUND_COLOR, 0, false, s.charAt(indexDifference));
+ }
+ return rt;
+ }
+ this.cmd("SetText", 2, "Reached the end of the string. Set Current node to \"True\"")
+ this.cmd("Step");
+ this.cmd("SetText", 2, "")
+
+ this.cmd("SetBackgroundColor", rt.graphicID, RadixTree.BACKGROUND_COLOR);
+ this.cmd("Step");
+ this.cmd("SetHighlight", rt.graphicID , 0);
+
+ rt.isword = true;
+ return rt;
+ }
+
+ var firstRemainder = rt.wordRemainder.substring(0, indexDifference);
+ var secondRemainder = rt.wordRemainder.substring(indexDifference);
+
+ this.cmd("SetText", 2, "Reached a mismatch in prefix. \nCreate a new node with common prefix")
+
+ this.cmd("CreateCircle", this.nextIndex, firstRemainder, RadixTree.NEW_NODE_X, RadixTree.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, RadixTree.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, RadixTree.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, RadixTree.NODE_WIDTH);
+ this.cmd("Step")
+
+ var newNode = new RadixNode(firstRemainder, this.nextIndex, 0, 0);
+ this.nextIndex += 1;
+
+ newNode.wordRemainder = firstRemainder;
+
+ var index = rt.wordRemainder.charCodeAt(indexDifference) - "A".charCodeAt(0);
+ newNode.parent = rt.parent;
+ newNode.children[index] = rt;
+ if (rt.parent != null)
+ {
+
+ this.cmd("Disconnect", rt.parent.graphicID, rt.graphicID);
+ this.cmd("Connect", rt.parent.graphicID, newNode.graphicID, RadixTree.FOREGROUND_COLOR, 0, false, newNode.wordRemainder.charAt(0));
+ var childIndex = newNode.wordRemainder.charCodeAt(0) - 'A'.charCodeAt(0);
+ rt.parent.children[childIndex] = newNode;
+ rt.parent = newNode;
+
+ }
+ else
+ {
+ this.root = newNode;
+ }
+ this.cmd("SetHighlight", rt.graphicID, 0);
+
+ rt.parent = newNode;
+
+ this.cmd("SetText", 2, "Connect new node to the old, and reset prefix stored at previous node");
+
+ this.cmd("Connect", newNode.graphicID, newNode.children[index].graphicID, RadixTree.FOREGROUND_COLOR, 0, false, rt.wordRemainder.charAt(indexDifference));
+ rt.wordRemainder = secondRemainder;
+ this.cmd("SetText", rt.graphicID, rt.wordRemainder);
+ this.cmd("Step");
+
+
+
+ this.resizeTree();
+
+ if (indexDifference == s.length)
+ {
+ newNode.isword = true;
+ this.cmd("SetBackgroundColor", newNode.graphicID, RadixTree.BACKGROUND_COLOR);
+ }
+ else
+ {
+ this.cmd("SetBackgroundColor", newNode.graphicID, RadixTree.FALSE_COLOR);
+ index = s.charCodeAt(indexDifference) - "A".charCodeAt(0)
+ this.cmd("SetText", 1, s.substring(indexDifference));
+
+ newNode.children[index] = this.addR(s.substring(indexDifference), null, rt.x, rt.y, indexDifference+wordIndex);
+ newNode.children[index].parent = newNode;
+ this.cmd("Connect", newNode.graphicID, newNode.children[index].graphicID, RadixTree.FOREGROUND_COLOR, 0, false, s.charAt(indexDifference));
+
+ }
+ return newNode;
+ }
+
+RadixTree.prototype.setNewPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ var newX = xPosition - tree.width / 2;
+ var newY = yPosition + RadixTree.HEIGHT_DELTA;
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ this.setNewPositions(tree.children[i], newX + tree.children[i].width / 2, newY);
+ newX = newX + tree.children[i].width;
+ }
+ }
+ }
+
+}
+RadixTree.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ for (var i = 0; i < 26; i++)
+ {
+ this.animateNewPositions(tree.children[i])
+ }
+ }
+}
+
+RadixTree.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ var size = 0;
+ for (var i = 0; i < 26; i++)
+ {
+ tree.childWidths[i] = this.resizeWidths(tree.children[i]);
+ size += tree.childWidths[i]
+ }
+ tree.width = Math.max(size, RadixTree.NODE_WIDTH + 4)
+ return tree.width;
+}
+
+
+
+
+function RadixNode(val, id, initialX, initialY)
+{
+ this.wordRemainder = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.children = new Array(26);
+ this.childWidths = new Array(26);
+ for (var i = 0; i < 26; i++)
+ {
+ this.children[i] = null;
+ this.childWidths[i] =0;
+ }
+ this.width = 0;
+ this.parent = null;
+ this.isword = false;
+}
+
+RadixTree.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+RadixTree.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new RadixTree(animManag, canvas.width, canvas.height);
+
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecFact.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecFact.js
new file mode 100644
index 0000000..ae5c91b
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecFact.js
@@ -0,0 +1,220 @@
+// 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
+
+
+
+function RecFact(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+RecFact.prototype = new Recursive();
+RecFact.prototype.constructor = RecFact;
+RecFact.superclass = Recursive.prototype;
+
+
+RecFact.MAX_VALUE = 20;
+
+RecFact.ACTIVATION_FIELDS = ["n ", "subValue ", "returnValue "];
+RecFact.CODE = [["def ","factorial(n)",":"],
+ [" if ","(n <= 1): "],
+ [" return 1"],
+ [" else:"],
+ [" subSolution = ", "factorial(n - 1)"],
+ [" solution = ", "subSolution * n"],
+ [" return ", "solution"]];
+
+
+RecFact.RECURSIVE_DELTA_Y = RecFact.ACTIVATION_FIELDS.length * Recursive.ACTIVATION_RECORD_HEIGHT;
+
+RecFact.ACTIVATION_RECORT_START_X = 330;
+RecFact.ACTIVATION_RECORT_START_Y = 20;
+
+
+
+RecFact.prototype.init = function(am, w, h)
+{
+ RecFact.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ this.code = RecFact.CODE;
+
+
+ this.addCodeToCanvas(this.code);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+RecFact.prototype.addControls = function()
+{
+ this.controls = [];
+ this.factorialField = addControlToAlgorithmBar("Text", "");
+ this.factorialField.onkeydown = this.returnSubmit(this.factorialField, this.factorialCallback.bind(this), 2, true);
+ this.controls.push(this.factorialField);
+
+ this.factorialButton = addControlToAlgorithmBar("Button", "Factorial");
+ this.factorialButton.onclick = this.factorialCallback.bind(this);
+ this.controls.push(this.factorialButton);
+
+}
+
+
+
+
+RecFact.prototype.factorialCallback = function(event)
+{
+ var factValue;
+
+ if (this.factorialField.value != "")
+ {
+ var factValue = Math.min(parseInt(this.factorialField.value), RecFact.MAX_VALUE);
+ this.factorialField.value = String(factValue);
+ this.implementAction(this.doFactorial.bind(this),factValue);
+ }
+}
+
+
+
+
+RecFact.prototype.doFactorial = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ this.currentY = RecFact.ACTIVATION_RECORT_START_Y;
+ this.currentX = RecFact.ACTIVATION_RECORT_START_X;
+
+ var final = this.factorial(value);
+ var resultID = this.nextIndex++;
+ this.oldIDs.push(resultID);
+ this.cmd("CreateLabel", resultID, "factorial(" + String(value) + ") = " + String(final),
+ Recursive.CODE_START_X, Recursive.CODE_START_Y + (this.code.length + 1) * Recursive.CODE_LINE_HEIGHT, 0);
+ //this.cmd("SetText", functionCallID, "factorial(" + String(value) + ") = " + String(final));
+ return this.commands;
+}
+
+
+RecFact.prototype.factorial = function(value)
+{
+ var activationRec = this.createActivation("factorial ", RecFact.ACTIVATION_FIELDS, this.currentX, this.currentY);
+ this.cmd("SetText", activationRec.fieldIDs[0], value);
+// this.cmd("CreateLabel", ID, "", 10, this.currentY, 0);
+ var oldX = this.currentX;
+ var oldY = this.currentY;
+ this.currentY += RecFact.RECURSIVE_DELTA_Y;
+ if (this.currentY + Recursive.RECURSIVE_DELTA_Y > this.canvasHeight)
+ {
+ this.currentY = RecFact.ACTIVATION_RECORT_START_Y;
+ this.currentX += Recursive.ACTIVATION_RECORD_SPACING;
+ }
+ this.cmd("SetForegroundColor", this.codeID[0][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_STANDARD_COLOR);
+ if (value > 1)
+ {
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_STANDARD_COLOR);
+
+ var firstValue = this.factorial(value-1);
+
+ this.cmd("SetForegroundColor", this.codeID[4][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", activationRec.fieldIDs[1], firstValue);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_STANDARD_COLOR);
+
+ this.cmd("SetForegroundColor", this.codeID[5][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", activationRec.fieldIDs[2], firstValue * value);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[5][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_STANDARD_COLOR);
+
+ this.cmd("SetForegroundColor", this.codeID[6][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][1], Recursive.CODE_HIGHLIGHT_COLOR);
+
+ this.cmd("Step");
+ this.deleteActivation(activationRec);
+ this.currentY = oldY;
+ this.currentX = oldX;
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = " + String(firstValue * value), oldX, oldY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("Delete",this.nextIndex);
+
+
+
+// this.cmd("SetForegroundColor", this.codeID[4][3], Recursive.CODE_HIGHLIGHT_COLOR);
+// this.cmd("Step");
+
+ return firstValue *value;
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[2][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], Recursive.CODE_STANDARD_COLOR);
+
+
+ this.currentY = oldY;
+ this.currentX = oldX;
+ this.deleteActivation(activationRec);
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = 1", oldX, oldY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete",this.nextIndex);
+
+ return 1;
+ }
+
+
+
+}
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new RecFact(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecQueens.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecQueens.js
new file mode 100644
index 0000000..16afa98
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecQueens.js
@@ -0,0 +1,453 @@
+// 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 ``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 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
+
+
+
+function Queens(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+Queens.prototype = new Recursive();
+Queens.prototype.constructor = Queens;
+Queens.superclass = Recursive.prototype;
+
+Queens.CALC_QUEENS_ACTIVATION_FIELDS = [" size ", " board "];
+Queens.QUEENS_ACTIVATION_FIELDS = [" board ", " current ", " size ", " i ", " done "];
+Queens.CHECK_ACTIVATION_FIELDS = [" board ", " current ", " i "];
+
+Queens.CODE = [["def ","calcQueens(size)",":"],
+ [" board = ", "[-1] * size"],
+ [ " return ","queens(board, 0, size)"],
+ [" "],
+ ["def ","queens(board, current, size)",":"],
+ [" if ", "(current == size):"],
+ [" return true"],
+ [" else:"],
+ [" for i in range(size):"],
+ [" board[current] = i"],
+ [" if (","noConflicts(board, current)",":"],
+ [" done"," = ", "queens(board, current + 1, size)"],
+ [" if (done):"],
+ [" return true"],
+ [" return false"],
+ [" "],
+ ["def ","noConflicts(board, current)",":"],
+ [" for i in range(current):"],
+ [" if ","(board[i] == board[current])",":"],
+ [" return false"],
+ [" if ","(current - i == abs(board[current] = board[i]))",":"],
+ [" return false"],
+ [" return true"]];
+
+
+Queens.RECURSIVE_DELTA_Y_CALC_QUEEN = Queens.CALC_QUEENS_ACTIVATION_FIELDS.length * Recursive.ACTIVATION_RECORD_HEIGHT;
+Queens.RECURSIVE_DELTA_Y_QUEEN = Queens.QUEENS_ACTIVATION_FIELDS.length * Recursive.ACTIVATION_RECORD_HEIGHT;
+Queens.RECURSIVE_DELTA_Y_CHECK = Queens.CHECK_ACTIVATION_FIELDS.length * Recursive.ACTIVATION_RECORD_HEIGHT;
+
+
+Queens.ACTIVATION_RECORT_START_X = 450;
+Queens.ACTIVATION_RECORT_START_Y = 20;
+
+Queens.INTERNAL_BOARD_START_X = 600;
+Queens.INTERNAL_BOARD_START_Y = 100;
+Queens.INTERNAL_BOARD_WIDTH = 20;
+Queens.INTERNAL_BOARD_HEIGHT = 20;
+
+Queens.LOGICAL_BOARD_START_X = Queens.INTERNAL_BOARD_START_X;
+Queens.LOGICAL_BOARD_START_Y = Queens.INTERNAL_BOARD_START_Y + Queens.INTERNAL_BOARD_HEIGHT * 1.5;
+Queens.LOGICAL_BOARD_WIDTH = Queens.INTERNAL_BOARD_WIDTH;
+Queens.LOGICAL_BOARD_HEIGHT = Queens.INTERNAL_BOARD_HEIGHT;
+Queens.ACTIVATION_RECORD_SPACING = 400;
+
+
+Queens.INDEX_COLOR = "#0000FF";
+
+Queens.prototype.init = function(am, w, h)
+{
+ Queens.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ this.code = Queens.CODE;
+
+
+ this.addCodeToCanvas(this.code);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+Queens.prototype.addControls = function()
+{
+ this.controls = [];
+ addLabelToAlgorithmBar("Board size: (1-8)");
+
+ this.sizeField = addControlToAlgorithmBar("Text", "");
+ this.sizeField.onkeydown = this.returnSubmit(this.sizeField, this.queensCallback.bind(this), 2, true);
+ this.controls.push(this.sizeField);
+
+ this.queensButton = addControlToAlgorithmBar("Button", "Queens");
+ this.queensButton.onclick = this.queensCallback.bind(this);
+ this.controls.push(this.queensButton);
+
+}
+
+
+
+
+Queens.prototype.queensCallback = function(event)
+{
+ var queensValue;
+
+ if (this.sizeField.value != "")
+ {
+ var queenSize = parseInt(this.sizeField.value);
+ queenSize = Math.min(queenSize, 8);
+ this.sizeField.value = String(queenSize);
+ this.implementAction(this.doQueens.bind(this),queenSize);
+ }
+}
+
+
+
+
+Queens.prototype.doQueens = function(size)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+
+ this.boardData = new Array(size);
+ this.boardInternalID = new Array(size);
+ this.boardLogicalID = new Array(size);
+ this.boardInternalIndexID = new Array(size);
+
+
+ this.currentY = Queens.ACTIVATION_RECORT_START_Y;
+ this.currentX = Queens.ACTIVATION_RECORT_START_X;
+ this.activationLeft = true;
+
+
+ this.cmd("SetForegroundColor", this.codeID[0][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ var activationRec = this.createActivation("calcQueens", Queens.CALC_QUEENS_ACTIVATION_FIELDS, this.currentX, this.currentY, this.activationLeft);
+ this.currentY += Queens.RECURSIVE_DELTA_Y_CALC_QUEEN;
+
+ this.cmd("SetText", activationRec.fieldIDs[0], size);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_HIGHLIGHT_COLOR);
+
+
+ for (var i = 0; i < size; i++)
+ {
+ this.boardInternalID[i] = this.nextIndex++;
+ this.oldIDs.push(this.boardInternalID[i])
+ this.cmd("CreateRectangle", this.boardInternalID[i],
+ "-1",
+ Queens.INTERNAL_BOARD_WIDTH,
+ Queens.INTERNAL_BOARD_HEIGHT,
+ Queens.INTERNAL_BOARD_START_X + i * Queens.INTERNAL_BOARD_WIDTH,
+ Queens.INTERNAL_BOARD_START_Y);
+
+ this.boardInternalIndexID[i] = this.nextIndex++;
+ this.oldIDs.push(this.boardInternalIndexID[i]);
+ this.cmd("CreateLabel", this.boardInternalIndexID[i], i,Queens.INTERNAL_BOARD_START_X + i * Queens.INTERNAL_BOARD_WIDTH,
+ Queens.INTERNAL_BOARD_START_Y - Queens.INTERNAL_BOARD_HEIGHT);
+ this.cmd("SetForegroundColor", this.boardInternalIndexID[i], Queens.INDEX_COLOR);
+
+ this.boardLogicalID[i] = new Array(size);
+ for (var j = 0; j < size; j++)
+ {
+ this.boardLogicalID[i][j] = this.nextIndex++;
+ this.oldIDs.push(this.boardLogicalID[i][j]);
+
+ this.cmd("CreateRectangle", this.boardLogicalID[i][j],
+ "",
+ Queens.LOGICAL_BOARD_WIDTH,
+ Queens.LOGICAL_BOARD_HEIGHT,
+ Queens.LOGICAL_BOARD_START_X + j * Queens.LOGICAL_BOARD_WIDTH,
+ Queens.LOGICAL_BOARD_START_Y + i * Queens.LOGICAL_BOARD_HEIGHT);
+
+
+ }
+ }
+ this.cmd("Connect", activationRec.fieldIDs[1], this.boardInternalID[0]);
+ this.cmd("Step");
+
+ this.cmd("SetForegroundColor", this.codeID[1][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[2][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][1], Recursive.CODE_STANDARD_COLOR);
+
+
+
+
+ board = new Array(size);
+ this.queens(board, 0, size);
+ this.cmd("Step");
+ this.cmd("Delete", this.nextIndex);
+ this.deleteActivation(activationRec);
+
+
+ return this.commands;
+}
+
+
+Queens.prototype.queens = function(board, current, size)
+{
+ var oldX = this.currentX;
+ var oldY = this.currentY;
+ var oldLeft = this.activationLeft;
+ var activationRec = this.createActivation("queens", Queens.QUEENS_ACTIVATION_FIELDS, this.currentX, this.currentY, this.activationLeft);
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_HIGHLIGHT_COLOR);
+
+ this.cmd("SetText", activationRec.fieldIDs[1], current);
+ this.cmd("SetText", activationRec.fieldIDs[2], size);
+ if (this.activationLeft)
+ {
+ this.cmd("Connect", activationRec.fieldIDs[0], this.boardInternalID[0]);
+ }
+ else
+ {
+ this.cmd("Connect", activationRec.fieldIDs[0], this.boardInternalID[size-1]);
+ }
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_STANDARD_COLOR);
+
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_STANDARD_COLOR);
+
+
+ this.currentY += Queens.RECURSIVE_DELTA_Y_QUEEN;
+ if (this.currentY + Queens.RECURSIVE_DELTA_Y_QUEEN > this.canvasHeight)
+ {
+ this.currentY = Queens.ACTIVATION_RECORT_START_Y;
+ this.currentX += Queens.ACTIVATION_RECORD_SPACING;
+ this.activationLeft = false;
+ }
+
+ if (current == size)
+ {
+ this.cmd("SetForegroundColor", this.codeID[6][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], Recursive.CODE_STANDARD_COLOR);
+
+ this.deleteActivation(activationRec);
+ this.currentX = oldX;
+ this.currentY = oldY;
+ this.activationLeft = oldLeft;
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = true", this.currentX, this.currentY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+
+ return true;
+ }
+
+ var i;
+ for (i = 0; i < size; i++)
+ {
+ this.cmd("SetTextColor", this.codeID[8][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ board[current] = i;
+ this.cmd("SetText", activationRec.fieldIDs[3], i);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[8][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.codeID[9][0], Recursive.CODE_HIGHLIGHT_COLOR);
+
+
+ this.cmd("SetText", this.boardLogicalID[i][current], "Q");
+ this.cmd("SetText", this.boardInternalID[current], i);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[9][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.codeID[10][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[10][1], Recursive.CODE_STANDARD_COLOR);
+
+ var moveLegal = this.legal(board,current);
+ this.cmd("SetTextColor", this.codeID[10][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetTextColor", this.codeID[10][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete",this.nextIndex);
+ this.cmd("SetTextColor", this.codeID[10][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.codeID[10][1], Recursive.CODE_STANDARD_COLOR);
+
+
+
+
+ if (moveLegal)
+ {
+ this.cmd("SetTextColor", this.codeID[11][2], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[11][2], Recursive.CODE_STANDARD_COLOR);
+ var done = this.queens(board, current+1, size);
+ this.cmd("SetTextColor", this.codeID[11][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetTextColor", this.codeID[11][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetTextColor", this.codeID[11][2], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", activationRec.fieldIDs[4], done);
+ this.cmd("Step");
+ this.cmd("Delete", this.nextIndex);
+ this.cmd("SetTextColor", this.codeID[11][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.codeID[11][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.codeID[11][2], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.codeID[12][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[12][0], Recursive.CODE_STANDARD_COLOR);
+
+ if (done)
+ {
+ this.cmd("SetTextColor", this.codeID[13][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[13][0], Recursive.CODE_STANDARD_COLOR);
+
+ this.deleteActivation(activationRec);
+ this.currentX = oldX;
+ this.currentY = oldY;
+ this.activationLeft = oldLeft;
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = true", this.currentX, this.currentY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+
+ return true;
+ }
+ }
+ this.cmd("SetText", this.boardLogicalID[i][current], "");
+
+
+ }
+ this.cmd("SetTextColor", this.codeID[14][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.codeID[14][0], Recursive.CODE_STANDARD_COLOR);
+ this.deleteActivation(activationRec);
+ this.currentX = oldX;
+ this.currentY = oldY;
+ this.activationLeft = oldLeft;
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = false", this.currentX, this.currentY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+
+ return false;
+}
+
+
+Queens.prototype.legal = function(board, current)
+{
+ var activationRec = this.createActivation("noConflicts", Queens.CHECK_ACTIVATION_FIELDS, this.currentX, this.currentY, this.activationLeft);
+ this.cmd("SetText", activationRec.fieldIDs[1], current);
+ if (this.activationLeft)
+ {
+ this.cmd("Connect", activationRec.fieldIDs[0], this.boardInternalID[0]);
+ }
+ else
+ {
+ this.cmd("Connect", activationRec.fieldIDs[0], this.boardInternalID[this.boardInternalID.length - 1]);
+ }
+ this.cmd("SetForegroundColor", this.codeID[16][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[16][1], Recursive.CODE_STANDARD_COLOR);
+
+
+ var i;
+ var OK = true;
+ if (current == 0)
+ {
+ this.cmd("SetForegroundColor", this.codeID[17][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetForegroundColor", this.codeID[17][0], Recursive.CODE_STANDARD_COLOR);
+ }
+ for (i = 0; i < current; i++)
+ {
+ this.cmd("SetText", activationRec.fieldIDs[2], i);
+ this.cmd("SetTextColor", activationRec.fieldIDs[2], Recursive.CODE_HIGHLIGHT_COLOR)
+ this.cmd("SetForegroundColor", this.codeID[17][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetForegroundColor", this.codeID[17][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", activationRec.fieldIDs[2], Recursive.CODE_STANDARD_COLOR)
+ this.cmd("SetForegroundColor", this.codeID[18][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetTextColor", this.boardLogicalID[board[current]][current], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetTextColor", this.boardLogicalID[board[i]][i], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.boardLogicalID[board[current]][current], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.boardLogicalID[board[i]][i], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[18][1], Recursive.CODE_STANDARD_COLOR);
+
+ if (board[i] == board[current])
+ {
+ this.cmd("SetForegroundColor", this.codeID[19][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[19][0], Recursive.CODE_STANDARD_COLOR);
+ OK = false;
+ break;
+ }
+ this.cmd("SetTextColor", this.boardLogicalID[board[current]][current], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetTextColor", this.boardLogicalID[board[i]][i], Recursive.CODE_HIGHLIGHT_COLOR);
+
+ this.cmd("SetForegroundColor", this.codeID[20][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetTextColor", this.boardLogicalID[board[current]][current], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetTextColor", this.boardLogicalID[board[i]][i], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[20][1], Recursive.CODE_STANDARD_COLOR);
+
+ if (current - i == Math.abs(board[current] - board[i]))
+ {
+ this.cmd("SetForegroundColor", this.codeID[21][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[21][0], Recursive.CODE_STANDARD_COLOR);
+
+ OK = false;
+ break;
+ }
+
+ }
+ if (OK)
+ {
+ this.cmd("SetForegroundColor", this.codeID[22][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[22][0], Recursive.CODE_STANDARD_COLOR);
+ }
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = " + String(OK), this.currentX, this.currentY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+ this.deleteActivation(activationRec);
+
+ return OK;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Queens(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecReverse.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecReverse.js
new file mode 100644
index 0000000..6467a98
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RecReverse.js
@@ -0,0 +1,229 @@
+// 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 ``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 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
+
+
+
+function Reverse(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+Reverse.prototype = new Recursive();
+Reverse.prototype.constructor = Reverse;
+Reverse.superclass = Recursive.prototype;
+
+Reverse.ACTIVATION_FIELDS = ["word ", "subProblem ", "subSolution ", "solution "];
+
+Reverse.CODE = [["def ","reverse(word)",":"],
+ [" if ","(word == \"\"): "],
+ [" return word"],
+ [" else:"],
+ [" subProblem = ", "word[1:]"],
+ [" subSolution = ", "reverse(subProblem)"],
+ [" solution = ", "subSolution + word[0]"],
+ [" return = ", "solution"]];
+
+
+Reverse.RECURSIVE_DELTA_Y = Reverse.ACTIVATION_FIELDS.length * Recursive.ACTIVATION_RECORD_HEIGHT;
+
+
+Reverse.ACTIVATION_RECORT_START_X = 375;
+Reverse.ACTIVATION_RECORT_START_Y = 20;
+
+
+
+Reverse.prototype.init = function(am, w, h)
+{
+ Reverse.superclass.init.call(this, am, w, h);
+ this.nextIndex = 0;
+ this.addControls();
+ this.code = Reverse.CODE;
+
+
+ this.addCodeToCanvas(this.code);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.initialIndex = this.nextIndex;
+ this.oldIDs = [];
+ this.commands = [];
+}
+
+
+Reverse.prototype.addControls = function()
+{
+ this.controls = [];
+ this.reverseField = addControlToAlgorithmBar("Text", "");
+ this.reverseField.onkeydown = this.returnSubmit(this.reverseField, this.reverseCallback.bind(this), 10, false);
+ this.controls.push(this.reverseField);
+
+ this.reverseButton = addControlToAlgorithmBar("Button", "Reverse");
+ this.reverseButton.onclick = this.reverseCallback.bind(this);
+ this.controls.push(this.reverseButton);
+
+}
+
+
+
+
+Reverse.prototype.reverseCallback = function(event)
+{
+ var factValue;
+
+ if (this.reverseField.value != "")
+ {
+ var revValue =this.reverseField.value;
+ this.implementAction(this.doReverse.bind(this),revValue);
+ }
+}
+
+
+
+
+Reverse.prototype.doReverse = function(value)
+{
+ this.commands = [];
+
+ this.clearOldIDs();
+
+ this.currentY = Reverse.ACTIVATION_RECORT_START_Y;
+ this.currentX = Reverse.ACTIVATION_RECORT_START_X;
+
+ var final = this.reverse(value);
+ var resultID = this.nextIndex++;
+ this.oldIDs.push(resultID);
+ this.cmd("CreateLabel", resultID, "reverse(" + String(value) + ") = " + String(final),
+ Recursive.CODE_START_X, Recursive.CODE_START_Y + (this.code.length + 1) * Recursive.CODE_LINE_HEIGHT, 0);
+ return this.commands;
+}
+
+
+Reverse.prototype.reverse = function(value)
+{
+
+ var activationRec = this.createActivation("reverse ", Reverse.ACTIVATION_FIELDS, this.currentX, this.currentY);
+ this.cmd("SetText", activationRec.fieldIDs[0], value);
+// this.cmd("CreateLabel", ID, "", 10, this.currentY, 0);
+ var oldX = this.currentX;
+ var oldY = this.currentY;
+ this.currentY += Reverse.RECURSIVE_DELTA_Y;
+ if (this.currentY + Recursive.RECURSIVE_DELTA_Y > this.canvasHeight)
+ {
+ this.currentY = Reverse.ACTIVATION_RECORT_START_Y;
+ this.currentX += Recursive.ACTIVATION_RECORD_SPACING;
+ }
+ this.cmd("SetForegroundColor", this.codeID[0][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[0][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[1][1], Recursive.CODE_STANDARD_COLOR);
+ if (value != "")
+ {
+ this.cmd("SetForegroundColor", this.codeID[4][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ var subProblem = value.substr(1);
+ this.cmd("SetText", activationRec.fieldIDs[1], subProblem);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[4][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[4][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_STANDARD_COLOR);
+
+
+
+ var subSolution = this.reverse(subProblem);
+
+ this.cmd("SetForegroundColor", this.codeID[5][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", activationRec.fieldIDs[2], subSolution);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[5][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[5][1], Recursive.CODE_STANDARD_COLOR);
+
+ this.cmd("SetForegroundColor", this.codeID[6][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][1], Recursive.CODE_HIGHLIGHT_COLOR);
+ var solution = subSolution + value[0];
+ this.cmd("SetText", activationRec.fieldIDs[3], solution);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[6][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[6][1], Recursive.CODE_STANDARD_COLOR);
+
+ this.cmd("SetForegroundColor", this.codeID[7][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[7][1], Recursive.CODE_HIGHLIGHT_COLOR);
+
+ this.cmd("Step");
+ this.deleteActivation(activationRec);
+ this.currentY = oldY;
+ this.currentX = oldX;
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = \"" + solution + "\"", oldX, oldY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[7][0], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.codeID[7][1], Recursive.CODE_STANDARD_COLOR);
+ this.cmd("Delete",this.nextIndex);
+
+
+
+// this.cmd("SetForegroundColor", this.codeID[4][3], Recursive.CODE_HIGHLIGHT_COLOR);
+// this.cmd("Step");
+
+ return solution;
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", this.codeID[2][0], Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.codeID[2][0], Recursive.CODE_STANDARD_COLOR);
+
+
+ this.currentY = oldY;
+ this.currentX = oldX;
+ this.deleteActivation(activationRec);
+ this.cmd("CreateLabel", this.nextIndex, "Return Value = \"\"", oldX, oldY);
+ this.cmd("SetForegroundColor", this.nextIndex, Recursive.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete",this.nextIndex);
+
+ return "";
+ }
+
+
+
+}
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Reverse(animManag, canvas.width, canvas.height);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Recursive.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Recursive.js
new file mode 100644
index 0000000..dc03d17
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Recursive.js
@@ -0,0 +1,222 @@
+// 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 ``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 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
+
+
+
+function Recursive(am, w, h)
+{
+ if (am != undefined)
+ this.init(am, w, h);
+
+}
+
+Recursive.prototype = new Algorithm();
+Recursive.prototype.constructor = Recursive;
+Recursive.superclass = Algorithm.prototype;
+
+
+Recursive.CODE_START_X = 10;
+Recursive.CODE_START_Y = 10;
+Recursive.CODE_LINE_HEIGHT = 14;
+
+Recursive.RECURSIVE_START_X = 20;
+Recursive.RECURSIVE_START_Y = 120;
+Recursive.RECURSIVE_DELTA_Y = 14;
+Recursive.RECURSIVE_DELTA_X = 15;
+Recursive.CODE_HIGHLIGHT_COLOR = "#FF0000";
+Recursive.CODE_STANDARD_COLOR = "#000000";
+
+Recursive.TABLE_INDEX_COLOR = "#0000FF"
+Recursive.CODE_RECURSIVE_1_COLOR = "#339933";
+Recursive.CODE_RECURSIVE_2_COLOR = "#0099FF";
+
+Recursive.ACTIVATION_RECORD_WIDTH = 100;
+Recursive.ACTIVATION_RECORD_HEIGHT = 20;
+
+Recursive.ACTIVATION_RECORD_SPACING = 2 * Recursive.ACTIVATION_RECORD_WIDTH + 10;
+
+
+
+
+Recursive.SEPARATING_LINE_COLOR = "#0000FF"
+
+Recursive.prototype.addCodeToCanvas = function(code)
+{
+ this.codeID = this.addCodeToCanvasBase(code, Recursive.CODE_START_X, Recursive.CODE_START_Y, Recursive.CODE_LINE_HEIGHT, Recursive.CODE_STANDARD_COLOR);
+/* this.codeID = Array(this.code.length);
+ var i, j;
+ for (i = 0; i < code.length; i++)
+ {
+ this.codeID[i] = new Array(code[i].length);
+ for (j = 0; j < code[i].length; j++)
+ {
+ this.codeID[i][j] = this.nextIndex++;
+ this.cmd("CreateLabel", this.codeID[i][j], code[i][j], Recursive.CODE_START_X, Recursive.CODE_START_Y + i * Recursive.CODE_LINE_HEIGHT, 0);
+ this.cmd("SetForegroundColor", this.codeID[i][j], Recursive.CODE_STANDARD_COLOR);
+ if (j > 0)
+ {
+ this.cmd("AlignRight", this.codeID[i][j], this.codeID[i][j-1]);
+ }
+ }
+
+
+ } */
+
+}
+
+
+Recursive.prototype.init = function(am, w, h)
+{
+ Recursive.superclass.init.call(this, am, w, h);
+}
+
+
+Recursive.prototype.clearOldIDs = function()
+{
+ for (var i = 0; i < this.oldIDs.length; i++)
+ {
+ this.cmd("Delete", this.oldIDs[i]);
+ }
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+Recursive.prototype.reset = function()
+{
+ this.oldIDs =[];
+ this.nextIndex = this.initialIndex;
+}
+
+
+
+
+Recursive.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+Recursive.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+Recursive.prototype.deleteActivation = function(activationRec)
+{
+ var i;
+ for (i = 0; i < activationRec.labelIDs.length; i++)
+ {
+ this.cmd("Delete", activationRec.labelIDs[i]);
+ this.cmd("Delete", activationRec.fieldIDs[i]);
+ }
+ this.cmd("Delete", activationRec.separatingLineID);
+ this.cmd("Delete", activationRec.nameID);
+}
+
+
+Recursive.prototype.createActivation = function(functionName, argList, x, y, labelsOnLeft)
+{
+ var activationRec = new ActivationRecord(argList);
+ var i;
+ activationRec.nameID = this.nextIndex++;
+ labelsOnLeft = (labelsOnLeft == undefined) ? true : labelsOnLeft;
+ for (i = 0; i < argList.length; i++)
+ {
+ var valueID = this.nextIndex++;
+ activationRec.fieldIDs[i] = valueID;
+
+ this.cmd("CreateRectangle", valueID,
+ "",
+ Recursive.ACTIVATION_RECORD_WIDTH,
+ Recursive.ACTIVATION_RECORD_HEIGHT,
+ x,
+ y + i * Recursive.ACTIVATION_RECORD_HEIGHT);
+
+ var labelID = this.nextIndex++;
+ activationRec.labelIDs[i] = labelID;
+ this.cmd("CreateLabel", labelID, argList[i]);
+ if (labelsOnLeft)
+ this.cmd("AlignLeft", labelID, valueID);
+ else
+ this.cmd("AlignRight", labelID, valueID);
+ }
+ activationRec.separatingLineID = this.nextIndex++;
+ this.cmd("CreateLabel", activationRec.nameID, " " + functionName + " ");
+ this.cmd("SetForegroundColor", activationRec.nameID, Recursive.SEPARATING_LINE_COLOR);
+
+ if (labelsOnLeft)
+ {
+ this.cmd("CreateRectangle", activationRec.separatingLineID,
+ "",
+ Recursive.ACTIVATION_RECORD_WIDTH * 2,
+ 1,
+ x - Recursive.ACTIVATION_RECORD_WIDTH / 2,
+ y - Recursive.ACTIVATION_RECORD_HEIGHT / 2);
+ this.cmd("AlignLeft", activationRec.nameID, activationRec.labelIDs[0]);
+ }
+ else
+ {
+ this.cmd("CreateRectangle", activationRec.separatingLineID,
+ "",
+ Recursive.ACTIVATION_RECORD_WIDTH * 2,
+ 1,
+ x + Recursive.ACTIVATION_RECORD_WIDTH / 2,
+ y - Recursive.ACTIVATION_RECORD_HEIGHT / 2);
+ this.cmd("AlignRight", activationRec.nameID, activationRec.labelIDs[0]);
+
+ }
+ this.cmd("SetForegroundColor", activationRec.separatingLineID, Recursive.SEPARATING_LINE_COLOR);
+ return activationRec;
+
+}
+
+
+
+function ActivationRecord(fields)
+{
+ this.fields = fields;
+ this.values = new Array(this.fields.length);
+ var i;
+ for (i = 0; i < this.fields.length; i++)
+ {
+ this.values[i] = "";
+ }
+ this.fieldIDs = new Array(this.fields.length);
+ this.labelIDs = new Array(this.fields.length);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RedBlack.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RedBlack.js
new file mode 100644
index 0000000..795ada6
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RedBlack.js
@@ -0,0 +1,1502 @@
+// 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 ``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 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
+
+function RedBlack(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+RedBlack.prototype = new Algorithm();
+RedBlack.prototype.constructor = RedBlack;
+RedBlack.superclass = Algorithm.prototype;
+
+RedBlack.prototype.init = function(am, w, h)
+{
+ var sc = RedBlack.superclass;
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 1;
+ this.commands = [];
+ this.startingX = w / 2;
+ this.print_max = w - PRINT_HORIZONTAL_GAP;
+ this.first_print_pos_y = h - 2 * PRINT_VERTICAL_GAP;
+
+
+ this.cmd("CreateLabel", 0, "", EXPLANITORY_TEXT_X, EXPLANITORY_TEXT_Y, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+RedBlack.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 4);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+
+ this.showNullLeaves = addCheckboxToAlgorithmBar("显示null叶子节点");
+ this.showNullLeaves.onclick = this.showNullLeavesCallback.bind(this);
+ this.showNullLeaves.checked = false;;
+
+}
+
+RedBlack.prototype.reset = function()
+{
+ this.nextIndex = 1;
+ this.treeRoot = null;
+}
+
+var FIRST_PRINT_POS_X = 50;
+var PRINT_VERTICAL_GAP = 20;
+var PRINT_HORIZONTAL_GAP = 50;
+
+
+var FOREGROUND_RED = "#ffffff";
+var BACKGROUND_RED = "#ff0000";
+
+var FOREGROUND_BLACK = "#ffffff"
+var BACKGROUND_BLACK = "#000000";
+var BACKGROUND_DOUBLE_BLACK = "#777777";
+
+
+// var HIGHLIGHT_LABEL_COLOR = RED
+// var HIGHLIGHT_LINK_COLOR = RED
+
+
+var HIGHLIGHT_LABEL_COLOR = "#FF0000"
+var HIGHLIGHT_LINK_COLOR = "#FF0000"
+
+var BLUE = "#0000FF";
+
+var LINK_COLOR = "#000000"
+var BACKGROUND_COLOR = BACKGROUND_BLACK;
+var HIGHLIGHT_COLOR = "#007700";
+var FOREGROUND_COLOR = FOREGROUND_BLACK;
+var PRINT_COLOR = FOREGROUND_COLOR
+
+var widthDelta = 50;
+var heightDelta = 50;
+var startingY = 50;
+
+
+var FIRST_PRINT_POS_X = 40;
+var PRINT_VERTICAL_GAP = 20;
+var PRINT_HORIZONTAL_GAP = 50;
+var EXPLANITORY_TEXT_X = 10;
+var EXPLANITORY_TEXT_Y = 10;
+
+RedBlack.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value;
+ // Get text value
+ insertedValue = this.normalizeNumber(insertedValue, 4);
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this), insertedValue);
+ }
+}
+
+RedBlack.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value;
+ if (deletedValue != "")
+ {
+ deletedValue = this.normalizeNumber(deletedValue, 4);
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+
+RedBlack.prototype.findCallback = function(event)
+{
+ var findValue = this.findField.value;
+ if (findValue != "")
+ {
+ findValue = this.normalizeNumber(findValue, 4);
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+ }
+}
+
+RedBlack.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+RedBlack.prototype.showNullLeavesCallback = function(event)
+{
+ if (this.showNullLeaves.checked)
+ {
+ this.animationManager.setAllLayers([0,1]);
+ }
+ else
+ {
+ this.animationManager.setAllLayers([0]);
+ }
+}
+
+
+RedBlack.prototype.printTree = function(unused)
+{
+ this.commands = [];
+
+ if (this.treeRoot != null)
+ {
+ this.highlightID = this.nextIndex++;
+ var firstLabel = this.nextIndex;
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, this.treeRoot.x, this.treeRoot.y);
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.treeRoot);
+ this.cmd("Delete",this.highlightID);
+ this.cmd("Step");
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ this.cmd("Delete", i);
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+}
+
+RedBlack.prototype.printTreeRec = function(tree)
+{
+ this.cmd("Step");
+ if (tree.left != null && !tree.left.phantomLeaf)
+ {
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.printTreeRec(tree.left);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.data, tree.x, tree.y);
+ this.cmd("SetForegroundColor", nextLabelID, PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += PRINT_VERTICAL_GAP;
+
+ }
+ if (tree.right != null && !tree.right.phantomLeaf)
+ {
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.printTreeRec(tree.right);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ return;
+}
+
+
+RedBlack.prototype.findElement = function(findValue)
+{
+ this.commands = [];
+
+ this.highlightID = this.nextIndex++;
+
+ this.doFind(this.treeRoot, findValue);
+
+
+ return this.commands;
+}
+
+
+RedBlack.prototype.doFind = function(tree, value)
+{
+ this.cmd("SetText", 0, "Searchiing for "+value);
+ if (tree != null && !tree.phantomLeaf)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (tree.data == value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " = " + value + " (Element found!)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "Found:"+value);
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ }
+ else
+ {
+ if (tree.data > value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " < " + tree.data + " (访问左子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.left!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.doFind(tree.left, value);
+ }
+ else
+ {
+ this.cmd("SetText", 0, " 正在搜索 "+value+":" + value + " > " + tree.data + " (访问右子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.right!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.doFind(tree.right, value);
+ }
+
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, " 正在搜索 "+value+":" + "< 空树 > (找不到元素)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, " 正在搜索 "+value+":" + " (找不到元素)");
+ }
+}
+
+
+
+
+
+RedBlack.prototype.findUncle = function(tree)
+{
+ if (tree.parent == null)
+ {
+ return null;
+ }
+ var par = tree.parent;
+ if (par.parent == null)
+ {
+ return null;
+ }
+ var grandPar = par.parent;
+
+ if (grandPar.left == par)
+ {
+ return grandPar.right;
+ }
+ else
+ {
+ return grandPar.left;
+ }
+}
+
+
+
+RedBlack.prototype.blackLevel = function(tree)
+{
+ if (tree == null)
+ {
+ return 1;
+ }
+ else
+ {
+ return tree.blackLevel;
+ }
+}
+
+
+RedBlack.prototype.attachLeftNullLeaf = function(node)
+{
+ // Add phantom left leaf
+ var treeNodeID = this.nextIndex++;
+ this.cmd("CreateCircle", treeNodeID, "null", node.x, node.y);
+ this.cmd("SetForegroundColor", treeNodeID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", treeNodeID, BACKGROUND_BLACK);
+ node.left = new RedBlackNode("", treeNodeID, this.startingX, startingY);
+ node.left.phantomLeaf = true;
+ this.cmd("SetLayer", treeNodeID, 1);
+ node.left.blackLevel = 1;
+ this.cmd("Connect",node.graphicID, treeNodeID, LINK_COLOR);
+}
+
+RedBlack.prototype.attachRightNullLeaf = function(node)
+{
+ // Add phantom right leaf
+ treeNodeID = this.nextIndex++;
+ this.cmd("CreateCircle", treeNodeID, "null", node.x, node.y);
+ this.cmd("SetForegroundColor", treeNodeID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", treeNodeID, BACKGROUND_BLACK);
+ node.right = new RedBlackNode("", treeNodeID, this.startingX, startingY);
+ this.cmd("SetLayer", treeNodeID, 1);
+
+ node.right.phantomLeaf = true;
+ node.right.blackLevel = 1;
+ this.cmd("Connect", node.graphicID, treeNodeID, LINK_COLOR);
+
+}
+RedBlack.prototype.attachNullLeaves = function(node)
+{
+ this.attachLeftNullLeaf(node);
+ this.attachRightNullLeaf(node);
+}
+
+RedBlack.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, " 正在添加 "+insertedValue);
+ this.highlightID = this.nextIndex++;
+ var treeNodeID;
+ if (this.treeRoot == null)
+ {
+ treeNodeID = this.nextIndex++;
+ this.cmd("CreateCircle", treeNodeID, insertedValue, this.startingX, startingY);
+ this.cmd("SetForegroundColor", treeNodeID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", treeNodeID, BACKGROUND_BLACK);
+ this.treeRoot = new RedBlackNode(insertedValue, treeNodeID, this.startingX, startingY);
+ this.treeRoot.blackLevel = 1;
+
+ this.attachNullLeaves(this.treeRoot);
+ this.resizeTree();
+
+ }
+ else
+ {
+ treeNodeID = this.nextIndex++;
+
+ this.cmd("CreateCircle", treeNodeID, insertedValue, 30, startingY);
+ this.cmd("SetForegroundColor", treeNodeID, FOREGROUND_RED);
+ this.cmd("SetBackgroundColor", treeNodeID, BACKGROUND_RED);
+ this.cmd("Step");
+ var insertElem = new RedBlackNode(insertedValue, treeNodeID, 100, 100)
+
+ this.cmd("SetHighlight", insertElem.graphicID, 1);
+ insertElem.height = 1;
+ this.insert(insertElem, this.treeRoot);
+ // resizeTree();
+ }
+ this.cmd("SetText", 0, " ");
+ return this.commands;
+}
+
+
+RedBlack.prototype.singleRotateRight = function(tree)
+{
+ var B = tree;
+ var t3 = B.right;
+ var A = tree.left;
+ var t1 = A.left;
+ var t2 = A.right;
+
+ this.cmd("SetText", 0, "右单旋");
+ this.cmd("SetEdgeHighlight", B.graphicID, A.graphicID, 1);
+ this.cmd("Step");
+
+ // TODO: Change link color
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", A.graphicID, t2.graphicID);
+ this.cmd("Connect", B.graphicID, t2.graphicID, LINK_COLOR);
+ t2.parent = B;
+ }
+ this.cmd("Disconnect", B.graphicID, A.graphicID);
+ this.cmd("Connect", A.graphicID, B.graphicID, LINK_COLOR);
+
+ A.parent = B.parent;
+ if (this.treeRoot == B)
+ {
+ this.treeRoot = A;
+ }
+ else
+ {
+ this.cmd("Disconnect", B.parent.graphicID, B.graphicID, LINK_COLOR);
+ this.cmd("Connect", B.parent.graphicID, A.graphicID, LINK_COLOR)
+ if (B.isLeftChild())
+ {
+ B.parent.left = A;
+ }
+ else
+ {
+ B.parent.right = A;
+ }
+ }
+ A.right = B;
+ B.parent = A;
+ B.left = t2;
+ this.resetHeight(B);
+ this.resetHeight(A);
+ this.resizeTree();
+ return A;
+}
+
+
+
+RedBlack.prototype.singleRotateLeft = function(tree)
+{
+ var A = tree;
+ var B = tree.right;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+
+ this.cmd("SetText", 0, "左单旋");
+ this.cmd("SetEdgeHighlight", A.graphicID, B.graphicID, 1);
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", B.graphicID, t2.graphicID);
+ this.cmd("Connect", A.graphicID, t2.graphicID, LINK_COLOR);
+ t2.parent = A;
+ }
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, LINK_COLOR);
+ B.parent = A.parent;
+ if (this.treeRoot == A)
+ {
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect", A.parent.graphicID, A.graphicID, LINK_COLOR);
+ this.cmd("Connect", A.parent.graphicID, B.graphicID, LINK_COLOR)
+
+ if (A.isLeftChild())
+ {
+ A.parent.left = B;
+ }
+ else
+ {
+ A.parent.right = B;
+ }
+ }
+ B.left = A;
+ A.parent = B;
+ A.right = t2;
+ this.resetHeight(A);
+ this.resetHeight(B);
+
+ this.resizeTree();
+ return B;
+}
+
+
+
+
+RedBlack.prototype.getHeight = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ return tree.height;
+}
+
+RedBlack.prototype.resetHeight = function(tree)
+{
+ if (tree != null)
+ {
+ var newHeight = Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1;
+ if (tree.height != newHeight)
+ {
+ tree.height = Math.max(this.getHeight(tree.left), this.getHeight(tree.right)) + 1
+ }
+ }
+}
+
+RedBlack.prototype.insert = function(elem, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("SetHighlight", elem.graphicID, 1);
+
+ if (elem.data < tree.data)
+ {
+ this.cmd("SetText", 0, elem.data + " < " + tree.data + ", 访问左子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, elem.data + " >= " + tree.data + ", 访问右子树");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlight", elem.graphicID, 0);
+
+ if (elem.data < tree.data)
+ {
+ if (tree.left == null || tree.left.phantomLeaf)
+ {
+ this.cmd("SetText", 0, "Found null tree (or phantom leaf), inserting element");
+ if (tree.left != null)
+ {
+ this.cmd("Delete", tree.left.graphicID);
+ }
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.left=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, LINK_COLOR);
+
+ this.attachNullLeaves(elem);
+ this.resizeTree();
+
+
+
+
+ this.resizeTree();
+
+ this.fixDoubleRed(elem);
+
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.left);
+
+ }
+ }
+ else
+ {
+ if (tree.right == null || tree.right.phantomLeaf)
+ {
+ this.cmd("SetText", 0, "Found null tree (or phantom leaf), inserting element");
+ if (tree.right != null)
+ {
+ this.cmd("Delete", tree.right.graphicID);
+ }
+
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.right=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, LINK_COLOR);
+ elem.x = tree.x + widthDelta/2;
+ elem.y = tree.y + heightDelta
+ this.cmd("Move", elem.graphicID, elem.x, elem.y);
+
+
+ this.attachNullLeaves(elem);
+ this.resizeTree();
+
+
+ this.resizeTree();
+ this.fixDoubleRed(elem);
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.right);
+ }
+ }
+
+
+}
+
+
+RedBlack.prototype.fixDoubleRed = function(tree)
+{
+ if (tree.parent != null)
+ {
+ if (tree.parent.blackLevel > 0)
+ {
+ return;
+ }
+ if (tree.parent.parent == null)
+ {
+ this.cmd("SetText", 0, "Tree root is red, color it black.");
+ this.cmd("Step");
+ tree.parent.blackLevel = 1;
+ this.cmd("SetForegroundColor", tree.parent.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", tree.parent.graphicID, BACKGROUND_BLACK);
+ return;
+ }
+ var uncle = this.findUncle(tree);
+ if (this.blackLevel(uncle) == 0)
+ {
+ this.cmd("SetText", 0, "Node and parent are both red. Uncle of node is red -- push blackness down from grandparent");
+ this.cmd("Step");
+
+ this.cmd("SetForegroundColor", uncle.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor",uncle.graphicID, BACKGROUND_BLACK);
+ uncle.blackLevel = 1;
+
+ tree.parent.blackLevel = 1;
+ this.cmd("SetForegroundColor", tree.parent.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor",tree.parent.graphicID, BACKGROUND_BLACK);
+
+ tree.parent.parent.blackLevel = 0;
+ this.cmd("SetForegroundColor", tree.parent.parent.graphicID, FOREGROUND_RED);
+ this.cmd("SetBackgroundColor",tree.parent.parent.graphicID, BACKGROUND_RED);
+ this.cmd("Step");
+ this.fixDoubleRed(tree.parent.parent);
+ }
+ else
+ {
+ if (tree.isLeftChild() && !tree.parent.isLeftChild())
+ {
+ this.cmd("SetText", 0, "Node and parent are both red. Node is left child, parent is right child -- rotate");
+ this.cmd("Step");
+
+ this.singleRotateRight(tree.parent);
+ tree=tree.right;
+
+ }
+ else if (!tree.isLeftChild() && tree.parent.isLeftChild())
+ {
+ this.cmd("SetText", 0, "Node and parent are both red. Node is right child, parent is left child -- rotate");
+ this.cmd("Step");
+
+ this.singleRotateLeft(tree.parent);
+ tree=tree.left;
+ }
+
+ if (tree.isLeftChild())
+ {
+ this.cmd("SetText", 0, "Node and parent are both red. Node is left child, parent is left child\nCan fix extra redness with a single rotation");
+ this.cmd("Step");
+
+ this.singleRotateRight(tree.parent.parent);
+ tree.parent.blackLevel = 1;
+ this.cmd("SetForegroundColor", tree.parent.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor",tree.parent.graphicID, BACKGROUND_BLACK);
+
+ tree.parent.right.blackLevel = 0;
+ this.cmd("SetForegroundColor", tree.parent.right.graphicID, FOREGROUND_RED);
+ this.cmd("SetBackgroundColor",tree.parent.right.graphicID, BACKGROUND_RED);
+
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, "Node and parent are both red. Node is right child, parent is right child\nCan fix extra redness with a single rotation");
+ this.cmd("Step");
+
+ this.singleRotateLeft(tree.parent.parent);
+ tree.parent.blackLevel = 1;
+ this.cmd("SetForegroundColor", tree.parent.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor",tree.parent.graphicID, BACKGROUND_BLACK);
+
+ tree.parent.left.blackLevel = 0;
+ this.cmd("SetForegroundColor", tree.parent.left.graphicID, FOREGROUND_RED);
+ this.cmd("SetBackgroundColor",tree.parent.left.graphicID, BACKGROUND_RED);
+
+ }
+ }
+
+ }
+ else
+ {
+ if (tree.blackLevel == 0)
+ {
+ this.cmd("SetText", 0, "Root of the tree is red. Color it black");
+ this.cmd("Step");
+
+ tree.blackLevel = 1;
+ this.cmd("SetForegroundColor", tree.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", tree.graphicID, BACKGROUND_BLACK);
+ }
+ }
+
+}
+
+RedBlack.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在刪除 "+deletedValue);
+ this.cmd("Step");
+ this.cmd("SetText", 0, " ");
+ this.highlightID = this.nextIndex++;
+ this.treeDelete(this.treeRoot, deletedValue);
+ this.cmd("SetText", 0, " ");
+ // Do delete
+ return this.commands;
+}
+
+
+RedBlack.prototype.fixLeftNull = function(tree)
+{
+ var treeNodeID = this.nextIndex++;
+ var nullLeaf;
+ this.cmd("SetText", 0, "Coloring 'Null Leaf' double black");
+
+ this.cmd("CreateCircle", treeNodeID, "null", tree.x, tree.y);
+ this.cmd("SetForegroundColor", treeNodeID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", treeNodeID, BACKGROUND_DOUBLE_BLACK);
+ nullLeaf = new RedBlackNode("null", treeNodeID, tree.x, tree.x);
+ nullLeaf.blackLevel = 2;
+ nullLeaf.parent = tree;
+ nullLeaf.phantomLeaf = true;
+ tree.left = nullLeaf;
+ this.cmd("Connect", tree.graphicID, nullLeaf.graphicID, LINK_COLOR);
+
+ this.resizeTree();
+ this.fixExtraBlackChild(tree, true);
+ this.cmd("SetLayer", nullLeaf.graphicID, 1);
+ nullLeaf.blackLevel = 1;
+ this.fixNodeColor(nullLeaf);
+}
+
+
+RedBlack.prototype.fixRightNull = function(tree)
+{
+ var treeNodeID = this.nextIndex++;
+ var nullLeaf;
+ this.cmd("SetText", 0, "Coloring 'Null Leaf' double black");
+
+ this.cmd("CreateCircle", treeNodeID, "null", tree.x, tree.y);
+ this.cmd("SetForegroundColor", treeNodeID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", treeNodeID, BACKGROUND_DOUBLE_BLACK);
+ nullLeaf = new RedBlackNode("null", treeNodeID, tree.x, tree.x);
+ nullLeaf.parent = tree;
+ nullLeaf.phantomLeaf = true;
+ nullLeaf.blackLevel = 2;
+ tree.right = nullLeaf;
+ this.cmd("Connect", tree.graphicID, nullLeaf.graphicID, LINK_COLOR);
+
+ this.resizeTree();
+
+ this.fixExtraBlackChild(tree, false);
+
+ this.cmd("SetLayer", nullLeaf.graphicID, 1);
+ nullLeaf.blackLevel = 1;
+ this.fixNodeColor(nullLeaf);
+
+}
+
+
+RedBlack.prototype.fixExtraBlackChild = function(parNode, isLeftChild)
+{
+ var sibling;
+ var doubleBlackNode;
+ if (isLeftChild)
+ {
+ sibling = parNode.right;
+ doubleBlackNode = parNode.left;
+ }
+ else
+ {
+ sibling = parNode.left;
+ doubleBlackNode = parNode.right;
+ }
+ if (this.blackLevel(sibling) > 0 && this.blackLevel(sibling.left) > 0 && this.blackLevel(sibling.right) > 0)
+ {
+ this.cmd("SetText", 0, "Double black node has black sibling and 2 black nephews. Push up black level");
+ this.cmd("Step");
+ sibling.blackLevel = 0;
+ this.fixNodeColor(sibling);
+ if (doubleBlackNode != null)
+ {
+ doubleBlackNode.blackLevel = 1;
+ this.fixNodeColor(doubleBlackNode);
+
+ }
+ if (parNode.blackLevel == 0)
+ {
+ parNode.blackLevel = 1;
+ this.fixNodeColor(parNode);
+ }
+ else
+ {
+ parNode.blackLevel = 2;
+ this.fixNodeColor(parNode);
+ this.cmd("SetText", 0, "Pushing up black level created another double black node. Repeating ...");
+ this.cmd("Step");
+ this.fixExtraBlack(parNode);
+ }
+ }
+ else if (this.blackLevel(sibling) == 0)
+ {
+ this.cmd("SetText", 0, "Double black node has red sibling. Rotate tree to make sibling black ...");
+ this.cmd("Step");
+ if (isLeftChild)
+ {
+ var newPar = this.singleRotateLeft(parNode);
+ newPar.blackLevel = 1;
+ this.fixNodeColor(newPar);
+ newPar.left.blackLevel = 0;
+ this.fixNodeColor(newPar.left);
+ this.cmd("Step"); // TODO: REMOVE
+ this.fixExtraBlack(newPar.left.left);
+
+ }
+ else
+ {
+ newPar = this.singleRotateRight(parNode);
+ newPar.blackLevel = 1;
+ this.fixNodeColor(newPar);
+ newPar.right.blackLevel = 0;
+ this.fixNodeColor(newPar.right);
+ this.cmd("Step"); // TODO: REMOVE
+
+ this.fixExtraBlack(newPar.right.right);
+ }
+ }
+ else if (isLeftChild && this.blackLevel(sibling.right) > 0)
+ {
+ this.cmd("SetText", 0, "Double black node has black sibling, but double black node is a left child, \nand the right nephew is black. Rotate tree to make opposite nephew red ...");
+ this.cmd("Step");
+
+ var newSib = this.singleRotateRight(sibling);
+ newSib.blackLevel = 1;
+ this.fixNodeColor(newSib);
+ newSib.right.blackLevel = 0;
+ this.fixNodeColor(newSib.right);
+ this.cmd("Step");
+ this.fixExtraBlackChild(parNode, isLeftChild);
+ }
+ else if (!isLeftChild && this.blackLevel(sibling.left) > 0)
+ {
+ this.cmd("SetText", 0, "Double black node has black sibling, but double black node is a right child, \nand the left nephew is black. Rotate tree to make opposite nephew red ...");
+ this.cmd("Step");
+ newSib = this.singleRotateLeft(sibling);
+ newSib.blackLevel = 1;
+ this.fixNodeColor(newSib);
+ newSib.left.blackLevel = 0;
+ this.fixNodeColor(newSib.left);
+ this.cmd("Step");
+ this.fixExtraBlackChild(parNode, isLeftChild);
+ }
+ else if (isLeftChild)
+ {
+ this.cmd("SetText", 0, "Double black node has black sibling, is a left child, and its right nephew is red.\nOne rotation can fix double-blackness.");
+ this.cmd("Step");
+
+ var oldParBlackLevel = parNode.blackLevel;
+ newPar = this.singleRotateLeft(parNode);
+ if (oldParBlackLevel == 0)
+ {
+ newPar.blackLevel = 0;
+ this.fixNodeColor(newPar);
+ newPar.left.blackLevel = 1;
+ this.fixNodeColor(newPar.left);
+ }
+ newPar.right.blackLevel = 1;
+ this.fixNodeColor(newPar.right);
+ if (newPar.left.left != null)
+ {
+ newPar.left.left.blackLevel = 1;
+ this.fixNodeColor(newPar.left.left);
+ }
+ }
+ else
+ {
+ this.cmd("SetText", 0, "Double black node has black sibling, is a right child, and its left nephew is red.\nOne rotation can fix double-blackness.");
+ this.cmd("Step");
+
+ oldParBlackLevel = parNode.blackLevel;
+ newPar = this.singleRotateRight(parNode);
+ if (oldParBlackLevel == 0)
+ {
+ newPar.blackLevel = 0;
+ this.fixNodeColor(newPar);
+ newPar.right.blackLevel = 1;
+ this.fixNodeColor(newPar.right);
+ }
+ newPar.left.blackLevel = 1;
+ this.fixNodeColor(newPar.left);
+ if (newPar.right.right != null)
+ {
+ newPar.right.right.blackLevel = 1;
+ this.fixNodeColor(newPar.right.right);
+ }
+ }
+}
+
+
+RedBlack.prototype.fixExtraBlack = function(tree)
+{
+ if (tree.blackLevel > 1)
+ {
+ if (tree.parent == null)
+ {
+ this.cmd("SetText", 0, "Double black node is root. Make it single black.");
+ this.cmd("Step");
+
+ tree.blackLevel = 1;
+ this.cmd("SetBackgroundColor", tree.graphicID, BACKGROUND_BLACK);
+ }
+ else if (tree.parent.left == tree)
+ {
+ this.fixExtraBlackChild(tree.parent, true);
+ }
+ else
+ {
+ this.fixExtraBlackChild(tree.parent, false);
+ }
+
+ }
+ else
+ {
+ // No extra blackness
+ }
+}
+
+
+
+RedBlack.prototype.treeDelete = function(tree, valueToDelete)
+{
+ var leftchild = false;
+ if (tree != null && !tree.phantomLeaf)
+ {
+ if (tree.parent != null)
+ {
+ leftchild = tree.parent.left == tree;
+ }
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (valueToDelete < tree.data)
+ {
+ this.cmd("SetText", 0, valueToDelete + " < " + tree.data + ", 访问左子树");
+ }
+ else if (valueToDelete > tree.data)
+ {
+ this.cmd("SetText", 0, valueToDelete + " > " + tree.data + ", 访问右子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, valueToDelete + " == " + tree.data + ". Found node to delete");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+
+ if (valueToDelete == tree.data)
+ {
+ var needFix = tree.blackLevel > 0;
+ if (((tree.left == null) || tree.left.phantomLeaf) && ((tree.right == null) || tree.right.phantomLeaf))
+ {
+ this.cmd("SetText", 0, "需要删除的是叶子节点,直接删除!");
+ this.cmd("Delete", tree.graphicID);
+
+ if (tree.left != null)
+ {
+ this.cmd("Delete", tree.left.graphicID);
+ }
+ if (tree.right != null)
+ {
+ this.cmd("Delete", tree.right.graphicID);
+ }
+
+
+ if (leftchild && tree.parent != null)
+ {
+ tree.parent.left = null;
+ this.resizeTree();
+
+ if (needFix)
+ {
+ this.fixLeftNull(tree.parent);
+ }
+ else
+ {
+
+ this.attachLeftNullLeaf(tree.parent);
+ this.resizeTree();
+ }
+ }
+ else if (tree.parent != null)
+ {
+ tree.parent.right = null;
+ this.resizeTree();
+ if (needFix)
+ {
+ this.fixRightNull(tree.parent);
+ }
+ else
+ {
+ this.attachRightNullLeaf(tree.parent);
+ this.resizeTree();
+ }
+ }
+ else
+ {
+ this.treeRoot = null;
+ }
+
+ }
+ else if (tree.left == null || tree.left.phantomLeaf)
+ {
+ this.cmd("SetText", 0, "需要删除的节点没有左子树. \nSet parent of deleted node to right child of deleted node.");
+ if (tree.left != null)
+ {
+ this.cmd("Delete", tree.left.graphicID);
+ tree.left = null;
+ }
+
+ if (tree.parent != null)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, tree.right.graphicID, LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ if (leftchild)
+ {
+ tree.parent.left = tree.right;
+ if (needFix)
+ {
+ this.cmd("SetText", 0, "Back node removed. Increasing child's blackness level");
+ tree.parent.left.blackLevel++;
+ this.fixNodeColor(tree.parent.left);
+ this.fixExtraBlack(tree.parent.left);
+ }
+ }
+ else
+ {
+ tree.parent.right = tree.right;
+ if (needFix)
+ {
+ tree.parent.right.blackLevel++;
+ this.cmd("SetText", 0, "Back node removed. Increasing child's blackness level");
+ this.fixNodeColor(tree.parent.right);
+ this.fixExtraBlack(tree.parent.right);
+ }
+
+ }
+ tree.right.parent = tree.parent;
+ }
+ else
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.treeRoot = tree.right;
+ this.treeRoot.parent = null;
+ if (this.treeRoot.blackLevel == 0)
+ {
+ this.treeRoot.blackLevel = 1;
+ this.cmd("SetForegroundColor", this.treeRoot.graphicID, FOREGROUND_BLACK);
+ this.cmd("SetBackgroundColor", this.treeRoot.graphicID, BACKGROUND_BLACK);
+ }
+ }
+ this.resizeTree();
+ }
+ else if (tree.right == null || tree.right.phantomLeaf)
+ {
+ this.cmd("SetText", 0,"需要删除的节点没有右子树. \nSet parent of deleted node to left child of deleted node.");
+ if (tree.right != null)
+ {
+ this.cmd("Delete", tree.right.graphicID);
+ tree.right = null;
+ }
+ if (tree.parent != null)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, tree.left.graphicID, LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ if (leftchild)
+ {
+ tree.parent.left = tree.left;
+ if (needFix)
+ {
+ tree.parent.left.blackLevel++;
+ this.fixNodeColor(tree.parent.left);
+ this.fixExtraBlack(tree.parent.left);
+ this.resizeTree();
+ }
+ else
+ {
+ this.cmd("SetText", 0, "删除的是红色节点. 不需要旋转.");
+ this.resizeTree();
+
+ }
+ }
+ else
+ {
+ tree.parent.right = tree.left;
+ if (needFix)
+ {
+ tree.parent.right.blackLevel++;
+ this.fixNodeColor(tree.parent.right);
+ this.fixExtraBlack(tree.parent.left);
+ this.resizeTree();
+ }
+ else
+ {
+ this.cmd("SetText", 0, "删除的是红色节点. 不需要旋转.");
+ this.resizeTree();
+ }
+ }
+ tree.left.parent = tree.parent;
+ }
+ else
+ {
+ this.cmd("Delete" , tree.graphicID);
+ this.treeRoot = tree.left;
+ this.treeRoot.parent = null;
+ if (this.treeRoot.blackLevel == 0)
+ {
+ this.treeRoot.blackLevel = 1;
+ this.fixNodeColor(this.treeRoot);
+ }
+ }
+ }
+ else // tree.left != null && tree.right != null
+ {
+ this.cmd("SetText", 0, "需要删除的节点有2棵子树. \n找到左子树中最大的节点.");
+
+ this.highlightID = this.nextIndex;
+ this.nextIndex += 1;
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ var tmp = tree;
+ tmp = tree.left;
+ this.cmd("Move", this.highlightID, tmp.x, tmp.y);
+ this.cmd("Step");
+ while (tmp.right != null && !tmp.right.phantomLeaf)
+ {
+ tmp = tmp.right;
+ this.cmd("Move", this.highlightID, tmp.x, tmp.y);
+ this.cmd("Step");
+ }
+ if (tmp.right != null)
+ {
+ this.cmd("Delete", tmp.right.graphicID);
+ tmp.right = null;
+ }
+ this.cmd("SetText", tree.graphicID, " ");
+ var labelID = this.nextIndex;
+ this.nextIndex += 1;
+ this.cmd("CreateLabel", labelID, tmp.data, tmp.x, tmp.y);
+ this.cmd("SetForegroundColor", labelID, BLUE);
+ tree.data = tmp.data;
+ this.cmd("Move", labelID, tree.x, tree.y);
+ this.cmd("SetText", 0, "Copy largest value of left subtree into node to delete.");
+
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("Delete", labelID);
+ this.cmd("SetText", tree.graphicID, tree.data);
+ this.cmd("Delete", this.highlightID);
+ this.cmd("SetText", 0, "Remove node whose value we copied.");
+
+ needFix = tmp.blackLevel > 0;
+
+
+ if (tmp.left == null)
+ {
+ this.cmd("Delete", tmp.graphicID);
+ if (tmp.parent != tree)
+ {
+ tmp.parent.right = null;
+ this.resizeTree();
+ if (needFix)
+ {
+ this.fixRightNull(tmp.parent);
+ }
+ else
+ {
+ this.cmd("SetText", 0, "删除的是红色节点. 不需要旋转.");
+ this.cmd("Step");
+ }
+ }
+ else
+ {
+ tree.left = null;
+ this.resizeTree();
+ if (needFix)
+ {
+ this.fixLeftNull(tmp.parent);
+ }
+ else
+ {
+ this.cmd("SetText", 0, "删除的是红色节点. 不需要旋转.");
+ this.cmd("Step");
+ }
+ }
+ }
+ else
+ {
+ this.cmd("Disconnect", tmp.parent.graphicID, tmp.graphicID);
+ this.cmd("Connect", tmp.parent.graphicID, tmp.left.graphicID, LINK_COLOR);
+ this.cmd("Step");
+ this.cmd("Delete", tmp.graphicID);
+
+ if (tmp.parent != tree)
+ {
+ tmp.parent.right = tmp.left;
+ tmp.left.parent = tmp.parent;
+ this.resizeTree();
+
+ if (needFix)
+ {
+ this.cmd("SetText", 0, "Coloring child of deleted node black");
+ this.cmd("Step");
+ tmp.left.blackLevel++;
+ if (tmp.left.phantomLeaf)
+ {
+ this.cmd("SetLayer", tmp.left.graphicID, 0);
+ }
+ this.fixNodeColor(tmp.left);
+ this.fixExtraBlack(tmp.left);
+ if (tmp.left.phantomLeaf)
+ {
+ this.cmd("SetLayer", tmp.left.graphicID, 1);
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, "删除的是红色节点. 不需要旋转.");
+ this.cmd("Step");
+ }
+ }
+ else
+ {
+ tree.left = tmp.left;
+ tmp.left.parent = tree;
+ this.resizeTree();
+ if (needFix)
+ {
+ this.cmd("SetText", 0, "Coloring child of deleted node black");
+ this.cmd("Step");
+ tmp.left.blackLevel++;
+ if (tmp.left.phantomLeaf)
+ {
+ this.cmd("SetLayer", tmp.left.graphicID, 0);
+ }
+
+ this.fixNodeColor(tmp.left);
+ this.fixExtraBlack(tmp.left);
+ if (tmp.left.phantomLeaf)
+ {
+ this.cmd("SetLayer", tmp.left.graphicID, 1);
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, "删除的是红色节点. 不需要旋转.");
+ this.cmd("Step");
+ }
+ }
+ }
+ tmp = tmp.parent;
+
+ }
+ }
+ else if (valueToDelete < tree.data)
+ {
+ if (tree.left != null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.treeDelete(tree.left, valueToDelete);
+ }
+ else
+ {
+ if (tree.right != null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, HIGHLIGHT_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ }
+ this.treeDelete(tree.right, valueToDelete);
+ }
+ }
+ else
+ {
+ this.cmd("SetText", 0, "元素 "+valueToDelete+" 未找到, 无法删除");
+ }
+
+}
+
+
+RedBlack.prototype.fixNodeColor = function(tree)
+{
+ if (tree.blackLevel == 0)
+ {
+ this.cmd("SetForegroundColor", tree.graphicID, FOREGROUND_RED);
+ this.cmd("SetBackgroundColor", tree.graphicID, BACKGROUND_RED);
+ }
+ else
+ {
+ this.cmd("SetForegroundColor", tree.graphicID, FOREGROUND_BLACK);
+ if (tree.blackLevel > 1)
+ {
+ this.cmd("SetBackgroundColor",tree.graphicID, BACKGROUND_DOUBLE_BLACK);
+ }
+ else
+ {
+ this.cmd("SetBackgroundColor",tree.graphicID, BACKGROUND_BLACK);
+ }
+ }
+}
+
+
+
+
+RedBlack.prototype.resizeTree = function()
+{
+ var startingPoint = this.startingX;
+ this.resizeWidths(this.treeRoot);
+ if (this.treeRoot != null)
+ {
+ if (this.treeRoot.leftWidth > startingPoint)
+ {
+ startingPoint = this.treeRoot.leftWidth;
+ }
+ else if (this.treeRoot.rightWidth > startingPoint)
+ {
+ startingPoint = Math.max(this.treeRoot.leftWidth, 2 * startingPoint - this.treeRoot.rightWidth);
+ }
+ this.setNewPositions(this.treeRoot, startingPoint, startingY, 0);
+ this.animateNewPositions(this.treeRoot);
+ this.cmd("Step");
+ }
+
+}
+
+RedBlack.prototype.setNewPositions = function(tree, xPosition, yPosition, side)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ if (side == -1)
+ {
+ xPosition = xPosition - tree.rightWidth;
+ tree.heightLabelX = xPosition - 20;
+ }
+ else if (side == 1)
+ {
+ xPosition = xPosition + tree.leftWidth;
+ tree.heightLabelX = xPosition + 20;
+ }
+ else
+ {
+ tree.heightLabelX = xPosition - 20;
+ }
+ tree.x = xPosition;
+ tree.heightLabelY = tree.y - 20;
+ this.setNewPositions(tree.left, xPosition, yPosition + heightDelta, -1)
+ this.setNewPositions(tree.right, xPosition, yPosition + heightDelta, 1)
+ }
+
+}
+RedBlack.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.animateNewPositions(tree.left);
+ this.animateNewPositions(tree.right);
+ }
+}
+
+RedBlack.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = Math.max(this.resizeWidths(tree.left), widthDelta / 2);
+ tree.rightWidth = Math.max(this.resizeWidths(tree.right), widthDelta / 2);
+ return tree.leftWidth + tree.rightWidth;
+}
+
+
+RedBlack.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+RedBlack.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+/////////////////////////////////////////////////////////
+// Red black node
+////////////////////////////////////////////////////////
+
+
+function RedBlackNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.blackLevel = 0;
+ this.phantomLeaf = false;
+ this.graphicID = id;
+ this.left = null;
+ this.right = null;
+ this.parent = null;
+ this.height = 0;
+ this.leftWidth = 0;
+ this.rightWidth = 0;
+}
+
+RedBlackNode.prototype.isLeftChild = function()
+{
+ if (this.parent == null)
+ {
+ return true;
+ }
+ return this.parent.left == this;
+}
+
+
+
+/////////////////////////////////////////////////////////
+// Setup stuff
+////////////////////////////////////////////////////////
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new RedBlack(animManag, canvas.width, canvas.height);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateScale2D.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateScale2D.js
new file mode 100644
index 0000000..595c5ac
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateScale2D.js
@@ -0,0 +1,996 @@
+// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, areobjectVertexLocalPosition
+// 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
+
+
+
+function RotateScale2D(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+RotateScale2D.prototype = new Algorithm();
+RotateScale2D.prototype.constructor = RotateScale2D;
+RotateScale2D.superclass = Algorithm.prototype;
+
+RotateScale2D.XAxisYPos = 300;
+RotateScale2D.XAxisStart = 100;
+RotateScale2D.XAxisEnd = 700;
+
+
+RotateScale2D.MATRIX_START_X = 10;
+RotateScale2D.MATRIX_START_Y = 10;
+RotateScale2D.MATRIX_MULTIPLY_SPACING = 10;
+RotateScale2D.EQUALS_SPACING = 30;
+
+
+
+RotateScale2D.YAxisXPos = 400;
+RotateScale2D.YAxisStart = 100;
+RotateScale2D.YAxisEnd = 500;
+
+RotateScale2D.MATRIX_ELEM_WIDTH = 50;
+RotateScale2D.MATRIX_ELEM_HEIGHT = 20;
+
+RotateScale2D.OBJECTS = [
+ [[100, 100], [-100, 100], [-100,-100], [100, -100]], // Square
+ [[10, 100], [-10, 100], [-10,-100], [100, -100], [100, -80], [10,-80]], // L
+ [[0, 141], [-134, 44], [-83, -114 ], [83, -114], [134,44]], // Pentagon
+ [[0, 141], [-35,48],[-134, 44], [-57, -19], [-83, -114 ], [0, -60],[83,-114], [57, -19], [134,44], [35, 48]], // Star
+ ]
+
+
+RotateScale2D.AXIS_COLOR = "#0000FF"
+RotateScale2D.VERTEX_FOREGORUND_COLOR = "#000000";
+RotateScale2D.VERTEX_BACKGROUND_COLOR = RotateScale2D.VERTEX_FOREGORUND_COLOR;
+RotateScale2D.EDGE_COLOR = "#000000";
+
+
+
+RotateScale2D.TRANSFORMED_VERTEX_FOREGORUND_COLOR = "#66FF66";
+RotateScale2D.TRANSFORMED_VERTEX_BACKGROUND_COLOR = RotateScale2D.VERTEX_FOREGORUND_COLOR;
+RotateScale2D.TRANSFORMED_EDGE_COLOR = "#66FF66";
+
+
+
+
+RotateScale2D.VECTOR_COLOR = "#FF0000";
+
+RotateScale2D.VERTEX_WIDTH = 3;
+RotateScale2D.VERTEX_HEIGHT = RotateScale2D.VERTEX_WIDTH;
+
+RotateScale2D.prototype.init = function(am, w, h)
+{
+ var sc = RotateScale2D.superclass.init.call(this, am, w, h);
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.addControls();
+ this.currentShape = 0;
+
+ this.commands = [];
+ this.nextIndex = 0;
+
+ this.setupAxis();
+
+ this.savedNextIndex = this.nextIndex;
+ this.setupObject();
+ this.setupObjectGraphic();
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.clearHistory();
+
+
+}
+
+RotateScale2D.prototype.setupAxis = function()
+{
+ this.xAxisLeft = this.nextIndex++;
+ this.xAxisRight = this.nextIndex++;
+ this.yAxisTop = this.nextIndex++;
+ this.yAxisBottom = this.nextIndex++;
+
+ this.xAxisLabel = this.nextIndex++;
+ this.yAxisLabel = this.nextIndex++;
+
+ this.originID = this.nextIndex++;
+
+ this.cmd("CreateRectangle", this.originID, "", 0, 0, RotateScale2D.YAxisXPos, RotateScale2D.XAxisYPos);
+
+
+ this.cmd("CreateRectangle", this.xAxisLeft, "", 0, 0, RotateScale2D.XAxisStart, RotateScale2D.XAxisYPos);
+ this.cmd("SetAlpha", this.xAxisLeft, 0);
+ this.cmd("CreateRectangle", this.xAxisRight, "", 0, 0, RotateScale2D.XAxisEnd, RotateScale2D.XAxisYPos);
+ this.cmd("SetAlpha", this.xAxisRight, 0);
+ this.cmd("Connect", this.xAxisLeft, this.xAxisRight, RotateScale2D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.xAxisRight, this.xAxisLeft, RotateScale2D.AXIS_COLOR, 0, 1, "");
+
+
+ this.cmd("CreateRectangle", this.yAxisTop, "", 0, 0, RotateScale2D.YAxisXPos, RotateScale2D.YAxisStart);
+ this.cmd("SetAlpha", this.yAxisTop, 0);
+ this.cmd("CreateRectangle", this.yAxisBottom, "", 0, 0, RotateScale2D.YAxisXPos, RotateScale2D.YAxisEnd);
+ this.cmd("SetAlpha", this.yAxisBottom, 0);
+ this.cmd("Connect", this.yAxisTop, this.yAxisBottom, RotateScale2D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.yAxisBottom, this.yAxisTop, RotateScale2D.AXIS_COLOR, 0, 1, "");
+ if (this.posYUp)
+ {
+ this.cmd("CreateLabel", this.yAxisLabel, "+y", RotateScale2D.YAxisXPos + 10, RotateScale2D.YAxisStart + 10);
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.yAxisLabel, "+y", RotateScale2D.YAxisXPos + 10, RotateScale2D.YAxisEnd - 10);
+ }
+ this.cmd("CreateLabel", this.xAxisLabel, "+x", RotateScale2D.XAxisEnd - 10, RotateScale2D.XAxisYPos - 10);
+ this.cmd("SetForegroundColor", this.yAxisLabel, RotateScale2D.AXIS_COLOR);
+ this.cmd("SetForegroundColor", this.xAxisLabel, RotateScale2D.AXIS_COLOR);
+}
+
+
+RotateScale2D.prototype.setupObject = function()
+{
+ this.objectVertexPosition = RotateScale2D.OBJECTS[this.currentShape].slice(0);
+}
+
+
+RotateScale2D.prototype.worldToScreenSpace = function(point)
+{
+ var transformedPoint = new Array(2);
+ transformedPoint[0] = point[0] + RotateScale2D.YAxisXPos;
+ if (this.posYUp)
+ {
+ transformedPoint[1] = RotateScale2D.XAxisYPos - point[1];
+ }
+ else
+ {
+ transformedPoint[1] = RotateScale2D.XAxisYPos + point[1];
+
+ }
+ return transformedPoint;
+}
+
+
+
+RotateScale2D.prototype.moveObjectToNewPosition = function()
+{
+ var i;
+ for (i = 0; i < this.objectVertexID.length; i++)
+ {
+ var point = this.worldToScreenSpace(this.objectVertexPosition[i]);
+ this.cmd("Move", this.objectVertexID[i], point[0], point[1]);
+ }
+
+}
+
+
+RotateScale2D.prototype.setupObjectGraphic = function()
+{
+ this.objectVertexID = new Array(this.objectVertexPosition.length);
+ var i;
+ for (i = 0; i < this.objectVertexPosition.length; i++)
+ {
+ this.objectVertexID[i] = this.nextIndex++;
+ var point = this.worldToScreenSpace(this.objectVertexPosition[i]);
+
+ this.cmd("CreateRectangle", this.objectVertexID[i], "", RotateScale2D.VERTEX_WIDTH, RotateScale2D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", this.objectVertexID[i], RotateScale2D.VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", this.objectVertexID[i], RotateScale2D.VERTEX_BACKGROUND_COLOR);
+ }
+ for (i = 1; i < this.objectVertexID.length; i++)
+ {
+ this.cmd("Connect", this.objectVertexID[i-1], this.objectVertexID[i], RotateScale2D.EDGE_COLOR, 0, 0, "");
+ }
+ this.cmd("Connect", this.objectVertexID[this.objectVertexID.length - 1], this.objectVertexID[0], RotateScale2D.EDGE_COLOR, 0, 0, "");
+}
+
+RotateScale2D.prototype.addControls = function()
+{
+ this.controls = [];
+
+ addLabelToAlgorithmBar("Rotation Angle");
+
+ this.rotationField = addControlToAlgorithmBar("Text", "");
+ this.rotationField.onkeydown = this.returnSubmitFloat(this.rotationField, this.transformCallback.bind(this), 4, true);
+ this.controls.push(this.rotationField);
+
+ addLabelToAlgorithmBar("Scale X");
+
+ this.scaleXField = addControlToAlgorithmBar("Text", "");
+ this.scaleXField.onkeydown = this.returnSubmitFloat(this.scaleXField, this.transformCallback.bind(this), 4, true);
+ this.controls.push(this.scaleXField);
+
+
+ addLabelToAlgorithmBar("Scale Y");
+
+ this.scaleYField = addControlToAlgorithmBar("Text", "");
+ this.scaleYField.onkeydown = this.returnSubmitFloat(this.scaleYField, this.transformCallback.bind(this), 4, true);
+ this.controls.push(this.scaleYField);
+
+
+ var transformButton = addControlToAlgorithmBar("Button", "Transform");
+ transformButton.onclick = this.transformCallback.bind(this);
+
+ this.controls.push(transformButton);
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Row Major",
+ "Column Major",
+ ],
+ "RankType");
+ this.rowMajorButton = radioButtonList[0];
+ this.rowMajorButton.onclick = this.changeRowColMajorCallback.bind(this, true);
+ this.controls.push(this.rowMajorButton);
+
+ this.colMajorButton = radioButtonList[1];
+ this.colMajorButton.onclick = this.changeRowColMajorCallback.bind(this, false);
+ this.controls.push(this.colMajorButton);
+
+ this.rowMajorButton.checked = this.rowMajor;
+ this.colMajorButton.checked = !this.rowMajor;
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["+y Up",
+ "+y Down",
+ ],
+ "yAxisDirection");
+ this.posYUpButton = radioButtonList[0];
+ this.posYUpButton.onclick = this.changePosYCallback.bind(this, true);
+ this.controls.push(this.posYUpButton);
+
+ this.posYDownButton = radioButtonList[1];
+ this.posYDownButton.onclick = this.changePosYCallback.bind(this, false);
+ this.controls.push(this.posYDownButton);
+
+ this.posYUpButton.checked = this.posYUp;
+ this.posYDownButton.checked = !this.posYUp;
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Rotate, then scale",
+ "Scale, then rotate",
+ ],
+ "RotateFirst");
+ this.rotateScaleButton = radioButtonList[0];
+ this.rotateScaleButton.onclick = this.rotateScaleOrderCallback.bind(this, true);
+ this.controls.push(this.rotateScaleButton);
+
+ this.scaleRotateButton = radioButtonList[1];
+ this.scaleRotateButton.onclick = this.rotateScaleOrderCallback.bind(this, false);
+ this.controls.push(this.scaleRotateButton);
+
+ this.rotateScaleButton.checked = this.rotateFirst;
+ this.scaleRotateButton.checked = !this.rotateFirst;
+
+ var changeShapeButton = addControlToAlgorithmBar("Button", "Change Shape");
+ changeShapeButton.onclick = this.changeShapeCallback.bind(this);
+
+ this.controls.push(changeShapeButton);
+
+}
+
+
+
+
+
+
+RotateScale2D.prototype.reset = function()
+{
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.currentShape = 0;
+ this.rowMajorButton.checked = this.rowMajor;
+ this.posYUpButton.checked = this.posYUp;
+ this.rotateScaleButton.checked = this.rotateFirst;
+
+ this.nextIndex = this.savedNextIndex;
+ this.setupObject();
+ this.setupObjectGraphic();
+}
+
+
+RotateScale2D.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+RotateScale2D.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+RotateScale2D.prototype.changePosYCallback = function(posYUp)
+{
+ if (this.posYUp != posYUp)
+ {
+ this.implementAction(this.changePosY.bind(this), posYUp);
+ }
+}
+
+RotateScale2D.prototype.changePosY = function(posYUp)
+{
+ this.commands = new Array();
+ this.posYUp= posYUp;
+ if (this.posYUpButton.checked != this.posYUp)
+ {
+ this.posYUpButton.checked = this.posYUp;
+ }
+ if (this.posYDownButton.checked == this.posYUp)
+ {
+ this.posYDownButton.checked = !this.posYUp;
+ }
+ if (this.posYUp)
+ {
+ this.cmd("Move", this.yAxisLabel, RotateScale2D.YAxisXPos + 10, RotateScale2D.YAxisStart + 10);
+ }
+ else
+ {
+ this.cmd("Move", this.yAxisLabel, RotateScale2D.YAxisXPos + 10, RotateScale2D.YAxisEnd - 10);
+
+ }
+
+ this.moveObjectToNewPosition();
+
+
+
+
+ // Move +y on axis up/down
+ return this.commands;
+}
+
+
+
+RotateScale2D.prototype.changeRowColMajorCallback = function(rowMajor)
+{
+ if (this.rowMajor != rowMajor)
+ {
+ this.implementAction(this.changeRowCol.bind(this), rowMajor);
+ }
+}
+
+RotateScale2D.prototype.changeRowCol = function(rowMajor)
+{
+ this.commands = new Array();
+ this.rowMajor= rowMajor;
+ if (this.rowMajorButton.checked != this.rowMajor)
+ {
+ this.rowMajorButton.checked = this.rowMajor;
+ }
+ if (this.colMajorButton.checked == this.rowMajor)
+ {
+ this.colMajorButton.checked = !this.rowMajor;
+ }
+ return this.commands;
+}
+
+
+RotateScale2D.prototype.fixNumber = function(value, defaultVal)
+{
+ if (value == "" || value == "-" || value == "." || value == "-." || isNaN(parseFloat(value)))
+ {
+ value = defaultVal;
+ }
+ else
+ {
+ value = String(parseFloat(value));
+ }
+ return value
+}
+
+RotateScale2D.prototype.transformCallback = function()
+{
+
+
+ this.rotationField.value = this.fixNumber(this.rotationField.value, "0");
+ this.scaleXField.value = this.fixNumber(this.scaleXField.value, "1");
+ this.scaleYField.value = this.fixNumber(this.scaleYField.value, "1");
+ this.implementAction(this.transform.bind(this), this.rotationField.value + ";" + this.scaleXField.value + ";" + this.scaleYField.value);
+
+}
+
+
+RotateScale2D.prototype.changeShapeCallback = function()
+{
+ this.implementAction(this.changeShape.bind(this), 0);
+}
+
+RotateScale2D.prototype.changeShape = function()
+{
+ this.commands = [];
+ var i;
+ for (i = 0; i < this.objectVertexID.length; i++)
+ {
+ this.cmd("Delete", this.objectVertexID[i]);
+ }
+ this.currentShape++;
+ if (this.currentShape >= RotateScale2D.OBJECTS.length)
+ {
+ this.currentShape = 0;
+ }
+ this.setupObject();
+ this.setupObjectGraphic();
+ return this.commands;
+}
+
+RotateScale2D.prototype.rotateScaleOrderCallback = function(rotateFirst)
+{
+ if (this.rotateFirst != rotateFirst)
+ {
+ this.implementAction(this.rotateScaleOrder.bind(this), rotateFirst);
+ }
+}
+
+
+RotateScale2D.prototype.rotateScaleOrder = function(rotateFirst)
+{
+ this.commands = new Array();
+ this.rotateFirst= rotateFirst;
+ if (this.rotateScaleButton.checked != this.rotateFirst)
+ {
+ this.rotateScaleButton.checked = this.rotateFirst;
+ }
+ if (this.scaleRotateButton.checked == this.rotateFirst)
+ {
+ this.scaleRotateButton.checked = !this.rotateFirst;
+ }
+ return this.commands;
+}
+
+
+function toRadians(degrees)
+{
+ return (degrees * 2 * Math.PI) / 360.0;
+}
+
+RotateScale2D.prototype.transform = function(input)
+{
+ var oldNextIndex = this.nextIndex;
+ this.commands = [];
+ var inputs = input.split(";");
+ var rotateDegree = toRadians(parseFloat(inputs[0]));
+ var scaleX = parseFloat(inputs[1]);
+ var scaleY = parseFloat(inputs[2]);
+
+ var xpos = RotateScale2D.MATRIX_START_X;
+ var ypos = RotateScale2D.MATRIX_START_Y;
+ if (!this.rowMajor)
+ {
+ xpos += 2 * RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.EQUALS_SPACING;
+ }
+
+ var xy;
+ if (this.rowMajor)
+ {
+ xy = this.createMatrix([["x", "y"]], xpos, ypos);
+ xpos += xy.data[0].length * RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_MULTIPLY_SPACING;
+
+ }
+
+ var matrixData;
+ if (this.rotateFirst)
+ {
+ if (this.rowMajor)
+ {
+ matrixData = [["cos \u0398", "sin \u0398"], ["-sin \u0398", "cos \u0398"]]
+ }
+ else
+ {
+ matrixData = [["ScaleX", "0"], ["0", "ScaleY"]];
+ }
+
+ }
+ else
+ {
+ if (this.rowMajor)
+ {
+ matrixData = [["ScaleX", "0"], ["0", "ScaleY"]];
+ }
+ else
+ {
+ matrixData = [["cos \u0398", "-sin \u0398"], ["sin \u0398", "cos \u0398"]]
+
+ }
+ }
+
+
+ var firstMat = this.createMatrix(matrixData, xpos, ypos);
+
+ xpos += firstMat.data[0].length * RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_MULTIPLY_SPACING;
+
+
+ if (this.rotateFirst)
+ {
+ if (this.rowMajor)
+ {
+ matrixData = [["ScaleX", "0"], ["0", "ScaleY"]];
+ }
+ else
+ {
+ matrixData = [["cos \u0398", "-sin \u0398"], ["sin \u0398", "cos \u0398"]]
+
+ }
+ }
+ else
+ {
+ if (this.rowMajor)
+ {
+ matrixData = [["cos \u0398", "sin \u0398"], ["-sin \u0398", "cos \u0398"]]
+ }
+ else
+ {
+ matrixData = [["ScaleX", "0"], ["0", "ScaleY"]];
+ }
+ }
+
+ var secondMat = this.createMatrix(matrixData,xpos, ypos);
+ xpos += secondMat.data[0].length * RotateScale2D.MATRIX_ELEM_WIDTH;
+
+ if (!this.rowMajor)
+ {
+ xpos += RotateScale2D.MATRIX_MULTIPLY_SPACING;
+ xy = this.createMatrix([["x"], ["y"]], xpos, ypos);
+ xpos += xy.data[0].length * RotateScale2D.MATRIX_ELEM_WIDTH;
+ }
+
+ this.cmd("Step");
+
+ var rotMat, scaleMat
+ if ((this.rotateFirst && this.rowMajor) || (!this.rotateFirst && !this.rowMajor))
+ {
+ rotMat = firstMat;
+ scaleMat = secondMat;
+ }
+ else
+ {
+ rotMat = secondMat;
+ scaleMat = firstMat;
+
+ }
+
+ if (this.rowMajor)
+ {
+ rotMat.data = [["cos " + inputs[0], "sin " + inputs[0]],["-sin " +inputs[0], "cos " + inputs[0]]];
+ }
+ else
+ {
+ rotMat.data = [["cos " + inputs[0], "-sin " + inputs[0]],["sin " +inputs[0], "cos " + inputs[0]]];
+ }
+ this.resetMatrixLabels(rotMat);
+
+ scaleMat.data = [[scaleX, 0],[0, scaleY]];
+ this.resetMatrixLabels(scaleMat);
+
+ this.cmd("Step");
+
+ if (this.rowMajor)
+ {
+ rotMat.data = [[Math.cos(rotateDegree), Math.sin(rotateDegree)],[-Math.sin(rotateDegree), Math.cos(rotateDegree)]];
+ }
+ else
+ {
+ rotMat.data = [[Math.cos(rotateDegree), -Math.sin(rotateDegree)],[Math.sin(rotateDegree), Math.cos(rotateDegree)]];
+ }
+ this.resetMatrixLabels(rotMat);
+ this.cmd("Step");
+ this.setMatrixAlpha(xy, 0.3);
+
+
+ var equalID = this.nextIndex++;
+ var equaXlPos;
+ if (this.rowMajor)
+ {
+ equalXPos = xpos + RotateScale2D.EQUALS_SPACING / 2;
+ }
+ else
+ {
+ equalXPos = RotateScale2D.MATRIX_START_X + 2 * RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.EQUALS_SPACING / 2;
+ }
+
+ this.cmd("CreateLabel", equalID, "=", equalXPos, ypos + rotMat.data.length / 2 * RotateScale2D.MATRIX_ELEM_HEIGHT);
+
+ xpos += RotateScale2D.EQUALS_SPACING;
+
+
+ var paren1 = this.nextIndex++
+ var paren2 = this.nextIndex++
+ var paren3 = this.nextIndex++
+ var paren4 = this.nextIndex++
+
+ var parenX;
+ parenX = 2 * RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_START_X + RotateScale2D.MATRIX_MULTIPLY_SPACING - 2;
+ if (!this.rowMajor)
+ {
+ parenX += RotateScale2D.EQUALS_SPACING - RotateScale2D.MATRIX_MULTIPLY_SPACING;
+ }
+
+ this.cmd("CreateRectangle", paren1, "", 0, 0, parenX, RotateScale2D.MATRIX_START_Y, "center","center");
+ this.cmd("CreateRectangle", paren2, "", 0, 0, parenX, RotateScale2D.MATRIX_START_Y + 2*RotateScale2D.MATRIX_ELEM_HEIGHT, "center","center");
+ this.cmd("Connect", paren1, paren2, "#000000", 0.2, 0, "");
+
+ parenX = 6*RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_START_X + 2*RotateScale2D.MATRIX_MULTIPLY_SPACING + 2;
+ if (!this.rowMajor)
+ {
+ parenX += RotateScale2D.EQUALS_SPACING - RotateScale2D.MATRIX_MULTIPLY_SPACING;
+ }
+
+ this.cmd("CreateRectangle", paren3, "", 0, 0, parenX, RotateScale2D.MATRIX_START_Y, "center","center");
+ this.cmd("CreateRectangle", paren4, "", 0, 0, parenX, RotateScale2D.MATRIX_START_Y+ 2*RotateScale2D.MATRIX_ELEM_HEIGHT, "center","center");
+
+ this.cmd("Connect", paren3, paren4, "#000000", -0.2, 0 ,"");
+
+ this.cmd("Step");
+ var tmpMat;
+ if (this.rowMajor)
+ {
+ tmpMat = this.createMatrix([["",""],["",""]],xpos, ypos);
+ }
+ else
+ {
+ tmpMat = this.createMatrix([["",""],["",""]],RotateScale2D.MATRIX_START_X, RotateScale2D.MATRIX_START_Y);
+ }
+ var explainID = this.nextIndex++;
+ if (this.rowMajor)
+ {
+ this.cmd("CreateLabel", explainID, "", 6*RotateScale2D.MATRIX_ELEM_WIDTH + 2*RotateScale2D.MATRIX_MULTIPLY_SPACING +
+ RotateScale2D.EQUALS_SPACING + RotateScale2D.MATRIX_START_X, 20 + 2*RotateScale2D.MATRIX_ELEM_HEIGHT, 0);
+ }
+ else
+ {
+ this.cmd("CreateLabel", explainID, "", RotateScale2D.MATRIX_START_X, 20 + 2*RotateScale2D.MATRIX_ELEM_HEIGHT, 0);
+ }
+ this.cmd("Step");
+ this.multiplyMatrix(firstMat, secondMat, tmpMat, explainID);
+
+
+ this.deleteMatrix(firstMat);
+ this.deleteMatrix(secondMat);
+ this.cmd("Delete", paren1);
+ this.cmd("Delete", paren2);
+ this.cmd("Delete", paren3);
+ this.cmd("Delete", paren4);
+ this.cmd("Delete", equalID);
+
+ if (this.rowMajor)
+ {
+ this.moveMatrix(tmpMat, xy.data[0].length * RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_MULTIPLY_SPACING + RotateScale2D.MATRIX_START_X,
+ RotateScale2D.MATRIX_START_Y);
+ xpos = (RotateScale2D.MATRIX_START_X + xy.data[0].length*RotateScale2D.MATRIX_ELEM_WIDTH +
+ RotateScale2D.MATRIX_MULTIPLY_SPACING + tmpMat.data[0].length * RotateScale2D.MATRIX_ELEM_WIDTH);
+ this.cmd("SetPosition", explainID, 4*RotateScale2D.MATRIX_ELEM_WIDTH + 1*RotateScale2D.MATRIX_MULTIPLY_SPACING +
+ RotateScale2D.EQUALS_SPACING + RotateScale2D.MATRIX_START_X, 20 + 2*RotateScale2D.MATRIX_ELEM_HEIGHT, 0);
+
+ }
+ else
+ {
+ this.moveMatrix(tmpMat, RotateScale2D.MATRIX_START_X + 4*RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.EQUALS_SPACING + RotateScale2D.MATRIX_MULTIPLY_SPACING,
+ RotateScale2D.MATRIX_START_Y);
+ xpos = (RotateScale2D.MATRIX_START_X + 7*RotateScale2D.MATRIX_ELEM_WIDTH +
+ 2 * RotateScale2D.MATRIX_MULTIPLY_SPACING + RotateScale2D.EQUALS_SPACING);
+
+ this.cmd("SetPosition", explainID, 7*RotateScale2D.MATRIX_ELEM_WIDTH + 2 * RotateScale2D.EQUALS_SPACING + 3*RotateScale2D.MATRIX_MULTIPLY_SPACING, RotateScale2D.MATRIX_START_Y + 10 + 2*RotateScale2D.MATRIX_ELEM_HEIGHT);
+
+ }
+ this.setMatrixAlpha(xy, 1);
+ this.cmd("Step");
+
+
+ var i;
+ var output;
+
+
+ var transformedObjectID = new Array(this.objectVertexID.length);
+
+ for (i = 0; i < this.objectVertexID.length; i++)
+ {
+ this.cmd("Connect", this.originID, this.objectVertexID[i], RotateScale2D.VECTOR_COLOR, 0, 1, "");
+ if (this.rowMajor)
+ {
+ xy.data = [this.objectVertexPosition[i].slice(0)];
+ }
+ else
+ {
+ xy.data[0][0] = this.objectVertexPosition[i][0];
+ xy.data[1][0] = this.objectVertexPosition[i][1];
+ }
+ this.resetMatrixLabels(xy);
+ this.cmd("Step");
+ this.cmd("CreateLabel", equalID, "=", xpos + RotateScale2D.EQUALS_SPACING / 2, ypos + tmpMat.data.length / 2 * RotateScale2D.MATRIX_ELEM_HEIGHT);
+ if (this.rowMajor)
+ {
+ output = this.createMatrix([["",""]], xpos + RotateScale2D.EQUALS_SPACING, ypos)
+ this.multiplyMatrix(xy, tmpMat, output, explainID);
+ }
+ else
+ {
+ output = this.createMatrix([[""],[""]], xpos + RotateScale2D.EQUALS_SPACING, ypos)
+ this.multiplyMatrix(tmpMat, xy, output, explainID);
+ }
+
+
+ transformedObjectID[i] = this.nextIndex++;
+ var point;
+ if (this.rowMajor)
+ {
+ point = this.worldToScreenSpace(output.data[0]);
+ }
+ else
+ {
+ point = this.worldToScreenSpace([output.data[0][0], output.data[1][0]]);
+ }
+
+ this.cmd("CreateRectangle", transformedObjectID[i], "", RotateScale2D.VERTEX_WIDTH, RotateScale2D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", transformedObjectID[i], RotateScale2D.TRANSFORMED_VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", transformedObjectID[i], RotateScale2D.TRANSFORMED_VERTEX_BACKGROUND_COLOR);
+ this.cmd("Connect", this.originID, transformedObjectID[i], RotateScale2D.TRANSFORMED_EDGE_COLOR, 0, 1, "");
+ this.cmd("Step");
+ this.cmd("Disconnect", this.originID, transformedObjectID[i]);
+
+ if (i > 0)
+ {
+ this.cmd("Connect", transformedObjectID[i-1], transformedObjectID[i], RotateScale2D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+
+ }
+
+ this.cmd("Disconnect", this.originID, this.objectVertexID[i]);
+ if (this.rowMajor)
+ {
+ this.objectVertexPosition[i] = output.data[0];
+ }
+ else
+ {
+ this.objectVertexPosition[i][0] = output.data[0][0];
+ this.objectVertexPosition[i][1] = output.data[1][0];
+ }
+ this.cmd("Delete", equalID);
+ this.deleteMatrix(output);
+
+ }
+ this.cmd("Step");
+
+ this.cmd("Connect", transformedObjectID[0], transformedObjectID[transformedObjectID.length-1], RotateScale2D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+
+ this.cmd("Step","B");
+ this.moveObjectToNewPosition();
+ this.cmd("Step","C");
+
+ for (i = 0; i < transformedObjectID.length; i++)
+ {
+ this.cmd("Delete", transformedObjectID[i]);
+ }
+
+
+ this.deleteMatrix(xy);
+ this.deleteMatrix(tmpMat);
+ this.cmd("Delete", explainID);
+
+ this.nextIndex = oldNextIndex
+
+ return this.commands;
+}
+
+
+RotateScale2D.prototype.multiplyMatrix = function(mat1, mat2, mat3, explainID)
+{
+ var i;
+ var j;
+ var explainText = "";
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat2.data[0].length; j++)
+ {
+ var explainText = "";
+ var value = 0;
+ for (k = 0; k < mat2.data.length; k++)
+ {
+ this.cmd("SetHighlight", mat1.dataID[i][k], 1);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 1);
+ if (explainText != "")
+ {
+ explainText = explainText + " + ";
+ }
+ value = value + mat1.data[i][k] * mat2.data[k][j];
+ explainText = explainText + String(mat1.data[i][k]) + " * " + String(mat2.data[k][j]);
+ this.cmd("SetText", explainID, explainText);
+ this.cmd("Step");
+ this.cmd("SetHighlight", mat1.dataID[i][k], 0);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 0);
+ }
+ value = this.standardize(value);
+ explainText += " = " + String(value);
+ this.cmd("SetText", explainID, explainText);
+ mat3.data[i][j] = value;
+ this.cmd("SetText", mat3.dataID[i][j], value);
+ this.cmd("Step");
+ }
+ }
+ this.cmd("SetText", explainID, "");
+
+
+}
+
+RotateScale2D.prototype.standardize = function(lab)
+{
+ var newLab = Math.round(lab * 1000) / 1000;
+ if (isNaN(newLab))
+ {
+ return lab;
+ }
+ else
+ {
+ return newLab;
+ }
+}
+
+
+RotateScale2D.prototype.resetMatrixLabels = function(mat)
+{
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.data[i][j] = this.standardize(mat.data[i][j]);
+ this.cmd("SetText", mat.dataID[i][j], mat.data[i][j]);
+ }
+ }
+}
+
+
+
+RotateScale2D.prototype.moveMatrix = function(mat, x, y)
+{
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ }
+
+
+ this.cmd("Move", mat.leftBrack1, x, y);
+ this.cmd("Move", mat.leftBrack2, x, y);
+ this.cmd("Move", mat.leftBrack3, x, y + height * RotateScale2D.MATRIX_ELEM_HEIGHT);
+
+ this.cmd("Move", mat.rightBrack1, x + width * RotateScale2D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack2, x + width * RotateScale2D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack3, x+ width * RotateScale2D.MATRIX_ELEM_WIDTH, y + height * RotateScale2D.MATRIX_ELEM_HEIGHT);
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Move", mat.dataID[i][j],
+ x + j*RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_ELEM_WIDTH / 2,
+ y + i*RotateScale2D.MATRIX_ELEM_HEIGHT + RotateScale2D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+}
+
+RotateScale2D.prototype.deleteMatrix = function(mat)
+{
+ this.cmd("Delete",mat.leftBrack1);
+ this.cmd("Delete",mat.leftBrack2);
+ this.cmd("Delete",mat.leftBrack3);
+ this.cmd("Delete",mat.rightBrack1);
+ this.cmd("Delete",mat.rightBrack2);
+ this.cmd("Delete",mat.rightBrack3);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Delete", mat.dataID[i][j]);
+ }
+ }
+}
+
+RotateScale2D.prototype.setMatrixAlpha = function(mat, alpha)
+{
+ this.cmd("SetAlpha",mat.leftBrack1, alpha);
+ this.cmd("SetAlpha",mat.leftBrack2, alpha);
+ this.cmd("SetAlpha",mat.leftBrack3, alpha);
+ this.cmd("SetAlpha",mat.rightBrack1, alpha);
+ this.cmd("SetAlpha",mat.rightBrack2, alpha);
+ this.cmd("SetAlpha",mat.rightBrack3, alpha);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("SetAlpha", mat.dataID[i][j], alpha);
+ }
+ }
+}
+
+
+RotateScale2D.prototype.createMatrix = function(contents, x, y)
+{
+ var mat = new Matrix(contents, x, y);
+ mat.leftBrack1 = this.nextIndex++;
+ mat.leftBrack2 = this.nextIndex++;
+ mat.leftBrack3 = this.nextIndex++;
+ mat.rightBrack1 = this.nextIndex++;
+ mat.rightBrack2 = this.nextIndex++;
+ mat.rightBrack3 = this.nextIndex++;
+
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ mat.dataID = new Array(mat.data.length);
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ mat.dataID[i] = new Array(mat.data[i].length);
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.dataID[i][j] = this.nextIndex++;
+ }
+ }
+
+ this.cmd("CreateRectangle", mat.leftBrack1, "", 5, 1, x, y, "left","center");
+ this.cmd("CreateRectangle", mat.leftBrack2, "", 1, height * RotateScale2D.MATRIX_ELEM_HEIGHT, x, y, "center","top");
+ this.cmd("CreateRectangle", mat.leftBrack3, "", 5, 1, x, y + height * RotateScale2D.MATRIX_ELEM_HEIGHT , "left","center");
+
+ this.cmd("CreateRectangle", mat.rightBrack1, "", 5, 1, x + width * RotateScale2D.MATRIX_ELEM_WIDTH, y, "right","center");
+ this.cmd("CreateRectangle", mat.rightBrack2, "", 1, height * RotateScale2D.MATRIX_ELEM_HEIGHT, x + width * RotateScale2D.MATRIX_ELEM_WIDTH, y, "center","top");
+ this.cmd("CreateRectangle", mat.rightBrack3, "", 5, 1, x+ width * RotateScale2D.MATRIX_ELEM_WIDTH, y + height * RotateScale2D.MATRIX_ELEM_HEIGHT , "right","center");
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("CreateLabel", mat.dataID[i][j], mat.data[i][j],
+ x + j*RotateScale2D.MATRIX_ELEM_WIDTH + RotateScale2D.MATRIX_ELEM_WIDTH / 2,
+ y + i*RotateScale2D.MATRIX_ELEM_HEIGHT + RotateScale2D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ return mat;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new RotateScale2D(animManag, canvas.width, canvas.height);
+}
+
+function Matrix(contents, x, y)
+{
+ this.data = contents;
+ this.x = x;
+ this.y = y;
+}
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateScale3D.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateScale3D.js
new file mode 100644
index 0000000..bd55e10
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateScale3D.js
@@ -0,0 +1,1155 @@
+// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, areobjectVertexLocalPosition
+// 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
+
+
+
+function RotateScale3D(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+RotateScale3D.prototype = new Algorithm();
+RotateScale3D.prototype.constructor = RotateScale3D;
+RotateScale3D.superclass = Algorithm.prototype;
+
+RotateScale3D.XAxisYPos = 300;
+RotateScale3D.XAxisStart = 100;
+RotateScale3D.XAxisEnd = 700;
+
+
+RotateScale3D.MATRIX_START_X = 10;
+RotateScale3D.MATRIX_START_Y = 10;
+RotateScale3D.MATRIX_MULTIPLY_SPACING = 10;
+RotateScale3D.EQUALS_SPACING = 30;
+
+RotateScale3D.AXIS_SIZE = 200;
+
+RotateScale3D.AXIS_ALPHA = 0.7;
+
+RotateScale3D.YAxisXPos = 400;
+RotateScale3D.YAxisStart = 100;
+RotateScale3D.YAxisEnd = 500;
+
+RotateScale3D.MATRIX_ELEM_WIDTH = 50;
+RotateScale3D.MATRIX_ELEM_HEIGHT = 20;
+
+RotateScale3D.OBJECTS = [
+ [[100, 100, 100], [-100, 100,100], [-100,-100,100], [100, -100, 100],
+ [100, -100, -100], [100, 100, -100], [-100, 100,-100], [-100,-100,-100]
+ ], // Cube
+
+ [[10, 10, 100], [-10, 10, 100], [-10, 10, -100], [100, 10, -100], [100, 10, -80], [10, 10, -80],
+ [10, -10, -80],[10, -10, 100], [-10, -10, 100], [-10, -10, -100], [100, -10, -100], [100, -10, -80],
+
+
+ ], // L
+ [[0, 0, 141], [-134, 0, 44], [-83, 0, -114 ], [83, 0, -114], [134, 0, 44]], // Pentagon
+ [[0, 0, 141], [-35,0, 48],[-134, 0, 44], [-57, 0, -19], [-83, 0, -114 ], [0, 0, -60],[83, 0, -114], [57, 0, -19], [134, 0, 44], [35, 0, 48]] // Star
+ ];
+
+RotateScale3D.EXTRA_CONNECTIONS = [
+ [[3, 0], [5,0], [6,1], [7,2], [4,7]], // Cube
+ [[5, 0], [6, 11], [0,7], [1,8], [2,9],[3,10],[4,11]], // L
+ [[4,0]], // Pentagon
+ [[9, 0]] //Star
+ ]
+
+
+RotateScale3D.CAMERA_Z_ROT = toRadians(-10);
+RotateScale3D.CAMERA_X_ROT = toRadians(10);
+
+RotateScale3D.CAMERA_TRANS_ANGLE = toRadians(30);
+RotateScale3D.L = 0.5;
+
+
+RotateScale3D.CAMERA_TRANSFORM = [[1, 0, 0],
+ [RotateScale3D.L * Math.cos(RotateScale3D.CAMERA_TRANS_ANGLE), 0, RotateScale3D.L * Math.sin(RotateScale3D.CAMERA_TRANS_ANGLE)],
+ [0, 0, 1]];
+
+
+RotateScale3D.CAMERA_TRANSFORM2 = [[Math.cos(RotateScale3D.CAMERA_Z_ROT), Math.sin(RotateScale3D.CAMERA_Z_ROT), 0],
+ [-Math.sin(RotateScale3D.CAMERA_Z_ROT), Math.cos(RotateScale3D.CAMERA_Z_ROT), 0],
+ [0, 0, 1]];
+
+RotateScale3D.CAMERA_TRANSFORM1 = [[1, 0, 0],
+ [0, Math.cos(RotateScale3D.CAMERA_X_ROT), Math.sin(RotateScale3D.CAMERA_X_ROT)],
+ [0, -Math.sin(RotateScale3D.CAMERA_X_ROT), Math.cos(RotateScale3D.CAMERA_X_ROT)]
+ ];
+
+
+
+RotateScale3D.AXIS_COLOR = "#0000FF"
+RotateScale3D.VERTEX_FOREGORUND_COLOR = "#000000";
+RotateScale3D.VERTEX_BACKGROUND_COLOR = RotateScale3D.VERTEX_FOREGORUND_COLOR;
+RotateScale3D.EDGE_COLOR = "#000000";
+
+
+
+RotateScale3D.TRANSFORMED_VERTEX_FOREGORUND_COLOR = "#66FF66";
+RotateScale3D.TRANSFORMED_VERTEX_BACKGROUND_COLOR = RotateScale3D.VERTEX_FOREGORUND_COLOR;
+RotateScale3D.TRANSFORMED_EDGE_COLOR = "#66FF66";
+
+
+
+
+RotateScale3D.VECTOR_COLOR = "#FF0000";
+
+RotateScale3D.VERTEX_WIDTH = 3;
+RotateScale3D.VERTEX_HEIGHT = RotateScale3D.VERTEX_WIDTH;
+
+RotateScale3D.prototype.init = function(am, w, h)
+{
+ var sc = RotateScale3D.superclass.init.call(this, am, w, h);
+ this.cameraTransform = RotateScale3D.CAMERA_TRANSFORM;
+// this.cameraTransform = this.multiply(RotateScale3D.CAMERA_TRANSFORM1, RotateScale3D.CAMERA_TRANSFORM2);
+
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.addControls();
+ this.currentShape = 0;
+
+ this.commands = [];
+ this.nextIndex = 0;
+
+ this.setupAxis();
+
+ this.savedNextIndex = this.nextIndex;
+ this.setupObject();
+ this.setupObjectGraphic();
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.clearHistory();
+
+
+}
+
+RotateScale3D.prototype.setupAxis = function()
+{
+ this.xAxisMinID = this.nextIndex++;
+ this.xAxisMaxID = this.nextIndex++;
+ this.yAxisMinID = this.nextIndex++;
+ this.yAxisMaxID = this.nextIndex++;
+
+ this.zAxisMinID = this.nextIndex++;
+ this.zAxisMaxID = this.nextIndex++;
+
+
+ this.xAxisLabel = this.nextIndex++;
+ this.yAxisLabel = this.nextIndex++;
+ this.zAxisLabel = this.nextIndex++;
+ var point;
+
+
+ this.originID = this.nextIndex++;
+
+ point = this.worldToScreenSpace([0, 0, 0]);
+
+ this.cmd("CreateRectangle", this.originID, "", 0, 0, point[0], point[1]);
+
+ point = this.worldToScreenSpace([-RotateScale3D.AXIS_SIZE, 0, 0]);
+ this.cmd("CreateRectangle", this.xAxisMinID, "", 0, 0, point[0], point[1]);
+ this.cmd("SetAlpha", this.xAxisMinID, 0);
+
+ point = this.worldToScreenSpace([RotateScale3D.AXIS_SIZE, 0, 0]);
+ this.cmd("CreateRectangle", this.xAxisMaxID, "", 0, 0, point[0], point[1]);
+ this.cmd("SetAlpha", this.xAxisMaxID, 0);
+
+ this.cmd("Connect", this.xAxisMinID, this.xAxisMaxID, RotateScale3D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.xAxisMaxID, this.xAxisMinID, RotateScale3D.AXIS_COLOR, 0, 1, "");
+ this.cmd("SetEdgeAlpha", this.xAxisMaxID, this.xAxisMinID, RotateScale3D.AXIS_ALPHA);
+ this.cmd("SetEdgeAlpha", this.xAxisMinID, this.xAxisMaxID, RotateScale3D.AXIS_ALPHA);
+
+ point = this.worldToScreenSpace([0,-RotateScale3D.AXIS_SIZE, 0]);
+ this.cmd("CreateRectangle", this.yAxisMinID, "", 0, 0, point[0], point[1]);
+ this.cmd("SetAlpha", this.yAxisMinID, 0);
+
+ point = this.worldToScreenSpace([0,RotateScale3D.AXIS_SIZE, 0]);
+ this.cmd("CreateRectangle", this.yAxisMaxID, "", 0, 0, point[0], point[1]);
+ this.cmd("SetAlpha", this.yAxisMaxID, 0);
+
+ this.cmd("Connect", this.yAxisMinID, this.yAxisMaxID, RotateScale3D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.yAxisMaxID, this.yAxisMinID, RotateScale3D.AXIS_COLOR, 0, 1, "");
+ this.cmd("SetEdgeAlpha", this.yAxisMaxID, this.yAxisMinID, RotateScale3D.AXIS_ALPHA);
+ this.cmd("SetEdgeAlpha", this.yAxisMinID, this.yAxisMaxID, RotateScale3D.AXIS_ALPHA);
+
+
+ point = this.worldToScreenSpace([0,0, -RotateScale3D.AXIS_SIZE]);
+ this.cmd("CreateRectangle", this.zAxisMinID, "", 0, 0, point[0], point[1]);
+ this.cmd("SetAlpha", this.zAxisMinID, 0);
+
+ point = this.worldToScreenSpace([0, 0, RotateScale3D.AXIS_SIZE]);
+ this.cmd("CreateRectangle", this.zAxisMaxID, "", 0, 0, point[0], point[1]);
+ this.cmd("SetAlpha", this.zAxisMaxID, 0);
+
+ this.cmd("Connect", this.zAxisMinID, this.zAxisMaxID, RotateScale3D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.zAxisMaxID, this.zAxisMinID, RotateScale3D.AXIS_COLOR, 0, 1, "");
+
+ this.cmd("SetEdgeAlpha", this.zAxisMaxID, this.zAxisMinID, RotateScale3D.AXIS_ALPHA);
+ this.cmd("SetEdgeAlpha", this.zAxisMinID, this.zAxisMaxID, RotateScale3D.AXIS_ALPHA);
+
+
+ point = this.worldToScreenSpace([RotateScale3D.AXIS_SIZE, 0, -10]);
+ this.cmd("CreateLabel", this.xAxisLabel, "+x", point[0], point[1]);
+
+ point = this.worldToScreenSpace([+10, RotateScale3D.AXIS_SIZE, 0]);
+ this.cmd("CreateLabel", this.yAxisLabel, "+y", point[0], point[1]);
+
+ point = this.worldToScreenSpace([+10, 0, RotateScale3D.AXIS_SIZE]);
+ this.cmd("CreateLabel", this.zAxisLabel, "+z", point[0], point[1]);
+
+ this.cmd("SetForegroundColor", this.yAxisLabel, RotateScale3D.AXIS_COLOR);
+ this.cmd("SetForegroundColor", this.xAxisLabel, RotateScale3D.AXIS_COLOR);
+ this.cmd("SetForegroundColor", this.zAxisLabel, RotateScale3D.AXIS_COLOR);
+}
+
+
+RotateScale3D.prototype.setupObject = function()
+{
+ this.objectVertexPosition = RotateScale3D.OBJECTS[this.currentShape].slice(0);
+ this.extraConnections = RotateScale3D.EXTRA_CONNECTIONS[this.currentShape].slice(0);
+}
+
+
+RotateScale3D.prototype.worldToScreenSpace = function(point)
+{
+ var transformedPoint = this.multiply([point], this.cameraTransform)[0];
+ var worldSpace = new Array(2);
+ worldSpace[0] = transformedPoint[0] + RotateScale3D.YAxisXPos;
+ worldSpace[1] = RotateScale3D.XAxisYPos - transformedPoint[2];
+
+ return worldSpace;
+}
+
+
+
+RotateScale3D.prototype.moveObjectToNewPosition = function()
+{
+ var i;
+ for (i = 0; i < this.objectVertexID.length; i++)
+ {
+ var point = this.worldToScreenSpace(this.objectVertexPosition[i]);
+ this.cmd("Move", this.objectVertexID[i], point[0], point[1]);
+ }
+
+}
+
+
+RotateScale3D.prototype.setupObjectGraphic = function()
+{
+ this.objectVertexID = new Array(this.objectVertexPosition.length);
+ var i;
+ for (i = 0; i < this.objectVertexPosition.length; i++)
+ {
+ this.objectVertexID[i] = this.nextIndex++;
+ var point = this.worldToScreenSpace(this.objectVertexPosition[i]);
+
+ this.cmd("CreateRectangle", this.objectVertexID[i], "", RotateScale3D.VERTEX_WIDTH, RotateScale3D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", this.objectVertexID[i], RotateScale3D.VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", this.objectVertexID[i], RotateScale3D.VERTEX_BACKGROUND_COLOR);
+ }
+ for (i = 1; i < this.objectVertexID.length; i++)
+ {
+ this.cmd("Connect", this.objectVertexID[i-1], this.objectVertexID[i], RotateScale3D.EDGE_COLOR, 0, 0, "");
+ }
+
+ for (var i = 0; i < this.extraConnections.length; i++)
+ {
+ this.cmd("Connect", this.objectVertexID[this.extraConnections[i][0]], this.objectVertexID[this.extraConnections[i][1]], RotateScale3D.EDGE_COLOR, 0, 0, "");
+ }
+
+}
+
+RotateScale3D.prototype.addControls = function()
+{
+ this.controls = [];
+
+ addLabelToAlgorithmBar("X Angle");
+
+ this.rotationFieldX = addControlToAlgorithmBar("Text", "");
+ this.rotationFieldX.onkeydown = this.returnSubmitFloat(this.rotationFieldX, this.rotateCallback.bind(this), 4, true);
+ this.controls.push(this.rotationFieldX);
+
+ addLabelToAlgorithmBar("Y Angle");
+
+ this.rotationFieldY = addControlToAlgorithmBar("Text", "");
+ this.rotationFieldY.onkeydown = this.returnSubmitFloat(this.rotationFieldY, this.rotateCallback.bind(this), 4, true);
+ this.controls.push(this.rotationFieldY);
+
+ addLabelToAlgorithmBar("Z Angle");
+
+ this.rotationFieldZ = addControlToAlgorithmBar("Text", "");
+ this.rotationFieldZ.onkeydown = this.returnSubmitFloat(this.rotationFieldZ, this.rotateCallback.bind(this), 4, true);
+ this.controls.push(this.rotationFieldZ);
+
+
+
+ var rotateButton = addControlToAlgorithmBar("Button", "Rotate");
+ rotateButton.onclick = this.rotateCallback.bind(this);
+
+ this.controls.push(rotateButton);
+
+
+ addLabelToAlgorithmBar("Scale X");
+
+ this.scaleXField = addControlToAlgorithmBar("Text", "");
+ this.scaleXField.onkeydown = this.returnSubmitFloat(this.scaleXField, this.scaleCallback.bind(this), 4, true);
+ this.controls.push(this.scaleXField);
+
+
+ addLabelToAlgorithmBar("Scale Y");
+
+ this.scaleYField = addControlToAlgorithmBar("Text", "");
+ this.scaleYField.onkeydown = this.returnSubmitFloat(this.scaleYField, this.scaleCallback.bind(this), 4, true);
+ this.controls.push(this.scaleYField);
+
+ addLabelToAlgorithmBar("Scale Z");
+
+ this.scaleZField = addControlToAlgorithmBar("Text", "");
+ this.scaleZField.onkeydown = this.returnSubmitFloat(this.scaleZField, this.scaleCallback.bind(this), 4, true);
+ this.controls.push(this.scaleZField);
+
+
+
+ var scaleButton = addControlToAlgorithmBar("Button", "Scale");
+ scaleButton.onclick = this.scaleCallback.bind(this);
+
+ this.controls.push(scaleButton);
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Row Major",
+ "Column Major",
+ ],
+ "RankType");
+ this.rowMajorButton = radioButtonList[0];
+ this.rowMajorButton.onclick = this.changeRowColMajorCallback.bind(this, true);
+ this.controls.push(this.rowMajorButton);
+
+ this.colMajorButton = radioButtonList[1];
+ this.colMajorButton.onclick = this.changeRowColMajorCallback.bind(this, false);
+ this.controls.push(this.colMajorButton);
+
+ this.rowMajorButton.checked = this.rowMajor;
+ this.colMajorButton.checked = !this.rowMajor;
+
+
+
+ var changeShapeButton = addControlToAlgorithmBar("Button", "Change Shape");
+ changeShapeButton.onclick = this.changeShapeCallback.bind(this);
+
+ this.controls.push(changeShapeButton);
+
+}
+
+
+
+
+
+
+RotateScale3D.prototype.reset = function()
+{
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.currentShape = 0;
+ this.rowMajorButton.checked = this.rowMajor;
+
+ this.nextIndex = this.savedNextIndex;
+ this.setupObject();
+ this.setupObjectGraphic();
+}
+
+
+RotateScale3D.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+RotateScale3D.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+RotateScale3D.prototype.changePosYCallback = function(posYUp)
+{
+ if (this.posYUp != posYUp)
+ {
+ this.implementAction(this.changePosY.bind(this), posYUp);
+ }
+}
+
+RotateScale3D.prototype.changePosY = function(posYUp)
+{
+ this.commands = new Array();
+ this.posYUp= posYUp;
+ if (this.posYUpButton.checked != this.posYUp)
+ {
+ this.posYUpButton.checked = this.posYUp;
+ }
+ if (this.posYDownButton.checked == this.posYUp)
+ {
+ this.posYDownButton.checked = !this.posYUp;
+ }
+ if (this.posYUp)
+ {
+ this.cmd("Move", this.yAxisLabel, RotateScale3D.YAxisXPos + 10, RotateScale3D.YAxisStart + 10);
+ }
+ else
+ {
+ this.cmd("Move", this.yAxisLabel, RotateScale3D.YAxisXPos + 10, RotateScale3D.YAxisEnd - 10);
+
+ }
+
+ this.moveObjectToNewPosition();
+
+
+
+
+ // Move +y on axis up/down
+ return this.commands;
+}
+
+
+
+RotateScale3D.prototype.changeRowColMajorCallback = function(rowMajor)
+{
+ if (this.rowMajor != rowMajor)
+ {
+ this.implementAction(this.changeRowCol.bind(this), rowMajor);
+ }
+}
+
+RotateScale3D.prototype.changeRowCol = function(rowMajor)
+{
+ this.commands = new Array();
+ this.rowMajor= rowMajor;
+ if (this.rowMajorButton.checked != this.rowMajor)
+ {
+ this.rowMajorButton.checked = this.rowMajor;
+ }
+ if (this.colMajorButton.checked == this.rowMajor)
+ {
+ this.colMajorButton.checked = !this.rowMajor;
+ }
+ return this.commands;
+}
+
+
+RotateScale3D.prototype.fixNumber = function(value, defaultVal)
+{
+ if (value == "" || value == "-" || value == "." || value == "-." || isNaN(parseFloat(value)))
+ {
+ value = defaultVal;
+ }
+ else
+ {
+ value = String(parseFloat(value));
+ }
+ return value
+}
+
+RotateScale3D.prototype.rotateCallback = function()
+{
+
+
+ this.rotationFieldX.value = this.fixNumber(this.rotationFieldX.value, "0");
+ this.rotationFieldY.value = this.fixNumber(this.rotationFieldY.value, "0");
+ this.rotationFieldZ.value = this.fixNumber(this.rotationFieldZ.value, "0");
+ this.implementAction(this.rotate.bind(this), this.rotationFieldZ.value + ";" +this.rotationFieldY.value + ";" +this.rotationFieldX.value);
+
+}
+RotateScale3D.prototype.scaleCallback = function()
+{
+
+
+ this.scaleXField.value = this.fixNumber(this.scaleXField.value, "1");
+ this.scaleYField.value = this.fixNumber(this.scaleYField.value, "1");
+ this.scaleZField.value = this.fixNumber(this.scaleZField.value, "1");
+ this.implementAction(this.scale.bind(this), this.scaleXField.value + ";" +this.scaleYField.value + ";" +this.scaleZField.value);
+
+}
+
+
+RotateScale3D.prototype.changeShapeCallback = function()
+{
+ this.implementAction(this.changeShape.bind(this), 0);
+}
+
+RotateScale3D.prototype.changeShape = function()
+{
+ this.commands = [];
+ var i;
+ for (i = 0; i < this.objectVertexID.length; i++)
+ {
+ this.cmd("Delete", this.objectVertexID[i]);
+ }
+ this.currentShape++;
+ if (this.currentShape >= RotateScale3D.OBJECTS.length)
+ {
+ this.currentShape = 0;
+ }
+ this.setupObject();
+ this.setupObjectGraphic();
+ return this.commands;
+}
+
+RotateScale3D.prototype.rotateScaleOrderCallback = function(rotateFirst)
+{
+ if (this.rotateFirst != rotateFirst)
+ {
+ this.implementAction(this.rotateScaleOrder.bind(this), rotateFirst);
+ }
+}
+
+
+RotateScale3D.prototype.rotateScaleOrder = function(rotateFirst)
+{
+ this.commands = new Array();
+ this.rotateFirst= rotateFirst;
+ if (this.rotateScaleButton.checked != this.rotateFirst)
+ {
+ this.rotateScaleButton.checked = this.rotateFirst;
+ }
+ if (this.scaleRotateButton.checked == this.rotateFirst)
+ {
+ this.scaleRotateButton.checked = !this.rotateFirst;
+ }
+ return this.commands;
+}
+
+
+function toRadians(degrees)
+{
+ return (degrees * 2 * Math.PI) / 360.0;
+}
+
+RotateScale3D.prototype.scale = function(input)
+{
+ var oldNextIndex = this.nextIndex;
+ this.commands = [];
+ var inputs = input.split(";");
+ var scaleX = parseFloat(inputs[0]);
+ var scaleY = parseFloat(inputs[1]);
+ var scaleZ = parseFloat(inputs[2]);
+
+ var xpos = RotateScale3D.MATRIX_START_X;
+ var ypos = RotateScale3D.MATRIX_START_Y;
+
+ xpos += 3 * RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING;
+
+
+ var transformMatrix = this.createMatrix([[scaleX, 0, 0],
+ [0, scaleY, 0],
+ [0, 0, scaleZ]], xpos, ypos);
+ this.transformPoints(transformMatrix);
+ this.deleteMatrix(transformMatrix);
+ return this.commands;
+
+}
+
+
+RotateScale3D.prototype.transformPoints = function(transformMatrix)
+{
+ var explainID = this.nextIndex++;
+ var equalID = this.nextIndex++;
+ var xyz;
+
+ if (this.rowMajor)
+ {
+ xyz = this.createMatrix([["x", "y", "z"]], RotateScale3D.MATRIX_START_X, RotateScale3D.MATRIX_START_Y);
+ this.cmd("CreateLabel", explainID, "", RotateScale3D.MATRIX_START_X + 6*RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING + RotateScale3D.EQUALS_SPACING,
+ RotateScale3D.MATRIX_START_Y + 1.5*RotateScale3D.MATRIX_ELEM_HEIGHT, 0);
+ this.cmd("CreateLabel", equalID, "=", RotateScale3D.MATRIX_START_X + 6*RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING + RotateScale3D.EQUALS_SPACING / 2,
+ RotateScale3D.MATRIX_START_Y + 0.5*RotateScale3D.MATRIX_ELEM_HEIGHT);
+
+ }
+ else
+ {
+ xyz = this.createMatrix([["x"], ["y"], ["z"]], RotateScale3D.MATRIX_START_X + 6*RotateScale3D.MATRIX_ELEM_WIDTH + 2*RotateScale3D.MATRIX_MULTIPLY_SPACING,
+ RotateScale3D.MATRIX_START_Y);
+ this.cmd("CreateLabel", explainID, "", RotateScale3D.MATRIX_START_X + 7*RotateScale3D.MATRIX_ELEM_WIDTH + 2*RotateScale3D.MATRIX_MULTIPLY_SPACING + RotateScale3D.EQUALS_SPACING,
+ RotateScale3D.MATRIX_START_Y + 3*RotateScale3D.MATRIX_ELEM_HEIGHT + 2, 0);
+ this.cmd("CreateLabel", equalID, "=", RotateScale3D.MATRIX_START_X + 7*RotateScale3D.MATRIX_ELEM_WIDTH + 2*RotateScale3D.MATRIX_MULTIPLY_SPACING + RotateScale3D.EQUALS_SPACING / 2,
+ RotateScale3D.MATRIX_START_Y + 1.5*RotateScale3D.MATRIX_ELEM_HEIGHT);
+
+ }
+ this.cmd("Step");
+
+ var i;
+
+ var transformedObjectID = new Array(this.objectVertexID.length);
+ var output;
+
+ for (i = 0; i < this.objectVertexID.length; i++)
+ {
+ this.cmd("Connect", this.originID, this.objectVertexID[i], RotateScale3D.VECTOR_COLOR, 0, 1, "");
+ if (this.rowMajor)
+ {
+ xyz.data = [this.objectVertexPosition[i].slice(0)];
+ }
+ else
+ {
+ xyz.data[0][0] = this.objectVertexPosition[i][0];
+ xyz.data[1][0] = this.objectVertexPosition[i][1];
+ xyz.data[2][0] = this.objectVertexPosition[i][2];
+ }
+ this.resetMatrixLabels(xyz);
+ this.cmd("Step");
+
+
+ if (this.rowMajor)
+ {
+ output = this.createMatrix([["", "", ""]],
+ RotateScale3D.MATRIX_START_X + 6*RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING + RotateScale3D.EQUALS_SPACING,
+ RotateScale3D.MATRIX_START_Y);
+ this.multiplyMatrix(xyz, transformMatrix, output, explainID);
+ }
+ else
+ {
+ output = this.createMatrix([[""], [""], [""]],
+ RotateScale3D.MATRIX_START_X + 7*RotateScale3D.MATRIX_ELEM_WIDTH + 2 * RotateScale3D.MATRIX_MULTIPLY_SPACING + RotateScale3D.EQUALS_SPACING,
+ RotateScale3D.MATRIX_START_Y);
+
+ this.multiplyMatrix(transformMatrix, xyz, output, explainID);
+ }
+
+
+ transformedObjectID[i] = this.nextIndex++;
+ var point;
+ if (this.rowMajor)
+ {
+ point = this.worldToScreenSpace(output.data[0]);
+ }
+ else
+ {
+ point = this.worldToScreenSpace([output.data[0][0], output.data[1][0], output.data[2][0]]);
+ }
+
+ this.cmd("CreateRectangle", transformedObjectID[i], "", RotateScale3D.VERTEX_WIDTH, RotateScale3D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", transformedObjectID[i], RotateScale3D.TRANSFORMED_VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", transformedObjectID[i], RotateScale3D.TRANSFORMED_VERTEX_BACKGROUND_COLOR);
+ this.cmd("Connect", this.originID, transformedObjectID[i], RotateScale3D.TRANSFORMED_EDGE_COLOR, 0, 1, "");
+ this.cmd("Step");
+ this.cmd("Disconnect", this.originID, transformedObjectID[i]);
+
+ if (i > 0)
+ {
+ this.cmd("Connect", transformedObjectID[i-1], transformedObjectID[i], RotateScale3D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+
+ }
+ for (var j = 0; j < this.extraConnections.length; j++)
+ {
+ if ((this.extraConnections[j][0] == i && this.extraConnections[j][1] < i) ||
+ (this.extraConnections[j][1] == i && this.extraConnections[j][0] < i))
+ {
+ this.cmd("Connect", transformedObjectID[this.extraConnections[j][0]], transformedObjectID[this.extraConnections[j][1]], RotateScale3D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+ }
+
+ }
+
+ this.cmd("Disconnect", this.originID, this.objectVertexID[i]);
+ if (this.rowMajor)
+ {
+ this.objectVertexPosition[i] = output.data[0];
+ }
+ else
+ {
+ this.objectVertexPosition[i][0] = output.data[0][0];
+ this.objectVertexPosition[i][1] = output.data[1][0];
+ }
+ this.deleteMatrix(output);
+
+ }
+ this.cmd("Step");
+
+ this.cmd("Connect", transformedObjectID[0], transformedObjectID[transformedObjectID.length-1], RotateScale3D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+
+ this.cmd("Step","B");
+ this.moveObjectToNewPosition();
+ this.cmd("Step","C");
+
+ for (i = 0; i < transformedObjectID.length; i++)
+ {
+ this.cmd("Delete", transformedObjectID[i]);
+ }
+
+
+ this.deleteMatrix(xyz);
+ this.cmd("Delete", explainID);
+ this.cmd("Delete", equalID);
+
+}
+
+
+RotateScale3D.prototype.rotate = function(input)
+{
+ var oldNextIndex = this.nextIndex;
+ this.commands = [];
+ var inputs = input.split(";");
+ var rotateAngle1 = toRadians(parseFloat(inputs[0]));
+ var rotateAngle2 = toRadians(parseFloat(inputs[1]));
+ var rotateAngle3 = toRadians(parseFloat(inputs[2]));
+
+ var xpos = RotateScale3D.MATRIX_START_X;
+ var ypos = RotateScale3D.MATRIX_START_Y;
+
+ xpos += 3 * RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING;
+
+
+ var matrix1Data;
+ var matrix2Data;
+ var matrix3Data;
+
+ matrix1Data = [["cos \u0398z", "sin \u0398z", 0],
+ ["-sin \u0398z", "cos \u0398z", 0],
+ [ 0, 0, 1]];
+ matrix2Data = [["cos \u0398y", 0, "sin \u0398y"],
+ [0, 1, 0 ],
+ ["-sin \u0398y", 0, "cos \u0398y"]];
+
+ matrix3Data = [[1, 0 , 0],
+ [0, "cos \u0398x", "sin \u0398x"],
+ [0, "-sin \u0398x", "cos \u0398x"]];
+ if (!this.rowMajor)
+ {
+ var tmp = matrix1Data;
+ matrix1Data = matrix3Data;
+ matrix3Data = tmp;
+ }
+
+ var firstMat = this.createMatrix(matrix1Data, xpos, ypos);
+ xpos += firstMat.data[0].length * RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING;
+
+ var secondMat = this.createMatrix(matrix2Data, xpos, ypos);
+ xpos += secondMat.data[0].length * RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING;
+
+ var thirdMat = this.createMatrix(matrix3Data, xpos, ypos);
+ xpos += secondMat.data[0].length * RotateScale3D.MATRIX_ELEM_WIDTH;
+
+ if (!this.rowMajor)
+ {
+ firstMat.transpose();
+ secondMat.transpose();
+ thirdMat.transpose();
+ this.resetMatrixLabels(firstMat);
+ this.resetMatrixLabels(secondMat);
+ this.resetMatrixLabels(thirdMat);
+
+ }
+
+ this.cmd("Step");
+
+ firstMat.data = [["cos " + inputs[0], "sin " +inputs[0], 0],
+ ["-sin "+ inputs[0], "cos "+ inputs[0], 0],
+ [ 0, 0, 1]];
+ secondMat.data = [["cos " +inputs[1], 0, "sin " +inputs[1]],
+ [0, 1, 0 ],
+ ["-sin " +inputs[1], 0, "cos " +inputs[1]]];
+
+ thirdMat.data = [[1, 0 , 0],
+ [0, "cos " +inputs[2], "sin " +inputs[2]],
+ [0, "-sin " +inputs[2], "cos " +inputs[2]]];
+
+ if (!this.rowMajor)
+ {
+ var tmp = firstMat.data;
+ firstMat.data = thirdMat.data;
+ thirdMat.data = tmp;
+ firstMat.transpose();
+ secondMat.transpose();
+ thirdMat.transpose();
+ }
+
+ this.resetMatrixLabels(firstMat);
+ this.resetMatrixLabels(secondMat);
+ this.resetMatrixLabels(thirdMat);
+
+ this.cmd("Step");
+
+ firstMat.data = [[Math.cos(rotateAngle1), Math.sin(rotateAngle1), 0],
+ [-Math.sin(rotateAngle1), Math.cos(rotateAngle1), 0],
+ [ 0, 0, 1]];
+ secondMat.data = [[Math.cos(rotateAngle2), 0, Math.sin(rotateAngle2)],
+ [ 0, 1, 0],
+ [-Math.sin(rotateAngle2), 0, Math.cos(rotateAngle2)]];
+ thirdMat.data = [[1, 0, 0],
+ [0, Math.cos(rotateAngle3), Math.sin(rotateAngle3)],
+ [0, -Math.sin(rotateAngle3), Math.cos(rotateAngle3)]];
+
+ if (!this.rowMajor)
+ {
+ var tmp = firstMat.data;
+ firstMat.data = thirdMat.data;
+ thirdMat.data = tmp;
+ firstMat.transpose();
+ secondMat.transpose();
+ thirdMat.transpose();
+ }
+
+ this.resetMatrixLabels(firstMat);
+ this.resetMatrixLabels(secondMat);
+ this.resetMatrixLabels(thirdMat);
+
+ this.cmd("Step");
+
+ this.setMatrixAlpha(firstMat, 0.3);
+
+
+ var paren1 = this.nextIndex++
+ var paren2 = this.nextIndex++
+ var paren3 = this.nextIndex++
+ var paren4 = this.nextIndex++
+ this.cmd("step");
+
+ var parenX;
+ parenX = xpos - 6 * RotateScale3D.MATRIX_ELEM_WIDTH - RotateScale3D.MATRIX_MULTIPLY_SPACING - 2;
+
+ this.cmd("CreateRectangle", paren1, "", 0, 0, parenX, RotateScale3D.MATRIX_START_Y, "center","center");
+ this.cmd("CreateRectangle", paren2, "", 0, 0, parenX, RotateScale3D.MATRIX_START_Y + 3*RotateScale3D.MATRIX_ELEM_HEIGHT, "center","center");
+ this.cmd("Connect", paren1, paren2, "#000000", 0.2, 0, "");
+
+ parenX = xpos;
+
+ this.cmd("CreateRectangle", paren3, "", 0, 0, parenX, RotateScale3D.MATRIX_START_Y, "center","center");
+ this.cmd("CreateRectangle", paren4, "", 0, 0, parenX, RotateScale3D.MATRIX_START_Y+ 3*RotateScale3D.MATRIX_ELEM_HEIGHT, "center","center");
+
+ this.cmd("Connect", paren3, paren4, "#000000", -0.2, 0 ,"");
+
+ this.cmd("Step");
+ var tmpMat = this.createMatrix([["","",""], ["","",""],["","",""]], xpos + RotateScale3D.EQUALS_SPACING, ypos);
+
+ var explainID = this.nextIndex++;
+ this.cmd("CreateLabel", explainID, "", xpos + RotateScale3D.EQUALS_SPACING, ypos + RotateScale3D.MATRIX_ELEM_HEIGHT*3 + 5, 0);
+
+ var equalID = this.nextIndex++;
+ this.cmd("CreateLabel", equalID, "=", xpos + RotateScale3D.EQUALS_SPACING / 2, ypos + RotateScale3D.MATRIX_ELEM_HEIGHT*1.5);
+ this.multiplyMatrix(secondMat, thirdMat, tmpMat, explainID);
+
+
+ this.cmd("Step");
+ this.deleteMatrix(secondMat);
+ this.deleteMatrix(thirdMat);
+ this.cmd("Delete", paren1);
+ this.cmd("Delete", paren2);
+ this.cmd("Delete", paren3);
+ this.cmd("Delete", paren4);
+ this.cmd("Delete", equalID);
+ this.cmd("Delete", explainID);
+
+ this.moveMatrix(tmpMat, RotateScale3D.MATRIX_START_X + 6*RotateScale3D.MATRIX_ELEM_WIDTH + 2* RotateScale3D.MATRIX_MULTIPLY_SPACING, ypos);
+
+ this.cmd("Step");
+
+
+ this.setMatrixAlpha(firstMat, 1);
+ xpos = RotateScale3D.MATRIX_START_X + 9 * RotateScale3D.MATRIX_ELEM_WIDTH + 2 * RotateScale3D.MATRIX_MULTIPLY_SPACING;
+
+ var transformMatrix = this.createMatrix([["","",""], ["","",""],["","",""]], xpos + RotateScale3D.EQUALS_SPACING, ypos);
+
+ this.cmd("CreateLabel", explainID, "", xpos + RotateScale3D.EQUALS_SPACING, ypos + RotateScale3D.MATRIX_ELEM_HEIGHT*3 + 5, 0);
+ this.cmd("CreateLabel", equalID, "=", xpos + RotateScale3D.EQUALS_SPACING / 2, ypos + RotateScale3D.MATRIX_ELEM_HEIGHT*1.5);
+
+ this.multiplyMatrix(firstMat, tmpMat, transformMatrix, explainID);
+
+ this.deleteMatrix(firstMat);
+ this.deleteMatrix(tmpMat);
+ this.cmd("Delete", equalID);
+ this.cmd("Delete", explainID);
+
+ this.moveMatrix(transformMatrix, RotateScale3D.MATRIX_START_X + 3*RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_MULTIPLY_SPACING, ypos);
+ this.cmd("Step");
+
+
+ this.transformPoints(transformMatrix);
+
+
+
+
+
+// this.nextIndex = oldNextIndex
+
+
+ this.deleteMatrix(transformMatrix);
+
+ return this.commands;
+}
+
+
+RotateScale3D.prototype.multiplyMatrix = function(mat1, mat2, mat3, explainID)
+{
+ var i;
+ var j;
+ var explainText = "";
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat2.data[0].length; j++)
+ {
+ var explainText = "";
+ var value = 0;
+ for (k = 0; k < mat2.data.length; k++)
+ {
+ this.cmd("SetHighlight", mat1.dataID[i][k], 1);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 1);
+ if (explainText != "")
+ {
+ explainText = explainText + " + ";
+ }
+ value = value + mat1.data[i][k] * mat2.data[k][j];
+ explainText = explainText + String(mat1.data[i][k]) + " * " + String(mat2.data[k][j]);
+ this.cmd("SetText", explainID, explainText);
+ this.cmd("Step");
+ this.cmd("SetHighlight", mat1.dataID[i][k], 0);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 0);
+ }
+ value = this.standardize(value);
+ explainText += " = " + String(value);
+ this.cmd("SetText", explainID, explainText);
+ mat3.data[i][j] = value;
+ this.cmd("SetText", mat3.dataID[i][j], value);
+ this.cmd("Step");
+ }
+ }
+ this.cmd("SetText", explainID, "");
+
+
+}
+
+RotateScale3D.prototype.standardize = function(lab)
+{
+ var newLab = Math.round(lab * 1000) / 1000;
+ if (isNaN(newLab))
+ {
+ return lab;
+ }
+ else
+ {
+ return newLab;
+ }
+}
+
+
+RotateScale3D.prototype.resetMatrixLabels = function(mat)
+{
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.data[i][j] = this.standardize(mat.data[i][j]);
+ this.cmd("SetText", mat.dataID[i][j], mat.data[i][j]);
+ }
+ }
+}
+
+
+
+RotateScale3D.prototype.moveMatrix = function(mat, x, y)
+{
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ }
+
+
+ this.cmd("Move", mat.leftBrack1, x, y);
+ this.cmd("Move", mat.leftBrack2, x, y);
+ this.cmd("Move", mat.leftBrack3, x, y + height * RotateScale3D.MATRIX_ELEM_HEIGHT);
+
+ this.cmd("Move", mat.rightBrack1, x + width * RotateScale3D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack2, x + width * RotateScale3D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack3, x+ width * RotateScale3D.MATRIX_ELEM_WIDTH, y + height * RotateScale3D.MATRIX_ELEM_HEIGHT);
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Move", mat.dataID[i][j],
+ x + j*RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_ELEM_WIDTH / 2,
+ y + i*RotateScale3D.MATRIX_ELEM_HEIGHT + RotateScale3D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+}
+
+RotateScale3D.prototype.deleteMatrix = function(mat)
+{
+ this.cmd("Delete",mat.leftBrack1);
+ this.cmd("Delete",mat.leftBrack2);
+ this.cmd("Delete",mat.leftBrack3);
+ this.cmd("Delete",mat.rightBrack1);
+ this.cmd("Delete",mat.rightBrack2);
+ this.cmd("Delete",mat.rightBrack3);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Delete", mat.dataID[i][j]);
+ }
+ }
+}
+
+RotateScale3D.prototype.setMatrixAlpha = function(mat, alpha)
+{
+ this.cmd("SetAlpha",mat.leftBrack1, alpha);
+ this.cmd("SetAlpha",mat.leftBrack2, alpha);
+ this.cmd("SetAlpha",mat.leftBrack3, alpha);
+ this.cmd("SetAlpha",mat.rightBrack1, alpha);
+ this.cmd("SetAlpha",mat.rightBrack2, alpha);
+ this.cmd("SetAlpha",mat.rightBrack3, alpha);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("SetAlpha", mat.dataID[i][j], alpha);
+ }
+ }
+}
+
+
+
+// Multiply two (data only!) matrices (not complete matrix object with graphics, just
+// the data
+RotateScale3D.prototype.multiply = function(lhs, rhs)
+{
+ var resultMat = new Array(lhs.length);
+ var i, j, k;
+
+ for (i = 0; i < lhs.length; i++)
+ {
+ resultMat[i] = new Array(rhs[0].length);
+ }
+ for (i = 0; i < lhs.length; i++)
+ {
+ for (j = 0; j < rhs[0].length; j++)
+ {
+ var value = 0;
+ for (k = 0; k < rhs.length; k++)
+ {
+ value = value + lhs[i][k] * rhs[k][j];
+ }
+ resultMat[i][j] = value;
+ }
+ }
+ return resultMat;
+}
+
+
+RotateScale3D.prototype.createMatrix = function(contents, x, y)
+{
+ var mat = new Matrix(contents, x, y);
+ mat.leftBrack1 = this.nextIndex++;
+ mat.leftBrack2 = this.nextIndex++;
+ mat.leftBrack3 = this.nextIndex++;
+ mat.rightBrack1 = this.nextIndex++;
+ mat.rightBrack2 = this.nextIndex++;
+ mat.rightBrack3 = this.nextIndex++;
+
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ mat.dataID = new Array(mat.data.length);
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ mat.dataID[i] = new Array(mat.data[i].length);
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.dataID[i][j] = this.nextIndex++;
+ }
+ }
+
+ this.cmd("CreateRectangle", mat.leftBrack1, "", 5, 1, x, y, "left","center");
+ this.cmd("CreateRectangle", mat.leftBrack2, "", 1, height * RotateScale3D.MATRIX_ELEM_HEIGHT, x, y, "center","top");
+ this.cmd("CreateRectangle", mat.leftBrack3, "", 5, 1, x, y + height * RotateScale3D.MATRIX_ELEM_HEIGHT , "left","center");
+
+ this.cmd("CreateRectangle", mat.rightBrack1, "", 5, 1, x + width * RotateScale3D.MATRIX_ELEM_WIDTH, y, "right","center");
+ this.cmd("CreateRectangle", mat.rightBrack2, "", 1, height * RotateScale3D.MATRIX_ELEM_HEIGHT, x + width * RotateScale3D.MATRIX_ELEM_WIDTH, y, "center","top");
+ this.cmd("CreateRectangle", mat.rightBrack3, "", 5, 1, x+ width * RotateScale3D.MATRIX_ELEM_WIDTH, y + height * RotateScale3D.MATRIX_ELEM_HEIGHT , "right","center");
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("CreateLabel", mat.dataID[i][j], mat.data[i][j],
+ x + j*RotateScale3D.MATRIX_ELEM_WIDTH + RotateScale3D.MATRIX_ELEM_WIDTH / 2,
+ y + i*RotateScale3D.MATRIX_ELEM_HEIGHT + RotateScale3D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ return mat;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new RotateScale3D(animManag, canvas.width, canvas.height);
+}
+
+function Matrix(contents, x, y)
+{
+ this.data = contents;
+ this.x = x;
+ this.y = y;
+}
+
+Matrix.prototype.transpose = function()
+{
+ var newData = new Array(this.data[0].length);
+ var i,j;
+ for (i = 0; i < this.data[0].length; i++)
+ {
+ newData[i] = new Array(this.data.length);
+ }
+ for (i = 0; i < this.data.length; i++)
+ {
+ for (j = 0; j < this.data[i].length; j++)
+ {
+ newData[j][i] = this.data[i][j];
+ }
+ }
+ this.data = newData;
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateTranslate2D.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateTranslate2D.js
new file mode 100644
index 0000000..a362b44
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/RotateTranslate2D.js
@@ -0,0 +1,956 @@
+// 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
+
+
+
+function RotateTranslate2D(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+RotateTranslate2D.prototype = new Algorithm();
+RotateTranslate2D.prototype.constructor = RotateTranslate2D;
+RotateTranslate2D.superclass = Algorithm.prototype;
+
+RotateTranslate2D.XAxisYPos = 300;
+RotateTranslate2D.XAxisStart = 100;
+RotateTranslate2D.XAxisEnd = 700;
+
+RotateTranslate2D.MATRIX_ELEM_WIDTH = 50;
+RotateTranslate2D.MATRIX_ELEM_HEIGHT = 20;
+
+
+RotateTranslate2D.MATRIX_MULTIPLY_SPACING = 10;
+RotateTranslate2D.EQUALS_SPACING = 30;
+RotateTranslate2D.MATRIX_START_X = 10 + 3 * RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_MULTIPLY_SPACING;
+RotateTranslate2D.MATRIX_START_Y = 10;
+
+
+
+RotateTranslate2D.YAxisXPos = 400;
+RotateTranslate2D.YAxisStart = 100;
+RotateTranslate2D.YAxisEnd = 500;
+
+
+RotateTranslate2D.OBJECTS = [
+ [[100, 100], [-100, 100], [-100,-100], [100, -100]], // Square
+ [[10, 100], [-10, 100], [-10,-100], [100, -100], [100, -80], [10,-80]], // L
+ [[0, 141], [-134, 44], [-83, -114 ], [83, -114], [134,44]], // Pentagon
+ [[0, 141], [-35,48],[-134, 44], [-57, -19], [-83, -114 ], [0, -60],[83,-114], [57, -19], [134,44], [35, 48]], // Star
+ ]
+
+
+RotateTranslate2D.AXIS_COLOR = "#9999FF"
+
+RotateTranslate2D.LOCAL_VERTEX_FOREGORUND_COLOR = "#000000";
+RotateTranslate2D.LOCAL_VERTEX_BACKGROUND_COLOR = RotateTranslate2D.LOCAL_VERTEX_FOREGORUND_COLOR;
+RotateTranslate2D.LOCAL_EDGE_COLOR = "#000000";
+
+RotateTranslate2D.GLOBAL_VERTEX_FOREGORUND_COLOR = "#00FF00";
+RotateTranslate2D.GLOBAL_VERTEX_BACKGROUND_COLOR = RotateTranslate2D.GLOBAL_VERTEX_FOREGORUND_COLOR;
+RotateTranslate2D.GLOBAL_EDGE_COLOR = "#00FF00";
+
+
+
+RotateTranslate2D.TRANSFORMED_VERTEX_FOREGORUND_COLOR = "#66FF66";
+RotateTranslate2D.TRANSFORMED_VERTEX_BACKGROUND_COLOR = RotateTranslate2D.TRANSFORMED_VERTEX_FOREGORUND_COLOR;
+RotateTranslate2D.TRANSFORMED_EDGE_COLOR = "#66FF66";
+
+
+
+
+RotateTranslate2D.VECTOR_COLOR = "#FF0000";
+
+RotateTranslate2D.VERTEX_WIDTH = 3;
+RotateTranslate2D.VERTEX_HEIGHT = RotateTranslate2D.VERTEX_WIDTH;
+
+RotateTranslate2D.prototype.init = function(am, w, h)
+{
+ var sc = RotateTranslate2D.superclass.init.call(this, am, w, h);
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.addControls();
+ this.currentShape = 0;
+
+ this.commands = [];
+ this.nextIndex = 0;
+
+ this.setupAxis();
+
+
+ this.transformMatrix = this.createMatrix([[1, 0, 0], [ 0, 1, 0], [0, 0, 1]], RotateTranslate2D.MATRIX_START_X, RotateTranslate2D.MATRIX_START_Y);
+
+ this.savedNextIndex = this.nextIndex;
+ this.setupObject();
+ this.setupObjectGraphic();
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.clearHistory();
+
+
+}
+
+RotateTranslate2D.prototype.setupAxis = function()
+{
+ this.xAxisLeft = this.nextIndex++;
+ this.xAxisRight = this.nextIndex++;
+ this.yAxisTop = this.nextIndex++;
+ this.yAxisBottom = this.nextIndex++;
+
+ this.xAxisLabel = this.nextIndex++;
+ this.yAxisLabel = this.nextIndex++;
+
+ this.originID = this.nextIndex++;
+
+ this.cmd("CreateRectangle", this.originID, "", 0, 0, RotateTranslate2D.YAxisXPos, RotateTranslate2D.XAxisYPos);
+
+
+ this.cmd("CreateRectangle", this.xAxisLeft, "", 0, 0, RotateTranslate2D.XAxisStart, RotateTranslate2D.XAxisYPos);
+ this.cmd("SetAlpha", this.xAxisLeft, 0);
+ this.cmd("CreateRectangle", this.xAxisRight, "", 0, 0, RotateTranslate2D.XAxisEnd, RotateTranslate2D.XAxisYPos);
+ this.cmd("SetAlpha", this.xAxisRight, 0);
+ this.cmd("Connect", this.xAxisLeft, this.xAxisRight, RotateTranslate2D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.xAxisRight, this.xAxisLeft, RotateTranslate2D.AXIS_COLOR, 0, 1, "");
+
+
+ this.cmd("CreateRectangle", this.yAxisTop, "", 0, 0, RotateTranslate2D.YAxisXPos, RotateTranslate2D.YAxisStart);
+ this.cmd("SetAlpha", this.yAxisTop, 0);
+ this.cmd("CreateRectangle", this.yAxisBottom, "", 0, 0, RotateTranslate2D.YAxisXPos, RotateTranslate2D.YAxisEnd);
+ this.cmd("SetAlpha", this.yAxisBottom, 0);
+ this.cmd("Connect", this.yAxisTop, this.yAxisBottom, RotateTranslate2D.AXIS_COLOR, 0, 1, "");
+ this.cmd("Connect", this.yAxisBottom, this.yAxisTop, RotateTranslate2D.AXIS_COLOR, 0, 1, "");
+ if (this.posYUp)
+ {
+ this.cmd("CreateLabel", this.yAxisLabel, "+y", RotateTranslate2D.YAxisXPos + 10, RotateTranslate2D.YAxisStart + 10);
+ }
+ else
+ {
+ this.cmd("CreateLabel", this.yAxisLabel, "+y", RotateTranslate2D.YAxisXPos + 10, RotateTranslate2D.YAxisEnd - 10);
+ }
+ this.cmd("CreateLabel", this.xAxisLabel, "+x", RotateTranslate2D.XAxisEnd - 10, RotateTranslate2D.XAxisYPos - 10);
+ this.cmd("SetForegroundColor", this.yAxisLabel, RotateTranslate2D.AXIS_COLOR);
+ this.cmd("SetForegroundColor", this.xAxisLabel, RotateTranslate2D.AXIS_COLOR);
+}
+
+
+RotateTranslate2D.prototype.setupObject = function()
+{
+ var i = 0;
+ this.objectVertexLocalPosition = new Array(RotateTranslate2D.OBJECTS[this.currentShape].length);
+ this.objectVertexWorldPosition = new Array(RotateTranslate2D.OBJECTS[this.currentShape].length);
+ for (i = 0; i < RotateTranslate2D.OBJECTS[this.currentShape].length; i++)
+ {
+ this.objectVertexLocalPosition[i] = RotateTranslate2D.OBJECTS[this.currentShape][i].slice(0)
+ this.objectVertexWorldPosition[i] = RotateTranslate2D.OBJECTS[this.currentShape][i].slice(0);
+
+ }
+}
+
+
+RotateTranslate2D.prototype.worldToScreenSpace = function(point)
+{
+ var transformedPoint = new Array(2);
+ transformedPoint[0] = point[0] + RotateTranslate2D.YAxisXPos;
+ if (this.posYUp)
+ {
+ transformedPoint[1] = RotateTranslate2D.XAxisYPos - point[1];
+ }
+ else
+ {
+ transformedPoint[1] = RotateTranslate2D.XAxisYPos + point[1];
+
+ }
+ return transformedPoint;
+}
+
+
+
+
+
+
+
+
+RotateTranslate2D.prototype.setupObjectGraphic = function()
+{
+ var i;
+
+ this.objectVertexLocalID = new Array(this.objectVertexLocalPosition.length);
+ this.objectVertexWorldID = new Array(this.objectVertexWorldPosition.length);
+ for (i= 0; i < this.objectVertexLocalPosition.length; i++)
+ {
+ this.objectVertexLocalID[i] = this.nextIndex++;
+ }
+ for (i= 0; i < this.objectVertexWorldPosition.length; i++)
+ {
+ this.objectVertexWorldID[i] = this.nextIndex++;
+ }
+
+
+ var point = this.worldToScreenSpace(this.objectVertexLocalPosition[0])
+ var xLocal = point[0];
+ var yLocal = point[1];
+ point = this.worldToScreenSpace(this.objectVertexWorldPosition[0])
+ var xGlobal = point[0];
+ var yGlobal = point[1];
+
+ for (i = 0; i < this.objectVertexLocalPosition.length; i++)
+ {
+ point = this.worldToScreenSpace(this.objectVertexLocalPosition[i]);
+
+ xLocal = Math.min(xLocal, point[0]);
+ yLocal = Math.max(yLocal, point[1]);
+
+
+ this.cmd("CreateRectangle", this.objectVertexLocalID[i], "", RotateTranslate2D.VERTEX_WIDTH, RotateTranslate2D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", this.objectVertexLocalID[i], RotateTranslate2D.LOCAL_VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", this.objectVertexLocalID[i], RotateTranslate2D.LOCAL_VERTEX_BACKGROUND_COLOR);
+
+
+
+ point = this.worldToScreenSpace(this.objectVertexWorldPosition[i]);
+
+ xGlobal = Math.min(xGlobal, point[0]);
+ yGlobal = Math.min(yGlobal, point[1]);
+
+ this.cmd("CreateRectangle", this.objectVertexWorldID[i], "", RotateTranslate2D.VERTEX_WIDTH, RotateTranslate2D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", this.objectVertexWorldID[i], RotateTranslate2D.GLOBAL_VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", this.objectVertexWorldID[i], RotateTranslate2D.GLOBAL_VERTEX_BACKGROUND_COLOR);
+
+ }
+ for (i = 1; i < this.objectVertexLocalID.length; i++)
+ {
+ this.cmd("Connect", this.objectVertexLocalID[i-1], this.objectVertexLocalID[i], RotateTranslate2D.LOCAL_EDGE_COLOR, 0, 0, "");
+ this.cmd("Connect", this.objectVertexWorldID[i-1], this.objectVertexWorldID[i], RotateTranslate2D.GLOBAL_EDGE_COLOR, 0, 0, "");
+ }
+ this.cmd("Connect", this.objectVertexLocalID[this.objectVertexLocalID.length - 1], this.objectVertexLocalID[0], RotateTranslate2D.LOCAL_EDGE_COLOR, 0, 0, "");
+ this.cmd("Connect", this.objectVertexWorldID[this.objectVertexWorldID.length - 1], this.objectVertexWorldID[0], RotateTranslate2D.GLOBAL_EDGE_COLOR, 0, 0, "");
+ this.localLabelID = this.nextIndex++;
+ this.globalLabelID = this.nextIndex++;
+
+
+ this.cmd("CreateLabel", this.localLabelID, "Local Space", xLocal, yLocal + 2, 0);
+ this.cmd("SetForegroundColor", this.localLabelID, RotateTranslate2D.LOCAL_VERTEX_FOREGORUND_COLOR);
+
+ labelPos = this.worldToScreenSpace([xGlobal, yGlobal]);
+
+ this.cmd("CreateLabel", this.globalLabelID, "World Space", xGlobal, yGlobal - 12, 0);
+ this.cmd("SetForegroundColor", this.globalLabelID, RotateTranslate2D.GLOBAL_VERTEX_FOREGORUND_COLOR);
+
+
+
+}
+
+RotateTranslate2D.prototype.addControls = function()
+{
+ this.controls = [];
+
+ addLabelToAlgorithmBar("Rotation Angle");
+
+ this.rotationField = addControlToAlgorithmBar("Text", "");
+ this.rotationField.onkeydown = this.returnSubmitFloat(this.rotationField, this.transformCallback.bind(this), 4, true);
+ this.controls.push(this.rotationField);
+
+ addLabelToAlgorithmBar("Translate X");
+
+ this.scaleXField = addControlToAlgorithmBar("Text", "");
+ this.scaleXField.onkeydown = this.returnSubmitFloat(this.scaleXField, this.transformCallback.bind(this), 4, true);
+ this.controls.push(this.scaleXField);
+
+
+ addLabelToAlgorithmBar("Translate Y");
+
+ this.scaleYField = addControlToAlgorithmBar("Text", "");
+ this.scaleYField.onkeydown = this.returnSubmitFloat(this.scaleYField, this.transformCallback.bind(this), 4, true);
+ this.controls.push(this.scaleYField);
+
+
+ var transformButton = addControlToAlgorithmBar("Button", "Transform");
+ transformButton.onclick = this.transformCallback.bind(this);
+
+ this.controls.push(transformButton);
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Row Major",
+ "Column Major",
+ ],
+ "RankType");
+ this.rowMajorButton = radioButtonList[0];
+ this.rowMajorButton.onclick = this.changeRowColMajorCallback.bind(this, true);
+ this.controls.push(this.rowMajorButton);
+
+ this.colMajorButton = radioButtonList[1];
+ this.colMajorButton.onclick = this.changeRowColMajorCallback.bind(this, false);
+ this.controls.push(this.colMajorButton);
+
+ this.rowMajorButton.checked = this.rowMajor;
+ this.colMajorButton.checked = !this.rowMajor;
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["+y Up",
+ "+y Down",
+ ],
+ "yAxisDirection");
+ this.posYUpButton = radioButtonList[0];
+ this.posYUpButton.onclick = this.changePosYCallback.bind(this, true);
+ this.controls.push(this.posYUpButton);
+
+ this.posYDownButton = radioButtonList[1];
+ this.posYDownButton.onclick = this.changePosYCallback.bind(this, false);
+ this.controls.push(this.posYDownButton);
+
+ this.posYUpButton.checked = this.posYUp;
+ this.posYDownButton.checked = !this.posYUp;
+
+
+ var changeShapeButton = addControlToAlgorithmBar("Button", "Change Shape");
+ changeShapeButton.onclick = this.changeShapeCallback.bind(this);
+
+ this.controls.push(changeShapeButton);
+
+}
+
+
+
+
+
+
+RotateTranslate2D.prototype.reset = function()
+{
+ this.rowMajor = true;
+ this.posYUp = true;
+ this.rotateFirst = true;
+ this.currentShape = 0;
+ this.rowMajorButton.checked = this.rowMajor;
+ this.posYUpButton.checked = this.posYUp;
+ this.transformMatrix.data = [[1,0,0],[0,1,0],[0,0,1]];
+ this.nextIndex = this.savedNextIndex;
+ this.setupObject();
+ this.setupObjectGraphic();
+}
+
+
+RotateTranslate2D.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+RotateTranslate2D.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+RotateTranslate2D.prototype.changePosYCallback = function(posYUp)
+{
+ if (this.posYUp != posYUp)
+ {
+ this.implementAction(this.changePosY.bind(this), posYUp);
+ }
+}
+
+RotateTranslate2D.prototype.changePosY = function(posYUp)
+{
+ this.commands = new Array();
+ this.posYUp= posYUp;
+ if (this.posYUpButton.checked != this.posYUp)
+ {
+ this.posYUpButton.checked = this.posYUp;
+ }
+ if (this.posYDownButton.checked == this.posYUp)
+ {
+ this.posYDownButton.checked = !this.posYUp;
+ }
+ if (this.posYUp)
+ {
+ this.cmd("Move", this.yAxisLabel, RotateTranslate2D.YAxisXPos + 10, RotateTranslate2D.YAxisStart + 10);
+ }
+ else
+ {
+ this.cmd("Move", this.yAxisLabel, RotateTranslate2D.YAxisXPos + 10, RotateTranslate2D.YAxisEnd - 10);
+
+ }
+
+ this.moveObjectToNewPosition(this.objectVertexLocalPosition, this.objectVertexLocalID, this.localLabelID, false);
+ this.moveObjectToNewPosition(this.objectVertexWorldPosition, this.objectVertexWorldID, this.globalLabelID, true);
+
+
+ return this.commands;
+}
+
+
+RotateTranslate2D.prototype.moveObjectToNewPosition = function(objectLocations, objectIDs, labelID, top)
+{
+ var point = this.worldToScreenSpace(objectLocations[0])
+ var labelX = point[0];
+ var labelY = point[1];
+
+ for (var i = 0; i < objectLocations.length; i++)
+ {
+ point = this.worldToScreenSpace(objectLocations[i]);
+ this.cmd("Move", objectIDs[i], point[0], point[1]);
+
+ labelX = Math.min(labelX, point[0]);
+ if (top)
+ {
+ labelY = Math.min(labelY, point[1]);
+ }
+ else
+ {
+ labelY = Math.max(labelY, point[1]);
+
+ }
+ }
+ if (top)
+ {
+ this.cmd("Move", labelID, labelX, labelY - 12);
+ }
+ else
+ {
+ this.cmd("Move", labelID, labelX, labelY + 2);
+ }
+}
+
+RotateTranslate2D.prototype.changeRowColMajorCallback = function(rowMajor)
+{
+ if (this.rowMajor != rowMajor)
+ {
+ this.implementAction(this.changeRowCol.bind(this), rowMajor);
+ }
+}
+
+RotateTranslate2D.prototype.changeRowCol = function(rowMajor)
+{
+ this.commands = new Array();
+ this.rowMajor= rowMajor;
+ if (this.rowMajorButton.checked != this.rowMajor)
+ {
+ this.rowMajorButton.checked = this.rowMajor;
+ }
+ if (this.colMajorButton.checked == this.rowMajor)
+ {
+ this.colMajorButton.checked = !this.rowMajor;
+ }
+
+ this.transformMatrix.transpose();
+ this.resetMatrixLabels(this.transformMatrix);
+
+
+ return this.commands;
+}
+
+
+RotateTranslate2D.prototype.fixNumber = function(value, defaultVal)
+{
+ if (value == "" || value == "-" || value == "." || value == "-." || isNaN(parseFloat(value)))
+ {
+ value = defaultVal;
+ }
+ else
+ {
+ value = String(parseFloat(value));
+ }
+ return value
+}
+
+RotateTranslate2D.prototype.transformCallback = function()
+{
+
+
+ this.rotationField.value = this.fixNumber(this.rotationField.value, "0");
+ this.scaleXField.value = this.fixNumber(this.scaleXField.value, "0");
+ this.scaleYField.value = this.fixNumber(this.scaleYField.value, "0");
+ this.implementAction(this.transform.bind(this), this.rotationField.value + ";" + this.scaleXField.value + ";" + this.scaleYField.value);
+
+}
+
+
+RotateTranslate2D.prototype.changeShapeCallback = function()
+{
+ this.implementAction(this.changeShape.bind(this), 0);
+}
+
+RotateTranslate2D.prototype.changeShape = function()
+{
+ this.commands = [];
+ var i;
+ for (i = 0; i < this.objectVertexLocalID.length; i++)
+ {
+ this.cmd("Delete", this.objectVertexLocalID[i]);
+ this.cmd("Delete", this.objectVertexWorldID[i]);
+ }
+ this.cmd("Delete", this.localLabelID);
+ this.cmd("Delete", this.globalLabelID);
+ this.currentShape++;
+ if (this.currentShape >= RotateTranslate2D.OBJECTS.length)
+ {
+ this.currentShape = 0;
+ }
+ this.transformMatrix.data = [[1,0,0],[0,1,0],[0,0,1]];
+ this.resetMatrixLabels(this.transformMatrix);
+ this.setupObject();
+ this.setupObjectGraphic();
+ return this.commands;
+}
+
+
+function toRadians(degrees)
+{
+ return (degrees * 2 * Math.PI) / 360.0;
+}
+
+RotateTranslate2D.prototype.transform = function(input)
+{
+ this.commands = [];
+
+ var inputs = input.split(";");
+ var rotateDegree = parseFloat(inputs[0]);
+ var deltaX = parseFloat(inputs[1]);
+ var deltaY = parseFloat(inputs[2]);
+ var rotateRadians = toRadians(rotateDegree);
+
+
+ var deltaMatrix;
+ if (this.rowMajor)
+ {
+ deltaMatrix = this.createMatrix([["cos \u0398", "sin \u0398", 0], ["-sin \u0398", "cos \u0398", 0],["\u0394x", "\u0394y", "1"]],
+ RotateTranslate2D.MATRIX_START_X +3 * RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_MULTIPLY_SPACING,
+ RotateTranslate2D.MATRIX_START_Y);
+ }
+ else
+ {
+ deltaMatrix = this.createMatrix([["cos \u0398", "-sin \u0398", "\u0394x"], ["sin \u0398", "cos \u0398", "\u0394y"],[0, 0, 1]],
+ RotateTranslate2D.MATRIX_START_X -3 * RotateTranslate2D.MATRIX_ELEM_WIDTH - RotateTranslate2D.MATRIX_MULTIPLY_SPACING,
+ RotateTranslate2D.MATRIX_START_Y);
+ }
+ this.cmd("Step");
+
+ if (this.rowMajor)
+ {
+ deltaMatrix.data = [["cos " + inputs[0], "sin " + inputs[0], 0], ["-sin " + inputs[0], "cos " + inputs[0], 0],["\u0394x", "\u0394y", "1"]]
+ }
+ else
+ {
+ deltaMatrix.data = [["cos " + inputs[0], "-sin " + inputs[0], "\u0394 x"], ["sin " + inputs[0], "cos " + inputs[0], "\u0394y"],[0, 0, 1]];
+ }
+ this.resetMatrixLabels(deltaMatrix);
+ this.cmd("Step");
+
+ if (this.rowMajor)
+ {
+ deltaMatrix.data = [[Math.cos(rotateRadians), Math.sin(rotateRadians), 0], [-Math.sin(rotateRadians), Math.cos(rotateRadians), 0],[deltaX, deltaY, 1]]
+ }
+ else
+ {
+ deltaMatrix.data = [[Math.cos(rotateRadians), -Math.sin(rotateRadians), deltaX], [Math.sin(rotateRadians), Math.cos(rotateRadians), deltaY],[0,0, 1]]
+ }
+ this.resetMatrixLabels(deltaMatrix);
+ this.cmd("Step");
+
+ var equalLabel = this.nextIndex++;
+ var resultMatrix;
+ var explainID = this.nextIndex++;
+ var resultXPos;
+
+ if (this.rowMajor)
+ {
+ resultXPos = RotateTranslate2D.MATRIX_START_X +6 * RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_MULTIPLY_SPACING;
+ }
+ else
+ {
+ resultXPos = RotateTranslate2D.MATRIX_START_X +3 * RotateTranslate2D.MATRIX_ELEM_WIDTH;
+ }
+ resultMatrix = this.createMatrix([["", "", ""],["", "", ""],["", "", ""]],
+ resultXPos + RotateTranslate2D.EQUALS_SPACING,
+ RotateTranslate2D.MATRIX_START_Y);
+ this.cmd("CreateLabel", equalLabel, "=", resultXPos + RotateTranslate2D.EQUALS_SPACING / 2,
+ RotateTranslate2D.MATRIX_START_Y + 1.5 * RotateTranslate2D.MATRIX_ELEM_HEIGHT);
+
+ this.cmd("CreateLabel", explainID, "", resultXPos + RotateTranslate2D.EQUALS_SPACING, RotateTranslate2D.MATRIX_START_Y + 3 * RotateTranslate2D.MATRIX_ELEM_HEIGHT + 5, 0);
+
+
+ this.cmd("Step"); // TODO: Remove this?
+ if (this.rowMajor)
+ {
+ this.multiplyMatrix(this.transformMatrix, deltaMatrix, resultMatrix, explainID);
+ }
+ else
+ {
+ this.multiplyMatrix(deltaMatrix, this.transformMatrix, resultMatrix, explainID);
+ }
+
+ this.setMatrixAlpha(this.transformMatrix, 0);
+ this.transformMatrix.data = resultMatrix.data;
+ this.resetMatrixLabels(this.transformMatrix);
+ this.moveMatrix(resultMatrix, RotateTranslate2D.MATRIX_START_X, RotateTranslate2D.MATRIX_START_Y);
+ this.deleteMatrix(deltaMatrix);
+ this.cmd("Delete", equalLabel);
+ this.cmd("SetText", explainID, "");
+ this.cmd("Step");
+ this.deleteMatrix(resultMatrix);
+ this.setMatrixAlpha(this.transformMatrix, 1);
+ var i;
+
+ var transformedObjectID = new Array(this.objectVertexLocalPosition.length);
+
+ var xy;
+
+ if (this.rowMajor)
+ {
+ xy = this.createMatrix([["x", "y", 1]], RotateTranslate2D.MATRIX_START_X - 3 * RotateTranslate2D.MATRIX_ELEM_WIDTH - RotateTranslate2D.MATRIX_MULTIPLY_SPACING,
+ RotateTranslate2D.MATRIX_START_Y);
+ }
+ else
+ {
+ xy = this.createMatrix([["x"], ["y"], [1]], RotateTranslate2D.MATRIX_START_X + 3 * RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_MULTIPLY_SPACING,
+ RotateTranslate2D.MATRIX_START_Y);
+
+ }
+ this.cmd("Step");
+ var equalX;
+ var equalY;
+
+ if (this.rowMajor)
+ {
+ equalX = RotateTranslate2D.MATRIX_START_X + 3*RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.EQUALS_SPACING / 2;
+ equalY = RotateTranslate2D.MATRIX_START_Y + 0.5 * RotateTranslate2D.MATRIX_ELEM_HEIGHT;
+ this.cmd("SetPosition", explainID, equalX + RotateTranslate2D.EQUALS_SPACING / 2, RotateTranslate2D.MATRIX_START_Y + RotateTranslate2D.MATRIX_ELEM_HEIGHT + 10);
+ }
+ else
+ {
+ equalX = RotateTranslate2D.MATRIX_START_X + 4*RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_MULTIPLY_SPACING + RotateTranslate2D.EQUALS_SPACING / 2;
+ equalY = RotateTranslate2D.MATRIX_START_Y + 1.5 * RotateTranslate2D.MATRIX_ELEM_HEIGHT;
+ this.cmd("SetPosition", explainID, equalX + RotateTranslate2D.EQUALS_SPACING / 2, RotateTranslate2D.MATRIX_START_Y + 3 * RotateTranslate2D.MATRIX_ELEM_HEIGHT + 10);
+ }
+ for (i = 0; i < this.objectVertexLocalPosition.length; i++)
+ {
+ this.cmd("Connect", this.originID, this.objectVertexLocalID[i], RotateTranslate2D.VECTOR_COLOR, 0, 1, "");
+ if (this.rowMajor)
+ {
+ xy.data[0][0] = this.objectVertexLocalPosition[i][0];
+ xy.data[0][1] = this.objectVertexLocalPosition[i][1];
+ xy.data[0][2] = 1;
+ }
+ else
+ {
+ xy.data[0][0] = this.objectVertexLocalPosition[i][0];
+ xy.data[1][0] = this.objectVertexLocalPosition[i][1];
+ xy.data[2][0] = 1;
+ }
+ this.resetMatrixLabels(xy);
+ this.cmd("Step");
+
+ this.cmd("CreateLabel", equalLabel, "=", equalX, equalY);
+ if (this.rowMajor)
+ {
+ output = this.createMatrix([["","", ""]], equalX + RotateTranslate2D.EQUALS_SPACING / 2, RotateTranslate2D.MATRIX_START_Y);
+ this.multiplyMatrix(xy, this.transformMatrix, output, explainID);
+ }
+ else
+ {
+ output = this.createMatrix([[""],[""], [""]], equalX + RotateTranslate2D.EQUALS_SPACING / 2, RotateTranslate2D.MATRIX_START_Y)
+ this.multiplyMatrix(this.transformMatrix, xy, output, explainID);
+ }
+
+ transformedObjectID[i] = this.nextIndex++;
+ var point;
+ if (this.rowMajor)
+ {
+ point = this.worldToScreenSpace([output.data[0][0], output.data[0][1]]);
+ }
+ else
+ {
+ point = this.worldToScreenSpace([output.data[0][0], output.data[1][0]]);
+ }
+
+ this.cmd("CreateRectangle", transformedObjectID[i], "", RotateTranslate2D.VERTEX_WIDTH, RotateTranslate2D.VERTEX_HEIGHT, point[0], point[1]);
+ this.cmd("SetForegroundColor", transformedObjectID[i], RotateTranslate2D.TRANSFORMED_VERTEX_FOREGORUND_COLOR);
+ this.cmd("SetBackgroundColor", transformedObjectID[i], RotateTranslate2D.TRANSFORMED_VERTEX_BACKGROUND_COLOR);
+ this.cmd("Connect", this.originID, transformedObjectID[i], RotateTranslate2D.TRANSFORMED_EDGE_COLOR, 0, 1, "");
+ this.cmd("Step");
+ this.cmd("Disconnect", this.originID, transformedObjectID[i]);
+
+ if (i > 0)
+ {
+ this.cmd("Connect", transformedObjectID[i-1], transformedObjectID[i], RotateTranslate2D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+ }
+
+ this.cmd("Disconnect", this.originID, this.objectVertexLocalID[i]);
+ if (this.rowMajor)
+ {
+ this.objectVertexWorldPosition[i][0] = output.data[0][0];
+ this.objectVertexWorldPosition[i][1] = output.data[0][1];
+ }
+ else
+ {
+ this.objectVertexWorldPosition[i][0] = output.data[0][0];
+ this.objectVertexWorldPosition[i][1] = output.data[1][0];
+ }
+ this.cmd("Delete", equalLabel);
+ this.deleteMatrix(output);
+ }
+ this.cmd("Step");
+ this.cmd("Connect", transformedObjectID[transformedObjectID.length-1], transformedObjectID[0], RotateTranslate2D.TRANSFORMED_EDGE_COLOR, 0, 0, "");
+
+ this.cmd("Step","B");
+ this.moveObjectToNewPosition(this.objectVertexWorldPosition, this.objectVertexWorldID, this.globalLabelID, true);
+ this.cmd("Step");
+
+ for (i = 0; i < transformedObjectID.length; i++)
+ {
+ this.cmd("Delete", transformedObjectID[i]);
+ }
+
+
+ this.deleteMatrix(xy);
+ return this.commands;
+}
+
+
+RotateTranslate2D.prototype.multiplyMatrix = function(mat1, mat2, mat3, explainID)
+{
+ var i;
+ var j;
+ var explainText = "";
+ for (i = 0; i < mat1.data.length; i++)
+ {
+ for (j = 0; j < mat2.data[0].length; j++)
+ {
+ var explainText = "";
+ var value = 0;
+ for (k = 0; k < mat2.data.length; k++)
+ {
+ this.cmd("SetHighlight", mat1.dataID[i][k], 1);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 1);
+ if (explainText != "")
+ {
+ explainText = explainText + " + ";
+ }
+ value = value + mat1.data[i][k] * mat2.data[k][j];
+ explainText = explainText + String(mat1.data[i][k]) + " * " + String(mat2.data[k][j]);
+ this.cmd("SetText", explainID, explainText);
+ this.cmd("Step");
+ this.cmd("SetHighlight", mat1.dataID[i][k], 0);
+ this.cmd("SetHighlight", mat2.dataID[k][j], 0);
+ }
+ value = this.standardize(value);
+ explainText += " = " + String(value);
+ this.cmd("SetText", explainID, explainText);
+ mat3.data[i][j] = value;
+ this.cmd("SetText", mat3.dataID[i][j], value);
+ this.cmd("Step");
+ }
+ }
+ this.cmd("SetText", explainID, "");
+
+
+}
+
+RotateTranslate2D.prototype.standardize = function(lab)
+{
+ var newLab = Math.round(lab * 1000) / 1000;
+ if (isNaN(newLab))
+ {
+ return lab;
+ }
+ else
+ {
+ return newLab;
+ }
+}
+
+
+RotateTranslate2D.prototype.resetMatrixLabels = function(mat)
+{
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.data[i][j] = this.standardize(mat.data[i][j]);
+ this.cmd("SetText", mat.dataID[i][j], mat.data[i][j]);
+ }
+ }
+}
+
+
+
+RotateTranslate2D.prototype.moveMatrix = function(mat, x, y)
+{
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ }
+
+
+ this.cmd("Move", mat.leftBrack1, x, y);
+ this.cmd("Move", mat.leftBrack2, x, y);
+ this.cmd("Move", mat.leftBrack3, x, y + height * RotateTranslate2D.MATRIX_ELEM_HEIGHT);
+
+ this.cmd("Move", mat.rightBrack1, x + width * RotateTranslate2D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack2, x + width * RotateTranslate2D.MATRIX_ELEM_WIDTH, y);
+ this.cmd("Move", mat.rightBrack3, x+ width * RotateTranslate2D.MATRIX_ELEM_WIDTH, y + height * RotateTranslate2D.MATRIX_ELEM_HEIGHT);
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Move", mat.dataID[i][j],
+ x + j*RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_ELEM_WIDTH / 2,
+ y + i*RotateTranslate2D.MATRIX_ELEM_HEIGHT + RotateTranslate2D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+}
+
+RotateTranslate2D.prototype.deleteMatrix = function(mat)
+{
+ this.cmd("Delete",mat.leftBrack1);
+ this.cmd("Delete",mat.leftBrack2);
+ this.cmd("Delete",mat.leftBrack3);
+ this.cmd("Delete",mat.rightBrack1);
+ this.cmd("Delete",mat.rightBrack2);
+ this.cmd("Delete",mat.rightBrack3);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("Delete", mat.dataID[i][j]);
+ }
+ }
+}
+
+RotateTranslate2D.prototype.setMatrixAlpha = function(mat, alpha)
+{
+ this.cmd("SetAlpha",mat.leftBrack1, alpha);
+ this.cmd("SetAlpha",mat.leftBrack2, alpha);
+ this.cmd("SetAlpha",mat.leftBrack3, alpha);
+ this.cmd("SetAlpha",mat.rightBrack1, alpha);
+ this.cmd("SetAlpha",mat.rightBrack2, alpha);
+ this.cmd("SetAlpha",mat.rightBrack3, alpha);
+ var i,j;
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("SetAlpha", mat.dataID[i][j], alpha);
+ }
+ }
+}
+
+
+RotateTranslate2D.prototype.createMatrix = function(contents, x, y)
+{
+ var mat = new Matrix(contents, x, y);
+ mat.leftBrack1 = this.nextIndex++;
+ mat.leftBrack2 = this.nextIndex++;
+ mat.leftBrack3 = this.nextIndex++;
+ mat.rightBrack1 = this.nextIndex++;
+ mat.rightBrack2 = this.nextIndex++;
+ mat.rightBrack3 = this.nextIndex++;
+
+ var height = mat.data.length;
+ var width = 0;
+
+ var i, j;
+ mat.dataID = new Array(mat.data.length);
+ for (i = 0; i < mat.data.length; i++)
+ {
+ width = Math.max(width, mat.data[i].length);
+ mat.dataID[i] = new Array(mat.data[i].length);
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ mat.dataID[i][j] = this.nextIndex++;
+ }
+ }
+
+ this.cmd("CreateRectangle", mat.leftBrack1, "", 5, 1, x, y, "left","center");
+ this.cmd("CreateRectangle", mat.leftBrack2, "", 1, height * RotateTranslate2D.MATRIX_ELEM_HEIGHT, x, y, "center","top");
+ this.cmd("CreateRectangle", mat.leftBrack3, "", 5, 1, x, y + height * RotateTranslate2D.MATRIX_ELEM_HEIGHT , "left","center");
+
+ this.cmd("CreateRectangle", mat.rightBrack1, "", 5, 1, x + width * RotateTranslate2D.MATRIX_ELEM_WIDTH, y, "right","center");
+ this.cmd("CreateRectangle", mat.rightBrack2, "", 1, height * RotateTranslate2D.MATRIX_ELEM_HEIGHT, x + width * RotateTranslate2D.MATRIX_ELEM_WIDTH, y, "center","top");
+ this.cmd("CreateRectangle", mat.rightBrack3, "", 5, 1, x+ width * RotateTranslate2D.MATRIX_ELEM_WIDTH, y + height * RotateTranslate2D.MATRIX_ELEM_HEIGHT , "right","center");
+
+ for (i = 0; i < mat.data.length; i++)
+ {
+ for (j = 0; j < mat.data[i].length; j++)
+ {
+ this.cmd("CreateLabel", mat.dataID[i][j], mat.data[i][j],
+ x + j*RotateTranslate2D.MATRIX_ELEM_WIDTH + RotateTranslate2D.MATRIX_ELEM_WIDTH / 2,
+ y + i*RotateTranslate2D.MATRIX_ELEM_HEIGHT + RotateTranslate2D.MATRIX_ELEM_HEIGHT / 2);
+ }
+ }
+ return mat;
+}
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new RotateTranslate2D(animManag, canvas.width, canvas.height);
+}
+
+function Matrix(contents, x, y)
+{
+ this.data = contents;
+ this.x = x;
+ this.y = y;
+}
+
+Matrix.prototype.transpose = function()
+{
+ var newData = new Array(this.data[0].length);
+ var i,j;
+ for (i = 0; i < this.data[0].length; i++)
+ {
+ newData[i] = new Array(this.data.length);
+ }
+ for (i = 0; i < this.data.length; i++)
+ {
+ for (j = 0; j < this.data[i].length; j++)
+ {
+ newData[j][i] = this.data[i][j];
+ }
+ }
+ this.data = newData;
+}
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Search.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Search.js
new file mode 100644
index 0000000..8f0e02d
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Search.js
@@ -0,0 +1,734 @@
+// Copyright 2015 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 ``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 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
+
+Search.CODE_START_X = 10;
+Search.CODE_START_Y = 10;
+Search.CODE_LINE_HEIGHT = 14;
+
+
+Search.CODE_HIGHLIGHT_COLOR = "#FF0000";
+Search.CODE_STANDARD_COLOR = "#000000";
+
+var SMALL_SIZE = 0;
+var LARGE_SIZE = 1;
+
+var EXTRA_FIELD_WIDTH = 50;
+var EXTRA_FIELD_HEIGHT = 50;
+
+var SEARCH_FOR_X = 450;
+var SEARCH_FOR_Y = 30;
+
+
+var RESULT_X = 550;
+var RESULT_Y = 30;
+
+
+var INDEX_X = 450;
+var INDEX_Y = 130;
+
+
+var HIGHLIGHT_CIRCLE_SIZE_SMALL = 20;
+var HIGHLIGHT_CIRCLE_SIZE_LARGE = 10;
+var HIGHLIGHT_CIRCLE_SIZE = HIGHLIGHT_CIRCLE_SIZE_SMALL;
+
+
+var LOW_CIRCLE_COLOR = "#1010FF";
+var LOW_BACKGROUND_COLOR = "#F0F0FF";
+var MID_CIRCLE_COLOR = "#118C4E";
+var MID_BACKGROUND_COLOR = "#F0FFF0";
+var HIGH_CIRCLE_COLOR = "#FF9009";
+var HIGH_BACKGROUND_COLOR = "#FFFFF0";
+
+var LOW_POS_X = 350;
+var LOW_POS_Y = 130;
+
+
+var MID_POS_X = 450;
+var MID_POS_Y = 130;
+
+var HIGH_POS_X = 550;
+var HIGH_POS_Y = 130;
+
+
+
+var ARRAY_START_X_SMALL = 100;
+var ARRAY_START_X_LARGE = 100;
+var ARRAY_START_X = ARRAY_START_X_SMALL;
+var ARRAY_START_Y_SMALL = 240;
+var ARRAY_START_Y_LARGE = 200;
+var ARRAY_START_Y = ARRAY_START_Y_SMALL;
+var ARRAY_ELEM_WIDTH_SMALL = 50;
+var ARRAY_ELEM_WIDTH_LARGE = 25;
+var ARRAY_ELEM_WIDTH = ARRAY_ELEM_WIDTH_SMALL;
+
+var ARRAY_ELEM_HEIGHT_SMALL = 50;
+var ARRAY_ELEM_HEIGHT_LARGE = 20;
+var ARRAY_ELEM_HEIGHT = ARRAY_ELEM_HEIGHT_SMALL;
+
+var ARRAY_ELEMS_PER_LINE_SMALL = 16;
+var ARRAY_ELEMS_PER_LINE_LARGE = 30;
+var ARRAY_ELEMS_PER_LINE = ARRAY_ELEMS_PER_LINE_SMALL;
+
+
+var ARRAY_LINE_SPACING_LARGE = 40;
+var ARRAY_LINE_SPACING_SMALL = 130;
+var ARRAY_LINE_SPACING = ARRAY_LINE_SPACING_SMALL;
+
+var SIZE_SMALL = 32;
+var SIZE_LARGE = 180;
+var SIZE = SIZE_SMALL;
+
+function Search(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+Search.prototype = new Algorithm();
+Search.prototype.constructor = Search;
+Search.superclass = Algorithm.prototype;
+
+
+Search.LINEAR_CODE = [ ["def ", "linearSearch(listData, value)"],
+ [" index = 0"],
+ [" while (","index < len(listData)", " and ", "listData[index] < value","):"],
+ [" index++;"],
+ [" if (", "index >= len(listData", " or ", "listData[index] != value", "):"],
+ [" return -1"],
+ [" return index"]];
+Search.BINARY_CODE = [ ["def ", "binarySearch(listData, value)"],
+ [" low = 0"],
+ [" high = len(listData) - 1"],
+ [" while (","low <= high",")"],
+ [" mid = (low + high) / 2"] ,
+ [" if (","listData[mid] == value","):"],
+ [" return mid"],
+ [" elif (","listData[mid] < value",")"],
+ [" low = mid + 1"],
+ [" else:"],
+ [" high = mid - 1"],
+ [" return -1"]]
+
+
+
+Search.prototype.init = function(am, w, h)
+{
+ Search.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.setup();
+ this.initialIndex = this.nextIndex;
+}
+
+
+Search.prototype.addControls = function()
+{
+ this.controls = [];
+ this.searchField = addControlToAlgorithmBar("Text", "");
+ this.searchField.onkeydown = this.returnSubmit(this.searchField, null, 6, true);
+ this.linearSearchButton = addControlToAlgorithmBar("Button", "Linear Search");
+ this.linearSearchButton.onclick = this.linearSearchCallback.bind(this);
+ this.controls.push(this.searchField);
+ this.controls.push(this.linearSearchButton);
+
+
+ this.binarySearchButton = addControlToAlgorithmBar("Button", "Binary Search");
+ this.binarySearchButton.onclick = this.binarySearchCallback.bind(this);
+ this.controls.push(this.binarySearchButton);
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Small", "Large"], "List Size");
+ this.smallListButton = radioButtonList[0];
+ this.smallListButton.onclick = this.smallListCallback.bind(this);
+ this.largeListButton = radioButtonList[1];
+ this.largeListButton.onclick = this.largeListCallback.bind(this);
+ this.smallListButton.checked = true;
+
+}
+
+
+
+Search.prototype.smallListCallback = function (event)
+{
+ if (this.size != SMALL_SIZE)
+ {
+ this.animationManager.resetAll();
+ this.setup_small();
+ }
+}
+
+
+Search.prototype.largeListCallback = function (event)
+{
+ if (this.size != LARGE_SIZE)
+ {
+ this.animationManager.resetAll();
+ this.setup_large();
+ }
+}
+
+
+
+Search.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+Search.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+Search.prototype.getIndexX = function(index) {
+ var xpos = (index % ARRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ return xpos;
+}
+
+
+Search.prototype.getIndexY = function(index) {
+ if (index == -1) {
+ index = 0;
+ }
+ var ypos = Math.floor(index / ARRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y + ARRAY_ELEM_HEIGHT;
+ return ypos;
+}
+
+Search.prototype.setup = function()
+{
+ this.nextIndex = 0;
+
+ this.values = new Array(SIZE);
+ this.arrayData = new Array(SIZE);
+ this.arrayID = new Array(SIZE);
+ this.arrayLabelID = new Array(SIZE);
+ for (var i = 0; i < SIZE; i++)
+ {
+ this.arrayData[i] = Math.floor(1+Math.random()*999);
+ this.arrayID[i]= this.nextIndex++;
+ this.arrayLabelID[i]= this.nextIndex++;
+ }
+
+ for (var i = 1; i < SIZE; i++) {
+ var nxt = this.arrayData[i];
+ var j = i
+ while (j > 0 && this.arrayData[j-1] > nxt) {
+ this.arrayData[j] = this.arrayData[j-1];
+ j = j - 1;
+ }
+ this.arrayData[j] = nxt;
+ }
+
+ this.leftoverLabelID = this.nextIndex++;
+ this.commands = new Array();
+
+
+ for (var i = 0; i < SIZE; i++)
+ {
+ var xLabelpos = this.getIndexX(i);
+ var yLabelpos = this.getIndexY(i);
+ this.cmd("CreateRectangle", this.arrayID[i],this.arrayData[i], ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT,xLabelpos, yLabelpos - ARRAY_ELEM_HEIGHT);
+ this.cmd("CreateLabel",this.arrayLabelID[i], i, xLabelpos, yLabelpos);
+ this.cmd("SetForegroundColor", this.arrayLabelID[i], "#0000FF");
+
+ }
+
+ this.movingLabelID = this.nextIndex++;
+ this.cmd("CreateLabel",this.movingLabelID, "", 0, 0);
+
+ // this.cmd("CreateLabel", this.leftoverLabelID, "", PUSH_LABEL_X, PUSH_LABEL_Y);
+
+
+ this.searchForBoxID = this.nextIndex++;
+ this.searchForBoxLabel = this.nextIndex++;
+ this.cmd("CreateRectangle", this.searchForBoxID, "", EXTRA_FIELD_WIDTH, EXTRA_FIELD_HEIGHT,SEARCH_FOR_X, SEARCH_FOR_Y);
+ this.cmd("CreateLabel", this.searchForBoxLabel, "Seaching For ", SEARCH_FOR_X, SEARCH_FOR_Y);
+ this.cmd("AlignLeft", this.searchForBoxLabel, this.searchForBoxID);
+
+ this.resultBoxID = this.nextIndex++;
+ this.resultBoxLabel = this.nextIndex++;
+ this.resultString = this.nextIndex++;
+ this.cmd("CreateRectangle", this.resultBoxID, "", EXTRA_FIELD_WIDTH, EXTRA_FIELD_HEIGHT,RESULT_X, RESULT_Y);
+ this.cmd("CreateLabel", this.resultBoxLabel, "Result ", RESULT_X, RESULT_Y);
+ this.cmd("CreateLabel", this.resultString, "", RESULT_X, RESULT_Y);
+ this.cmd("AlignLeft", this.resultBoxLabel, this.resultBoxID);
+ this.cmd("AlignRight", this.resultString, this.resultBoxID);
+ this.cmd("SetTextColor", this.resultString, "#FF0000");
+
+
+
+ this.indexBoxID = this.nextIndex++;
+ this.indexBoxLabel = this.nextIndex++;
+ this.cmd("CreateRectangle", this.indexBoxID, "", EXTRA_FIELD_WIDTH, EXTRA_FIELD_HEIGHT,INDEX_X, INDEX_Y);
+ this.cmd("CreateLabel", this.indexBoxLabel, "index ", INDEX_X, INDEX_Y);
+ this.cmd("AlignLeft", this.indexBoxLabel, this.indexBoxID);
+
+
+
+ this.midBoxID = this.nextIndex++;
+ this.midBoxLabel = this.nextIndex++;
+ this.cmd("CreateRectangle", this.midBoxID, "", EXTRA_FIELD_WIDTH, EXTRA_FIELD_HEIGHT,MID_POS_X, MID_POS_Y);
+ this.cmd("CreateLabel", this.midBoxLabel, "mid ", MID_POS_X, MID_POS_Y);
+ this.cmd("AlignLeft", this.midBoxLabel, this.midBoxID);
+ this.cmd("SetForegroundColor", this.midBoxID, MID_CIRCLE_COLOR);
+ this.cmd("SetTextColor", this.midBoxID, MID_CIRCLE_COLOR);
+ this.cmd("SetBackgroundColor", this.midBoxID, MID_BACKGROUND_COLOR);
+
+ this.midCircleID = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", this.midCircleID, MID_CIRCLE_COLOR, 0, 0, HIGHLIGHT_CIRCLE_SIZE);
+
+
+ this.lowBoxID = this.nextIndex++;
+ this.lowBoxLabel = this.nextIndex++;
+ this.cmd("CreateRectangle", this.lowBoxID, "", EXTRA_FIELD_WIDTH, EXTRA_FIELD_HEIGHT,LOW_POS_X, LOW_POS_Y);
+ this.cmd("CreateLabel", this.lowBoxLabel, "low ", LOW_POS_X, LOW_POS_Y);
+ this.cmd("AlignLeft", this.lowBoxLabel, this.lowBoxID);
+ this.cmd("SetForegroundColor", this.lowBoxID, LOW_CIRCLE_COLOR);
+ this.cmd("SetTextColor", this.lowBoxID, LOW_CIRCLE_COLOR);
+ this.cmd("SetBackgroundColor", this.lowBoxID, LOW_BACKGROUND_COLOR);
+
+ this.lowCircleID = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", this.lowCircleID, LOW_CIRCLE_COLOR, 0,0,HIGHLIGHT_CIRCLE_SIZE);
+
+
+
+ this.highBoxID = this.nextIndex++;
+ this.highBoxLabel = this.nextIndex++;
+ this.cmd("CreateRectangle", this.highBoxID, "", EXTRA_FIELD_WIDTH, EXTRA_FIELD_HEIGHT,HIGH_POS_X, HIGH_POS_Y);
+ this.cmd("CreateLabel", this.highBoxLabel, "high ", HIGH_POS_X, HIGH_POS_Y);
+ this.cmd("AlignLeft", this.highBoxLabel, this.highBoxID);
+ this.cmd("SetForegroundColor", this.highBoxID, HIGH_CIRCLE_COLOR);
+ this.cmd("SetTextColor", this.highBoxID, HIGH_CIRCLE_COLOR);
+ this.cmd("SetBackgroundColor", this.highBoxID, HIGH_BACKGROUND_COLOR);
+
+
+ this.highCircleID = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", this.highCircleID, HIGH_CIRCLE_COLOR, 0 , 0, HIGHLIGHT_CIRCLE_SIZE);
+
+
+ this.cmd("SetALpha", this.lowBoxID, 0);
+ this.cmd("SetALpha", this.lowBoxLabel, 0);
+ this.cmd("SetALpha", this.midBoxID, 0);
+ this.cmd("SetALpha", this.midBoxLabel, 0);
+ this.cmd("SetALpha", this.highBoxID, 0);
+ this.cmd("SetALpha", this.highBoxLabel, 0);
+
+ this.cmd("SetALpha", this.midCircleID, 0);
+ this.cmd("SetALpha", this.lowCircleID, 0);
+ this.cmd("SetALpha", this.highCircleID, 0);
+
+ this.cmd("SetALpha", this.indexBoxID, 0);
+ this.cmd("SetALpha", this.indexBoxLabel, 0);
+
+ this.highlight1ID = this.nextIndex++;
+ this.highlight2ID = this.nextIndex++;
+
+ this.binaryCodeID = this.addCodeToCanvasBase(Search.BINARY_CODE, Search.CODE_START_X, Search.CODE_START_Y, Search.CODE_LINE_HEIGHT, Search.CODE_STANDARD_COLOR);
+
+ this.linearCodeID = this.addCodeToCanvasBase(Search.LINEAR_CODE, Search.CODE_START_X, Search.CODE_START_Y, Search.CODE_LINE_HEIGHT, Search.CODE_STANDARD_COLOR);
+
+ this.setCodeAlpha(this.binaryCodeID, 0);
+ this.setCodeAlpha(this.linearCodeID, 0);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+Search.prototype.setup_small = function() {
+
+ HIGHLIGHT_CIRCLE_SIZE = HIGHLIGHT_CIRCLE_SIZE_SMALL;
+ ARRAY_START_X = ARRAY_START_X_SMALL;
+ ARRAY_START_Y = ARRAY_START_Y_SMALL;
+ ARRAY_ELEM_WIDTH = ARRAY_ELEM_WIDTH_SMALL;
+ ARRAY_ELEM_HEIGHT = ARRAY_ELEM_HEIGHT_SMALL;
+ ARRAY_ELEMS_PER_LINE = ARRAY_ELEMS_PER_LINE_SMALL;
+ ARRAY_LINE_SPACING = ARRAY_LINE_SPACING_SMALL;
+ SIZE = SIZE_SMALL;
+ this.size = SMALL_SIZE;
+ this.setup();
+
+}
+
+
+Search.prototype.setup_large = function() {
+
+ HIGHLIGHT_CIRCLE_SIZE = HIGHLIGHT_CIRCLE_SIZE_LARGE;
+ ARRAY_START_X = ARRAY_START_X_LARGE;
+ ARRAY_START_Y = ARRAY_START_Y_LARGE;
+ ARRAY_ELEM_WIDTH = ARRAY_ELEM_WIDTH_LARGE;
+ ARRAY_ELEM_HEIGHT = ARRAY_ELEM_HEIGHT_LARGE;
+ ARRAY_ELEMS_PER_LINE = ARRAY_ELEMS_PER_LINE_LARGE;
+ ARRAY_LINE_SPACING = ARRAY_LINE_SPACING_LARGE;
+ SIZE = SIZE_LARGE;
+ this.size = LARGE_SIZE;
+ this.setup()
+
+}
+
+
+
+
+Search.prototype.linearSearchCallback = function(event)
+{
+ var searchVal = this.searchField.value;
+ this.implementAction(this.linearSearch.bind(this), searchVal);
+}
+
+
+Search.prototype.binarySearchCallback = function(event)
+{
+
+ var searchVal = this.searchField.value;
+ this.implementAction(this.binarySearch.bind(this), searchVal);
+
+}
+
+
+
+Search.prototype.binarySearch = function(searchVal)
+{
+ this.commands = new Array();
+ this.setCodeAlpha(this.binaryCodeID, 1);
+ this.setCodeAlpha(this.linearCodeID, 0);
+
+ this.cmd("SetALpha", this.lowBoxID, 1);
+ this.cmd("SetALpha", this.lowBoxLabel, 1);
+ this.cmd("SetALpha", this.midBoxID, 1);
+ this.cmd("SetALpha", this.midBoxLabel, 1);
+ this.cmd("SetALpha", this.highBoxID, 1);
+ this.cmd("SetALpha", this.highBoxLabel, 1);
+
+ this.cmd("SetAlpha", this.lowCircleID, 1);
+ this.cmd("SetAlpha", this.midCircleID, 1);
+ this.cmd("SetAlpha", this.highCircleID, 1);
+ this.cmd("SetPosition", this.lowCircleID, LOW_POS_X, LOW_POS_Y);
+ this.cmd("SetPosition", this.midCircleID, MID_POS_X, MID_POS_Y);
+ this.cmd("SetPosition", this.highCircleID, HIGH_POS_X, HIGH_POS_Y);
+ this.cmd("SetAlpha", this.indexBoxID, 0);
+ this.cmd("SetAlpha", this.indexBoxLabel, 0);
+
+ this.cmd("SetText", this.resultString, "");
+ this.cmd("SetText", this.resultBoxID, "");
+ this.cmd("SetText", this.movingLabelID, "");
+
+
+ var low = 0;
+ var high = SIZE- 1;
+ this.cmd("Move", this.lowCircleID, this.getIndexX(0), this.getIndexY(0));
+ this.cmd("SetText", this.searchForBoxID, searchVal);
+ this.cmd("SetForegroundColor", this.binaryCodeID[1][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.lowBoxID, 1)
+ this.cmd("SetText", this.lowBoxID, 0)
+ this.cmd("step");
+ this.cmd("SetForegroundColor", this.binaryCodeID[1][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.lowBoxID, 0)
+ this.cmd("SetForegroundColor", this.binaryCodeID[2][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.highBoxID, 1)
+ this.cmd("SetText", this.highBoxID, SIZE-1)
+ this.cmd("Move", this.highCircleID, this.getIndexX(SIZE-1), this.getIndexY(SIZE-1));
+ this.cmd("step");
+ this.cmd("SetForegroundColor", this.binaryCodeID[2][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.highBoxID, 0)
+ var keepGoing = true;
+
+ while (keepGoing) {
+ this.cmd("SetHighlight", this.highBoxID, 1)
+ this.cmd("SetHighlight", this.lowBoxID, 1)
+ this.cmd("SetForegroundColor", this.binaryCodeID[3][1], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("step");
+ this.cmd("SetHighlight", this.highBoxID, 0)
+ this.cmd("SetHighlight", this.lowBoxID, 0)
+ this.cmd("SetForegroundColor", this.binaryCodeID[3][1], Search.CODE_STANDARD_COLOR);
+ if (low > high)
+ {
+ keepGoing = false;
+ } else {
+ var mid = Math.floor((high + low) / 2);
+ this.cmd("SetForegroundColor", this.binaryCodeID[4][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.highBoxID, 1)
+ this.cmd("SetHighlight", this.lowBoxID, 1)
+ this.cmd("SetHighlight", this.midBoxID, 1)
+ this.cmd("SetText", this.midBoxID, mid)
+ this.cmd("Move", this.midCircleID, this.getIndexX(mid), this.getIndexY(mid));
+
+ this.cmd("step");
+ this.cmd("SetForegroundColor", this.binaryCodeID[4][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.midBoxID, 0)
+ this.cmd("SetHighlight", this.highBoxID, 0)
+ this.cmd("SetHighlight", this.lowBoxID, 0)
+ this.cmd("SetHighlight", this.searchForBoxID, 1)
+ this.cmd("SetHighlight", this.arrayID[mid],1);
+ this.cmd("SetForegroundColor", this.binaryCodeID[5][1], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("step");
+ this.cmd("SetHighlight", this.searchForBoxID, 0)
+ this.cmd("SetHighlight", this.arrayID[mid],0);
+ this.cmd("SetForegroundColor", this.binaryCodeID[5][1], Search.CODE_STANDARD_COLOR);
+ if (this.arrayData[mid] == searchVal) {
+// HIGHLIGHT CODE!
+ keepGoing = false;
+
+ }
+ else {
+
+ this.cmd("SetForegroundColor", this.binaryCodeID[7][1], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.searchForBoxID, 1)
+ this.cmd("SetHighlight", this.arrayID[mid],1);
+ this.cmd("step")
+ this.cmd("SetForegroundColor", this.binaryCodeID[7][1], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.searchForBoxID, 0)
+ this.cmd("SetHighlight", this.arrayID[mid],0);
+ if (this.arrayData[mid] < searchVal) {
+ this.cmd("SetForegroundColor", this.binaryCodeID[8][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.lowID,1);
+ this.cmd("SetText", this.lowBoxID,mid+1);
+ this.cmd("Move", this.lowCircleID, this.getIndexX(mid+1), this.getIndexY(mid+1));
+
+ low = mid + 1;
+ for (var i = 0; i < low; i++) {
+ this.cmd("SetAlpha", this.arrayID[i],0.2);
+ }
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.binaryCodeID[8][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.lowBoxID,0);
+ } else {
+ this.cmd("SetForegroundColor", this.binaryCodeID[10][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.highBoxID,1);
+ high = mid - 1;
+ this.cmd("SetText", this.highBoxID,high);
+ this.cmd("Move", this.highCircleID, this.getIndexX(high), this.getIndexY(high));
+
+ for (var i = high + 1; i < SIZE; i++) {
+ this.cmd("SetAlpha", this.arrayID[i],0.2);
+ }
+ this.cmd("Step");
+
+ this.cmd("SetForegroundColor", this.binaryCodeID[10][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.midBoxID,0);
+
+
+ }
+ }
+
+ }
+
+ }
+ if (high < low) {
+ this.cmd("SetText", this.resultString, " Element Not found");
+ this.cmd("SetText", this.resultBoxID, -1);
+ this.cmd("AlignRight", this.resultString, this.resultBoxID);
+ this.cmd("SetForegroundColor", this.binaryCodeID[11][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetForegroundColor", this.binaryCodeID[11][0], Search.CODE_STANDARD_COLOR);
+
+ } else {
+ this.cmd("SetText", this.resultString, " Element found");
+ this.cmd("SetText", this.movingLabelID, mid);
+ this.cmd("SetPosition", this.movingLabelID, this.getIndexX(mid), this.getIndexY(mid));
+
+ this.cmd("Move", this.movingLabelID, RESULT_X, RESULT_Y);
+
+ this.cmd("AlignRight", this.resultString, this.resultBoxID);
+ this.cmd("SetForegroundColor", this.binaryCodeID[6][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetForegroundColor", this.binaryCodeID[6][0], Search.CODE_STANDARD_COLOR);
+
+ }
+
+ for (var i = 0; i < SIZE; i++) {
+ this.cmd("SetAlpha", this.arrayID[i],1);
+ }
+ return this.commands;
+
+
+
+
+}
+
+
+Search.prototype.linearSearch = function(searchVal)
+{
+ this.commands = new Array();
+ this.setCodeAlpha(this.binaryCodeID, 0);
+ this.setCodeAlpha(this.linearCodeID, 1);
+
+ this.cmd("SetALpha", this.lowBoxID, 0);
+ this.cmd("SetALpha", this.lowBoxLabel, 0);
+ this.cmd("SetALpha", this.midBoxID, 0);
+ this.cmd("SetALpha", this.midBoxLabel, 0);
+ this.cmd("SetALpha", this.highBoxID, 0);
+ this.cmd("SetALpha", this.highBoxLabel, 0);
+
+
+ this.cmd("SetAlpha", this.lowCircleID, 1);
+ this.cmd("SetAlpha", this.midCircleID, 0);
+ this.cmd("SetAlpha", this.highCircleID, 0);
+
+ this.cmd("SetPosition", this.lowCircleID, INDEX_X, INDEX_Y);
+
+ this.cmd("SetALpha", this.indexBoxID, 1);
+ this.cmd("SetALpha", this.indexBoxLabel, 1);
+
+ this.cmd("SetText", this.resultString, "");
+ this.cmd("SetText", this.resultBoxID, "");
+ this.cmd("SetText", this.movingLabelID, "");
+
+
+
+ var goOn = true;
+ var nextSearch = 0;
+ this.cmd("SetText", this.searchForBoxID, searchVal);
+ this.cmd("SetForegroundColor", this.linearCodeID[1][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.indexBoxID,1);
+ this.cmd("SetText", this.indexBoxID, "0");
+ this.cmd("Move", this.lowCircleID, this.getIndexX(0), this.getIndexY(0));
+
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[1][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.indexBoxID,0);
+
+
+ var foundIndex = 0
+ while (goOn) {
+ if (foundIndex == SIZE) {
+ this.cmd("SetForegroundColor", this.linearCodeID[2][1], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[2][1], Search.CODE_STANDARD_COLOR);
+ goOn = false;
+
+ } else {
+ this.cmd("SetHighlight", this.arrayID[foundIndex],1);
+ this.cmd("SetHighlight", this.searchForBoxID,1);
+ this.cmd("SetForegroundColor", this.linearCodeID[2][3], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step")
+ this.cmd("SetForegroundColor", this.linearCodeID[2][3], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.arrayID[foundIndex],0);
+ this.cmd("SetHighlight", this.searchForBoxID,0);
+ goOn = this.arrayData[foundIndex] < searchVal
+ if (goOn)
+ {
+ foundIndex++;
+
+ this.cmd("SetForegroundColor", this.linearCodeID[3][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.indexBoxID,1);
+ this.cmd("SetText", this.indexBoxID, foundIndex);
+ this.cmd("Move", this.lowCircleID, this.getIndexX(foundIndex), this.getIndexY(foundIndex));
+
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[3][0], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetHighlight", this.indexBoxID,0);
+ }
+ }
+ }
+ if (foundIndex ==SIZE)
+ {
+ this.cmd("SetForegroundColor", this.linearCodeID[4][1], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[4][1], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[5][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[5][0], Search.CODE_STANDARD_COLOR);
+
+
+ }
+
+ else if (this.arrayData[foundIndex] == searchVal)
+ {
+ this.cmd("SetForegroundColor", this.linearCodeID[4][1], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[4][2], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[4][3], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetHighlight", this.arrayID[foundIndex],1);
+ this.cmd("SetHighlight", this.searchForBoxID,1);
+ this.cmd("Step");
+
+ this.cmd("SetHighlight", this.arrayID[foundIndex],0);
+ this.cmd("SetHighlight", this.searchForBoxID,0);
+
+
+
+ this.cmd("SetForegroundColor", this.linearCodeID[4][1], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[4][2], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[4][3], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[6][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", this.resultString, " Element found");
+ this.cmd("SetText", this.movingLabelID, foundIndex);
+ this.cmd("SetPosition", this.movingLabelID, this.getIndexX(foundIndex), this.getIndexY(foundIndex));
+
+ this.cmd("Move", this.movingLabelID, RESULT_X, RESULT_Y);
+
+ this.cmd("AlignRight", this.resultString, this.resultBoxID);
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[6][0], Search.CODE_STANDARD_COLOR);
+
+
+
+ }
+ else
+ {
+ this.cmd("SetHighlight", this.arrayID[foundIndex],1);
+ this.cmd("SetHighlight", this.searchForBoxID,1);
+ this.cmd("SetForegroundColor", this.linearCodeID[4][3], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.arrayID[foundIndex],0);
+ this.cmd("SetHighlight", this.searchForBoxID,0);
+ this.cmd("SetForegroundColor", this.linearCodeID[4][3], Search.CODE_STANDARD_COLOR);
+ this.cmd("SetForegroundColor", this.linearCodeID[5][0], Search.CODE_HIGHLIGHT_COLOR);
+ this.cmd("SetText", this.resultString, " Element Not found");
+ this.cmd("SetText", this.resultBoxID, -1);
+ this.cmd("AlignRight", this.resultString, this.resultBoxID);
+
+ this.cmd("Step");
+ this.cmd("SetForegroundColor", this.linearCodeID[5][0], Search.CODE_STANDARD_COLOR);
+
+
+
+ }
+ return this.commands;
+
+
+}
+
+
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Search(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SimpleStack.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SimpleStack.js
new file mode 100644
index 0000000..87fe957
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SimpleStack.js
@@ -0,0 +1,200 @@
+// 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 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
+
+
+
+function SimpleStack(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+SimpleStack.prototype = new Algorithm();
+SimpleStack.prototype.constructor = SimpleStack;
+SimpleStack.superclass = Algorithm.prototype;
+
+
+SimpleStack.ELEMENT_WIDTH = 30;
+SimpleStack.ELEMENT_HEIGHT = 30;
+SimpleStack.INSERT_X = 30;
+SimpleStack.INSERT_Y = 30;
+SimpleStack.STARTING_X = 30;
+SimpleStack.STARTING_Y = 100;
+SimpleStack.FOREGROUND_COLOR = "#000055"
+SimpleStack.BACKGROUND_COLOR = "#AAAAFF"
+
+
+SimpleStack.prototype.init = function(am, w, h)
+{
+ // Call the unit function of our "superclass", which adds a couple of
+ // listeners, and sets up the undo stack
+ SimpleStack.superclass.init.call(this, am, w, h);
+
+ this.addControls();
+
+ // Useful for memory management
+ this.nextIndex = 0;
+
+ this.stackID = [];
+ this.stackValues = [];
+
+ this.stackTop = 0;
+}
+
+SimpleStack.prototype.addControls = function()
+{
+ this.controls = [];
+
+
+ this.pushField = addControlToAlgorithmBar("Text", "");
+ this.pushField.onkeydown = this.returnSubmit(this.pushField,
+ this.pushCallback.bind(this), // callback to make when return is pressed
+ 4, // integer, max number of characters allowed in field
+ false); // boolean, true of only digits can be entered.
+ this.controls.push(this.pushField);
+
+ this.pushButton = addControlToAlgorithmBar("Button", "Push");
+ this.pushButton.onclick = this.pushCallback.bind(this);
+ this.controls.push(this.pushButton);
+
+ this.popButton = addControlToAlgorithmBar("Button", "Pop");
+ this.popButton.onclick = this.popCallback.bind(this);
+ this.controls.push(this.popButton);
+}
+
+SimpleStack.prototype.reset = function()
+{
+ // Reset the (very simple) memory manager.
+ // NOTE: If we had added a number of objects to the scene *before* any user
+ // input, then we would want to set this to the appropriate value based
+ // on objects added to the scene before the first user input
+ this.nextIndex = 0;
+
+ // Reset our data structure. (Simple in this case)
+ this.stackTop = 0;
+}
+
+
+SimpleStack.prototype.pushCallback = function()
+{
+ var pushedValue = this.pushField.value;
+
+ if (pushedValue != "")
+ {
+ this.pushField.value = "";
+ this.implementAction(this.push.bind(this), pushedValue);
+ }
+
+}
+
+SimpleStack.prototype.popCallback = function()
+{
+ this.implementAction(this.pop.bind(this), "");
+}
+
+
+SimpleStack.prototype.push = function(pushedValue)
+{
+ this.commands = [];
+
+ this.stackID[this.stackTop] = this.nextIndex++;
+
+ this.cmd("CreateRectangle", this.stackID[this.stackTop],
+ pushedValue,
+ SimpleStack.ELEMENT_WIDTH,
+ SimpleStack.ELEMENT_HEIGHT,
+ SimpleStack.INSERT_X,
+ SimpleStack.INSERT_Y);
+ this.cmd("SetForegroundColor", this.stackID[this.stackTop], SimpleStack.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.stackID[this.stackTop], SimpleStack.BACKGROUND_COLOR);
+ this.cmd("Step");
+ var nextXPos = SimpleStack.STARTING_X + this.stackTop * SimpleStack.ELEMENT_WIDTH;
+ var nextYPos = SimpleStack.STARTING_Y;
+ this.cmd("Move", this.stackID[this.stackTop], nextXPos, nextYPos);
+ this.cmd("Step"); // Not necessary, but not harmful either
+ this.stackTop++;
+ return this.commands;
+}
+
+SimpleStack.prototype.pop = function(unused)
+{
+ this.commands = [];
+
+ if (this.stackTop > 0)
+ {
+ this.stackTop--;
+
+ this.cmd("Move", this.stackID[this.stackTop], SimpleStack.INSERT_X, SimpleStack.INSERT_Y);
+ this.cmd("Step");
+ this.cmd("Delete", this.stackID[this.stackTop]);
+ this.cmd("Step");
+
+ // OPTIONAL: We can do a little better with memory leaks in our own memory manager by
+ // reclaiming this memory. It is recommened that you *NOT* do this unless
+ // you really know what you are doing (memory management leads to tricky bugs!)
+ // *and* you really need to (very long runnning visualizaitons, not common)
+ // Because this is a stack, we can reclaim memory easily. Most of the time, this
+ // is not the case, and can be dangerous.
+ // nextIndex = this.stackID[this.stackTop];
+ }
+ return this.commands;
+}
+
+
+
+
+
+// Called by our superclass when we get an animation started event -- need to wait for the
+// event to finish before we start doing anything
+SimpleStack.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+// Called by our superclass when we get an animation completed event -- we can
+/// now interact again.
+SimpleStack.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+}
+
+////////////////////////////////////////////////////////////
+// Script to start up your function, called from the webapge:
+////////////////////////////////////////////////////////////
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new SimpleStack(animManag, canvas.width, canvas.height);
+
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SkewHeap.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SkewHeap.js
new file mode 100644
index 0000000..cc983ce
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SkewHeap.js
@@ -0,0 +1,512 @@
+// 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 ``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 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
+
+
+
+function SkewHeap(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+SkewHeap.prototype = new Algorithm();
+SkewHeap.prototype.constructor = SkewHeap;
+SkewHeap.superclass = Algorithm.prototype;
+
+SkewHeap.LINK_COLOR = "#007700";
+SkewHeap.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+SkewHeap.FOREGROUND_COLOR = "#007700";
+SkewHeap.BACKGROUND_COLOR = "#EEFFEE";
+
+SkewHeap.WIDTH_DELTA = 50;
+SkewHeap.HEIGHT_DELTA = 50;
+SkewHeap.STARTING_Y = 90;
+
+SkewHeap.INSERT_X = 50;
+SkewHeap.INSERT_Y = 45;
+SkewHeap.BACKGROUND_ALPHA = 0.5;
+
+SkewHeap.MESSAGE_X = 20;
+SkewHeap.MESSAGE_Y = 10;
+
+
+
+SkewHeap.MESSAGE_ID = 0;
+
+SkewHeap.prototype.init = function(am, w, h)
+{
+ SkewHeap.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.treeRoot = null;
+ this.secondaryRoot = null;
+ this.animationManager.setAllLayers([0, 1]);
+ this.nextIndex = 1;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", SkewHeap.MESSAGE_X, SkewHeap.MESSAGE_Y, 0);
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+ this.commands = [];
+}
+
+
+SkewHeap.prototype.addControls = function()
+{
+ this.controls = [];
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.controls.push(this.insertField);
+
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.controls.push(this.insertButton);
+
+ this.removeSmallestButton = addControlToAlgorithmBar("Button", "Remove Smallest");
+ this.removeSmallestButton.onclick = this.removeSmallestCallback.bind(this);
+ this.controls.push(this.removeSmallestButton);
+
+ this.clearHeapButton = addControlToAlgorithmBar("Button", "Clear Heap");
+ this.clearHeapButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearHeapButton);
+
+}
+
+
+
+
+
+SkewHeap.prototype.insertCallback = function(event)
+{
+ var insertedValue;
+
+ insertedValue = this.normalizeNumber(this.insertField.value, 4);
+ if (insertedValue != "")
+ {
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this),insertedValue);
+ }
+}
+
+SkewHeap.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clear.bind(this, ""));
+}
+
+SkewHeap.prototype.clear = function(ignored)
+{
+ this.commands = new Array();
+ this.clearTree(this.treeRoot);
+ this.treeRoot = null;
+ this.nexIndex = 1;
+ return this.commands;
+}
+
+SkewHeap.prototype.clearTree = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.clearTree(tree.left);
+ this.clearTree(tree.right);
+ }
+
+}
+
+SkewHeap.prototype.reset = function()
+{
+ this.treeRoot = null;
+ this.secondaryRoot = null;
+ this.nextIndex = 1;
+}
+
+SkewHeap.prototype.removeSmallestCallback = function(event)
+{
+ this.implementAction(this.removeSmallest.bind(this),"");
+}
+
+
+
+SkewHeap.prototype.removeSmallest = function(dummy)
+{
+
+ this.commands = new Array();
+
+ if (this.treeRoot != null)
+ {
+ this.highlightLeft = this.nextIndex++;
+ this.highlightRight = this.nextIndex++;
+
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Remove root element, leaving two subtrees");
+ if (this.treeRoot.left != null)
+ {
+ this.cmd("Disconnect", this.treeRoot.graphicID, this.treeRoot.left.graphicID);
+ }
+ if (this.treeRoot.right != null)
+ {
+ this.cmd("Disconnect", this.treeRoot.graphicID, this.treeRoot.right.graphicID);
+ }
+ var oldElem = this.treeRoot.graphicID;
+ this.cmd("Move", this.treeRoot.graphicID, SkewHeap.INSERT_X, SkewHeap.INSERT_Y);
+ this.cmd("Step");
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Merge the two subtrees");
+
+ if (this.treeRoot.left == null)
+ {
+ this.treeRoot = null;
+ }
+ else if (this.treeRoot.right == null)
+ {
+ this.treeRoot = this.treeRoot.left;
+ this.resizeTrees();
+ }
+ else
+ {
+ var secondTree = this.treeRoot.right;
+ this.secondaryRoot = secondTree;
+ this.treeRoot = this.treeRoot.left;
+ this.resizeTrees();
+ //this.secondaryRoot = null;
+ this.cmd("CreateHighlightCircle", this.highlightLeft, SkewHeap.HIGHLIGHT_CIRCLE_COLOR, this.treeRoot.x, this.treeRoot.y);
+
+ this.cmd("CreateHighlightCircle", this.highlightRight, SkewHeap.HIGHLIGHT_CIRCLE_COLOR, secondTree.x, secondTree.y);
+ this.treeRoot = this.merge(this.treeRoot, secondTree);
+ this.secondaryRoot = null;
+ }
+ this.resizeTrees();
+ this.cmd("Delete", oldElem);
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "");
+
+
+ }
+ // Clear for real
+ return this.commands;
+
+}
+
+
+
+SkewHeap.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Create a heap with one node, merge with existing heap.");
+
+ this.secondaryRoot = new SkewHeapNode(insertedValue, this.nextIndex++, SkewHeap.INSERT_X, SkewHeap.INSERT_Y);
+ this.cmd("CreateCircle", this.secondaryRoot.graphicID, insertedValue, this.secondaryRoot.x, this.secondaryRoot.y);
+ this.cmd("SetForegroundColor", this.secondaryRoot.graphicID, SkewHeap.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.secondaryRoot.graphicID, SkewHeap.BACKGROUND_COLOR);
+
+
+ if (this.treeRoot != null)
+ {
+ this.resizeTrees();
+ this.highlightLeft = this.nextIndex++;
+ this.highlightRight = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", this.highlightLeft, SkewHeap.HIGHLIGHT_CIRCLE_COLOR, this.treeRoot.x, this.treeRoot.y);
+
+ this.cmd("CreateHighlightCircle", this.highlightRight, SkewHeap.HIGHLIGHT_CIRCLE_COLOR, this.secondaryRoot.x, this.secondaryRoot.y);
+
+
+ var rightTree = this.secondaryRoot;
+ this.secondaryRoot = null;
+
+ this.treeRoot = this.merge(this.treeRoot, rightTree);
+
+ this.resizeTrees();
+ }
+ else
+ {
+ this.treeRoot = this.secondaryRoot;
+ this.secondaryRoot = null;
+ this.resizeTrees();
+ }
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "");
+
+
+ return this.commands;
+}
+
+
+SkewHeap.prototype.merge = function(tree1, tree2)
+{
+ if (tree1 == null)
+ {
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Merging right heap with empty heap, return right heap");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightRight);
+ this.cmd("Delete", this.highlightLeft);
+
+ return tree2;
+ }
+ if (tree2 == null)
+ {
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Merging left heap with empty heap, return left heap");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightRight);
+ this.cmd("Delete", this.highlightLeft);
+
+ return tree1;
+ }
+ var tmp;
+ this.cmd("SetHighlight", tree1.graphicID, 1);
+ this.cmd("SetHighlight", tree2.graphicID, 1);
+ if (tree2.data < tree1.data)
+ {
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Min element is in right heap. Recursively merge right subtree of right heap with left heap");
+ tmp = tree1;
+ tree1 = tree2;
+ tree2 = tmp;
+ tmp = this.highlightRight;
+ this.highlightRight = this.highlightLeft;
+ this.highlightLeft = tmp;
+ }
+ else
+ {
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Min element is in left heap. Recursively merge right subtree of left heap with right heap");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree1.graphicID, 0);
+ this.cmd("SetHighlight", tree2.graphicID, 0);
+ if (tree1.right == null)
+ {
+ this.cmd("Move", this.highlightLeft, tree1.x + SkewHeap.WIDTH_DELTA / 2, tree1.y + SkewHeap.HEIGHT_DELTA);
+ }
+ else
+ {
+ this.cmd("Move", this.highlightLeft, tree1.right.x, tree1.right.y);
+
+ }
+ this.cmd("Step");
+ if (tree1.right != null)
+ {
+ this.cmd("Disconnect", tree1.graphicID, tree1.right.graphicID, SkewHeap.LINK_COLOR);
+ }
+ var next = tree1.right;
+ this.cmd("SetAlpha", tree1.graphicID, SkewHeap.BACKGROUND_ALPHA);
+ if (tree1.left != null)
+ {
+ this.cmd("SetEdgeAlpha", tree1.graphicID, tree1.left.graphicID, SkewHeap.BACKGROUND_ALPHA);
+ this.setTreeAlpha(tree1.left, SkewHeap.BACKGROUND_ALPHA);
+
+ }
+ this.cmd("Step");
+ tree1.right = this.merge(next, tree2);
+ if (this.secondaryRoot == tree1.right)
+ {
+ this.secondaryRoot = null;
+ }
+ if (this.treeRoot == tree1.right)
+ {
+ this.treeRoot = null;
+ }
+ if (tree1.right.parent != tree1)
+ {
+ tree1.right.disconnectFromParent();
+ }
+ tree1.right.parent = tree1;
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Reconnecting tree after merge");
+
+ this.cmd("Connect", tree1.graphicID, tree1.right.graphicID, SkewHeap.LINK_COLOR);
+ this.cmd("SetAlpha", tree1.graphicID, 1);
+
+ this.resizeTrees();
+ if (tree1.left != null)
+ {
+ this.cmd("SetEdgeAlpha", tree1.graphicID, tree1.left.graphicID, 1);
+ this.setTreeAlpha(tree1.left, 1);
+ this.cmd("Step");
+ }
+
+ this.cmd("SetHighlight", tree1.graphicID, 1);
+ this.cmd("SetText", SkewHeap.MESSAGE_ID, "Swapping subtrees after merge ...");
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree1.graphicID, 0);
+ var tmp = tree1.left;
+ tree1.left = tree1.right;
+ tree1.right = tmp;
+ this.resizeTrees();
+
+ return tree1;
+}
+
+
+
+SkewHeap.prototype.setTreeAlpha = function(tree, newAlpha)
+{
+ if (tree != null)
+ {
+ this.cmd("SetAlpha", tree.graphicID, newAlpha);
+ if (tree.left != null)
+ {
+ this.cmd("SetEdgeAlpha", tree.graphicID, tree.left.graphicID, newAlpha);
+ this.setTreeAlpha(tree.left, newAlpha);
+ }
+ if (tree.right != null)
+ {
+ this.cmd("SetEdgeAlpha", tree.graphicID, tree.right.graphicID, newAlpha);
+ this.setTreeAlpha(tree.right, newAlpha);
+ }
+ }
+}
+
+SkewHeap.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = Math.max(this.resizeWidths(tree.left), SkewHeap.WIDTH_DELTA / 2);
+ tree.rightWidth = Math.max(this.resizeWidths(tree.right), SkewHeap.WIDTH_DELTA / 2);
+ return tree.leftWidth + tree.rightWidth;
+}
+
+
+
+SkewHeap.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+SkewHeap.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+
+SkewHeap.prototype.resizeTrees = function()
+{
+ var firstTreeStart;
+ var secondTreeStart;
+ this.resizeWidths(this.treeRoot);
+ this.resizeWidths(this.secondaryRoot);
+
+ if (this.treeRoot != null)
+ {
+ startingPoint = this.treeRoot.leftWidth;
+ this.setNewPositions(this.treeRoot, startingPoint, SkewHeap.STARTING_Y, 0);
+ this.animateNewPositions(this.treeRoot);
+ if (this.secondaryRoot != null)
+ {
+ secondTreeStart = this.treeRoot.leftWidth + this.treeRoot.rightWidth + this.secondaryRoot.leftWidth + 50;
+ this.setNewPositions(this.secondaryRoot, secondTreeStart, SkewHeap.STARTING_Y, 0);
+ this.animateNewPositions(this.secondaryRoot);
+ }
+
+ this.cmd("Step");
+ }
+ else if (this.secondaryRoot != null)
+ {
+ startingPoint = this.secondaryRoot.leftWidth;
+ this.setNewPositions(this.secondaryRoot, startingPoint, SkewHeap.STARTING_Y, 0);
+ this.animateNewPositions(this.secondaryRoot);
+ }
+
+}
+
+SkewHeap.prototype.setNewPositions = function(tree, xPosition, yPosition, side)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ if (side == -1)
+ {
+ xPosition = xPosition - tree.rightWidth;
+ }
+ else if (side == 1)
+ {
+ xPosition = xPosition + tree.leftWidth;
+ }
+ else
+ {
+// ??? tree.heightLabelX = xPosition - SkewHeap.NPL_OFFSET_Y;
+ }
+ tree.x = xPosition;
+ this.setNewPositions(tree.left, xPosition, yPosition + SkewHeap.HEIGHT_DELTA, -1)
+ this.setNewPositions(tree.right, xPosition, yPosition + SkewHeap.HEIGHT_DELTA, 1)
+ }
+
+}
+
+
+SkewHeap.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.animateNewPositions(tree.left);
+ this.animateNewPositions(tree.right);
+ }
+}
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new SkewHeap(animManag, canvas.width, canvas.height);
+}
+
+
+
+
+function SkewHeapNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.x = (initialX == undefined) ? 0 : initialX;
+ this.y = (initialY == undefined) ? 0 : initialY;
+
+ this.graphicID = id;
+ this.left = null;
+ this.right = null;
+ this.leftWidth = 0;
+ this.rightWidth = 0;
+ this.parent = null;
+}
+
+SkewHeapNode.prototype.disconnectFromParent = function()
+{
+ if (this.parent != null)
+ {
+ if (this.parent.right == this)
+ {
+ this.parent.right = null;
+ }
+ else if (this.parent.left === this)
+ {
+ this.parent.left == null;
+ }
+ }
+}
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SplayTree.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SplayTree.js
new file mode 100644
index 0000000..b6bf766
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/SplayTree.js
@@ -0,0 +1,1102 @@
+// 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 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
+
+
+// Constants.
+
+SPLAYTREE.LINK_COLOR = "#007700";
+SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+SPLAYTREE.FOREGROUND_COLOR = "#007700";
+SPLAYTREE.BACKGROUND_COLOR = "#EEFFEE";
+SPLAYTREE.PRINT_COLOR = SPLAYTREE.FOREGROUND_COLOR;
+
+SPLAYTREE.WIDTH_DELTA = 50;
+SPLAYTREE.HEIGHT_DELTA = 50;
+SPLAYTREE.STARTING_Y = 50;
+
+
+SPLAYTREE.FIRST_PRINT_POS_X = 50;
+SPLAYTREE.PRINT_VERTICAL_GAP = 20;
+SPLAYTREE.PRINT_HORIZONTAL_GAP = 50;
+
+
+
+function SPLAYTREE(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+SPLAYTREE.prototype = new Algorithm();
+SPLAYTREE.prototype.constructor = SPLAYTREE;
+SPLAYTREE.superclass = Algorithm.prototype;
+
+SPLAYTREE.prototype.init = function(am, w, h)
+{
+ var sc = SPLAYTREE.superclass;
+ this.startingX = w / 2;
+ this.first_print_pos_y = h - 2 * SPLAYTREE.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 10, 0);
+ this.nextIndex = 1;
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+SPLAYTREE.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeydown = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 4);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 4);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 4);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+}
+
+SPLAYTREE.prototype.reset = function()
+{
+ this.nextIndex = 1;
+ this.treeRoot = null;
+}
+
+SPLAYTREE.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value;
+ // Get text value
+ insertedValue = this.normalizeNumber(insertedValue, 4);
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.insertElement.bind(this), insertedValue);
+ }
+}
+
+SPLAYTREE.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value;
+ if (deletedValue != "")
+ {
+ deletedValue = this.normalizeNumber(deletedValue, 4);
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+}
+
+
+
+
+// TODO: This top-down version is broken. Don't use
+SPLAYTREE.prototype.splay = function(value)
+{
+ if (this.treeRoot == null)
+ {
+ return false;
+ }
+ if (this.treeRoot.data == value)
+ {
+ return true;
+ }
+ if (value < this.treeRoot.data)
+ {
+ if (this.treeRoot.left == null)
+ {
+ return false;
+ }
+ else if (this.treeRoot.left.data == value)
+ {
+ this.singleRotateRight(this.treeRoot);
+ return true;
+ }
+ else if (value < this.treeRoot.left.data)
+ {
+ if (this.treeRoot.left.left == null)
+ {
+ this.singleRotateRight(this.treeRoot);
+ return this.splay(value);
+ }
+ else
+ {
+ this.zigZigRight(this.treeRoot);
+ return this.splay(value);
+ }
+ }
+ else
+ {
+ if (this.treeRoot.left.right == null)
+ {
+ this.singleRotateRight(this.treeRoot);
+ return this.splay(value);
+ }
+ else
+ {
+ this.doubleRotateRight(this.treeRoot);
+ return this.splay(value);
+ }
+
+ }
+ }
+ else
+ {
+ if (this.treeRoot.right == null)
+ {
+ return false;
+ }
+ else if (this.treeRoot.right.data == value)
+ {
+ this.singleRotateLeft(this.treeRoot);
+ return true;
+ }
+ else if (value > this.treeRoot.right.data)
+ {
+ if (this.treeRoot.right.right == null)
+ {
+ this.singleRotateLeft(this.treeRoot);
+ return this.splay(value);
+ }
+ else
+ {
+ this.zigZigLeft(this.treeRoot);
+ return this.splay(value);
+ }
+ }
+ else
+ {
+ if (this.treeRoot.right.left == null)
+ {
+ this.singleRotateLeft(this.treeRoot);
+ return this.splay(value);
+ }
+ else
+ {
+ this.doubleRotateLeft(this.treeRot);
+ return this.splay(value);
+ }
+
+ }
+
+
+ }
+
+}
+
+
+
+SPLAYTREE.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+SPLAYTREE.prototype.printTree = function(unused)
+{
+ this.commands = [];
+
+ if (this.treeRoot != null)
+ {
+ this.highlightID = this.nextIndex++;
+ var firstLabel = this.nextIndex;
+ this.cmd("CreateHighlightCircle", this.highlightID, SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR, this.treeRoot.x, this.treeRoot.y);
+ this.xPosOfNextLabel = SPLAYTREE.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.treeRoot);
+ this.cmd("Delete", this.highlightID);
+ this.cmd("Step")
+
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+}
+
+SPLAYTREE.prototype.printTreeRec = function(tree)
+{
+ this.cmd("Step");
+ if (tree.left != null)
+ {
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.printTreeRec(tree.left);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, tree.data, tree.x, tree.y);
+ this.cmd("SetForegroundColor", nextLabelID, SPLAYTREE.PRINT_COLOR);
+ this.cmd("Move", nextLabelID, this.xPosOfNextLabel, this.yPosOfNextLabel);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += SPLAYTREE.PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = SPLAYTREE.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += SPLAYTREE.PRINT_VERTICAL_GAP;
+
+ }
+ if (tree.right != null)
+ {
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.printTreeRec(tree.right);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+ return;
+}
+
+SPLAYTREE.prototype.findCallback = function(event)
+{
+ var findValue;
+ findValue = this.normalizeNumber(this.findField.value, 4);
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+SPLAYTREE.prototype.findElement = function(findValue)
+{
+ this.commands = [];
+
+ this.highlightID = this.nextIndex++;
+
+
+
+ var found = this.doFind(this.treeRoot, findValue);
+
+ if (found)
+ {
+ this.cmd("SetText", 0, "Element " + findValue + " found.");
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, "Element " + findValue + " 未找到.");
+
+ }
+
+
+ return this.commands;
+}
+
+
+SPLAYTREE.prototype.doFind = function(tree, value)
+{
+ this.cmd("SetText", 0, "正在搜索 "+value);
+ if (tree != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ if (tree.data == value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " = " + value + " (Element found!)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "Splaying found node to root of tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.splayUp(tree);
+ return true;
+ }
+ else
+ {
+ if (tree.data > value)
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " < " + tree.data + " (访问左子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.left!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ return this.doFind(tree.left, value);
+ }
+ else
+ {
+ this.splayUp(tree);
+ return false;
+ }
+ }
+ else
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + value + " > " + tree.data + " (访问右子树)");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ if (tree.right!= null)
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ return this.doFind(tree.right, value);
+ }
+ else
+ {
+ this.splayUp(tree);
+ return false;
+
+ }
+ }
+
+ }
+
+ }
+ else
+ {
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + "< 空树 > (找不到元素)");
+ this.cmd("Step");
+ this.cmd("SetText", 0, "正在搜索 "+value+":" + " (找不到元素)");
+ return false;
+ }
+}
+
+SPLAYTREE.prototype.insertElement = function(insertedValue)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "Inserting "+insertedValue);
+ this.highlightID = this.nextIndex++;
+
+ if (this.treeRoot == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, insertedValue, this.startingX, SPLAYTREE.STARTING_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, SPLAYTREE.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, SPLAYTREE.BACKGROUND_COLOR);
+ this.cmd("Step");
+ this.treeRoot = new BSTNode(insertedValue, this.nextIndex, this.startingX, SPLAYTREE.STARTING_Y)
+ this.nextIndex += 1;
+ }
+ else
+ {
+ this.cmd("CreateCircle", this.nextIndex, insertedValue, 100, 100);
+ this.cmd("SetForegroundColor", this.nextIndex, SPLAYTREE.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, SPLAYTREE.BACKGROUND_COLOR);
+ this.cmd("Step");
+ var insertElem = new BSTNode(insertedValue, this.nextIndex, 100, 100)
+
+
+ this.nextIndex += 1;
+ this.cmd("SetHighlight", insertElem.graphicID, 1);
+ this.insert(insertElem, this.treeRoot)
+ this.resizeTree();
+ this.cmd("SetText", 0 , "Splay inserted element to root of tree");
+ this.cmd("Step");
+ this.splayUp(insertElem);
+
+ }
+ this.cmd("SetText", 0, "");
+ return this.commands;
+}
+
+
+SPLAYTREE.prototype.insert = function(elem, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID , 1);
+ this.cmd("SetHighlight", elem.graphicID , 1);
+
+ if (elem.data < tree.data)
+ {
+ this.cmd("SetText", 0, elem.data + " < " + tree.data + ", 访问左子树");
+ }
+ else
+ {
+ this.cmd("SetText", 0, elem.data + " >= " + tree.data + ", 访问右子树");
+ }
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ this.cmd("SetHighlight", elem.graphicID, 0);
+
+ if (elem.data < tree.data)
+ {
+ if (tree.left == null)
+ {
+ this.cmd("SetText", 0,"Found null tree, inserting element");
+
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.left=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, SPLAYTREE.LINK_COLOR);
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.left);
+ }
+ }
+ else
+ {
+ if (tree.right == null)
+ {
+ this.cmd("SetText", 0, "Found null tree, inserting element");
+ this.cmd("SetHighlight", elem.graphicID, 0);
+ tree.right=elem;
+ elem.parent = tree;
+ this.cmd("Connect", tree.graphicID, elem.graphicID, SPLAYTREE.LINK_COLOR);
+ elem.x = tree.x + SPLAYTREE.WIDTH_DELTA/2;
+ elem.y = tree.y + SPLAYTREE.HEIGHT_DELTA
+ this.cmd("Move", elem.graphicID, elem.x, elem.y);
+ }
+ else
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightID);
+ this.insert(elem, tree.right);
+ }
+ }
+
+
+}
+
+SPLAYTREE.prototype.deleteElement = function(deletedValue)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "正在刪除 "+deletedValue);
+ this.cmd("Step");
+ this.cmd("SetText", 0, "");
+ this.highlightID = this.nextIndex++;
+ this.treeDelete(this.treeRoot, deletedValue);
+ this.cmd("SetText", 0, "");
+ // Do delete
+ return this.commands;
+}
+
+SPLAYTREE.prototype.treeDelete = function(tree, valueToDelete)
+{
+ this.cmd("SetText", 0, "Finding "+valueToDelete + " and splaying to rooot");
+ this.cmd("Step");
+
+ var inTree = this.doFind(this.treeRoot, valueToDelete);
+ this.cmd("SetText", 0, "Removing root, leaving left and right trees");
+ this.cmd("Step")
+ if (inTree)
+ {
+ if (this.treeRoot.right == null)
+ {
+ this.cmd("Delete", this.treeRoot.graphicID);
+ this.cmd("SetText", 0, "No right tree, make left tree the root.");
+ this.cmd("Step");
+ this.treeRoot = this.treeRoot.left;
+ this.treeRoot.parent = null;
+ this.resizeTree();
+ }
+ else if (this.treeRoot.left == null)
+ {
+ this.cmd("Delete", this.treeRoot.graphicID);
+ this.cmd("SetText", 0, "No left tree, make right tree the root.");
+ this.cmd("Step");
+ this.treeRoot = this.treeRoot.right
+ this.treeRoot.parent = null;
+ this.resizeTree();
+ }
+ else
+ {
+ var right = this.treeRoot.right;
+ var left = this.treeRoot.left;
+ var oldGraphicID = this.treeRoot.graphicID;
+ this.cmd("Disconnect", this.treeRoot.graphicID, left.graphicID);
+ this.cmd("Disconnect", this.treeRoot.graphicID, right.graphicID);
+ this.cmd("SetAlpha", this.treeRoot.graphicID, 0);
+ this.cmd("SetText", 0, "Splay largest element in left tree to root");
+ this.cmd("Step")
+
+ left.parent = null;
+ var largestLeft = this.findMax(left);
+ this.splayUp(largestLeft);
+ this.cmd("SetText", 0, "Left tree now has no right subtree, connect left and right trees");
+ this.cmd("Step");
+ this.cmd("Connect", largestLeft.graphicID, right.graphicID, SPLAYTREE.LINK_COLOR);
+ largestLeft.parent = null;
+ largestLeft.right = right;
+ right.parent = largestLeft;
+ this.treeRoot = largestLeft;
+ this.cmd("Delete", oldGraphicID);
+ this.resizeTree();
+
+ }
+ }
+}
+
+
+
+
+SPLAYTREE.prototype.singleRotateRight = function(tree)
+{
+ var B = tree;
+ var t3 = B.right;
+ var A = tree.left;
+ var t1 = A.left;
+ var t2 = A.right;
+
+ this.cmd("SetText", 0, "Zig Right");
+ this.cmd("SetEdgeHighlight", B.graphicID, A.graphicID, 1);
+ this.cmd("Step");
+
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", A.graphicID, t2.graphicID);
+ this.cmd("Connect", B.graphicID, t2.graphicID, SPLAYTREE.LINK_COLOR);
+ t2.parent = B;
+ }
+ this.cmd("Disconnect", B.graphicID, A.graphicID);
+ this.cmd("Connect", A.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR);
+ A.parent = B.parent;
+ if (B.parent == null)
+ {
+ this.treeRoot = A;
+ }
+ else
+ {
+ this.cmd("Disconnect", B.parent.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR);
+ this.cmd("Connect", B.parent.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR)
+ if (B.isLeftChild())
+ {
+ B.parent.left = A;
+ }
+ else
+ {
+ B.parent.right = A;
+ }
+ }
+ A.right = B;
+ B.parent = A;
+ B.left = t2;
+ this.resizeTree();
+}
+
+
+SPLAYTREE.prototype.zigZigRight = function(tree)
+{
+ var C = tree;
+ var B = tree.left;
+ var A = tree.left.left;
+ var t1 = A.left;
+ var t2 = A.right;
+ var t3 = B.right;
+ var t4 = C.right;
+
+ this.cmd("SetText", 0, "Zig-Zig Right");
+ this.cmd("SetEdgeHighlight", C.graphicID, B.graphicID, 1);
+ this.cmd("SetEdgeHighlight", B.graphicID, A.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", C.graphicID, B.graphicID, 0);
+ this.cmd("SetEdgeHighlight", B.graphicID, A.graphicID, 0);
+
+
+ if (C.parent != null)
+ {
+ this.cmd("Disconnect", C.parent.graphicID, C.graphicID);
+ this.cmd("Connect", C.parent.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR);
+ if (C.isLeftChild())
+ {
+ C.parent.left = A;
+ }
+ else
+ {
+ C.parent.right = A;
+ }
+ }
+ else
+ {
+ this.treeRoot = A;
+ }
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", A.graphicID, t2.graphicID);
+ this.cmd("Connect", B.graphicID, t2.graphicID, SPLAYTREE.LINK_COLOR);
+ t2.parent = B;
+ }
+ if (t3 != null)
+ {
+ this.cmd("Disconnect", B.graphicID, t3.graphicID);
+ this.cmd("Connect", C.graphicID, t3.graphicID, SPLAYTREE.LINK_COLOR);
+ t3.parent = C;
+ }
+ this.cmd("Disconnect", B.graphicID, A.graphicID);
+ this.cmd("Connect", A.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR);
+ this.cmd("Disconnect", C.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, C.graphicID, SPLAYTREE.LINK_COLOR);
+
+ A.right = B;
+ A.parent = C.parent;
+ B.parent = A;
+ B.left = t2;
+ B.right = C;
+ C.parent = B;
+ C.left = t3;
+ this.resizeTree();
+}
+
+
+SPLAYTREE.prototype.zigZigLeft = function(tree)
+{
+ var A = tree;
+ var B = tree.right;
+ var C = tree.right.right;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = C.left;
+ var t4 = C.right;
+
+ this.cmd("SetText", 0, "Zig-Zig Left");
+ this.cmd("SetEdgeHighlight", A.graphicID, B.graphicID, 1);
+ this.cmd("SetEdgeHighlight", B.graphicID, C.graphicID, 1);
+ this.cmd("Step");
+ this.cmd("SetEdgeHighlight", A.graphicID, B.graphicID, 0);
+ this.cmd("SetEdgeHighlight", B.graphicID, C.graphicID, 0);
+
+
+
+ if (A.parent != null)
+ {
+ this.cmd("Disconnect", A.parent.graphicID, A.graphicID);
+ this.cmd("Connect", A.parent.graphicID, C.graphicID, SPLAYTREE.LINK_COLOR);
+ if (A.isLeftChild())
+ {
+ A.parent.left = C;
+ }
+ else
+ {
+ A.parent.right = C;
+ }
+ }
+ else
+ {
+ this.treeRoot = C;
+ }
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", B.graphicID, t2.graphicID);
+ this.cmd("Connect", A.graphicID, t2.graphicID, SPLAYTREE.LINK_COLOR);
+ t2.parent = A;
+ }
+ if (t3 != null)
+ {
+ this.cmd("Disconnect", C.graphicID, t3.graphicID);
+ this.cmd("Connect", B.graphicID, t3.graphicID, SPLAYTREE.LINK_COLOR);
+ t3.parent = B;
+ }
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Disconnect", B.graphicID, C.graphicID);
+ this.cmd("Connect", C.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR);
+ this.cmd("Connect", B.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR);
+ C.parent = A.parent;
+ A.right = t2;
+ B.left = A;
+ A.parent = B;
+ B.right = t3;
+ C.left = B;
+ B.parent = C;
+
+ this.resizeTree();
+
+}
+
+SPLAYTREE.prototype.singleRotateLeft = function(tree)
+{
+ var A = tree;
+ var B = tree.right;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+
+ this.cmd("SetText", 0, "Zig Left");
+ this.cmd("SetEdgeHighlight", A.graphicID, B.graphicID, 1);
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect", B.graphicID, t2.graphicID);
+ this.cmd("Connect", A.graphicID, t2.graphicID, SPLAYTREE.LINK_COLOR);
+ t2.parent = A;
+ }
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR);
+ B.parent = A.parent;
+ if (A.parent == null)
+ {
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect", A.parent.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR);
+ this.cmd("Connect", A.parent.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR)
+
+ if (A.isLeftChild())
+ {
+ A.parent.left = B;
+ }
+ else
+ {
+ A.parent.right = B;
+ }
+ }
+ B.left = A;
+ A.parent = B;
+ A.right = t2;
+
+ this.resizeTree();
+}
+
+
+
+SPLAYTREE.prototype.splayUp = function(tree)
+{
+ if (tree.parent == null)
+ {
+ return;
+ }
+ else if (tree.parent.parent == null)
+ {
+ if (tree.isLeftChild())
+ {
+ this.singleRotateRight(tree.parent);
+
+ }
+ else
+ {
+ this.singleRotateLeft(tree.parent);
+ }
+ }
+ else if (tree.isLeftChild() && !tree.parent.isLeftChild())
+ {
+ this.doubleRotateLeft(tree.parent.parent);
+ this.splayUp(tree);
+
+ }
+ else if (!tree.isLeftChild() && tree.parent.isLeftChild())
+ {
+ this.doubleRotateRight(tree.parent.parent);
+ this.splayUp(tree);
+ }
+ else if (tree.isLeftChild())
+ {
+ this.zigZigRight(tree.parent.parent);
+ this.splayUp(tree);
+ }
+ else
+ {
+ this.zigZigLeft(tree.parent.parent);
+ this.splayUp(tree);
+ }
+}
+
+
+SPLAYTREE.prototype.findMax = function(tree)
+{
+ if (tree.right != null)
+ {
+ this.highlightID = this.nextIndex++;
+ this.cmd("CreateHighlightCircle", this.highlightID, SPLAYTREE.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("Step");
+ while(tree.right != null)
+ {
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ tree = tree.right;
+ }
+ this.cmd("Delete", this.highlightID);
+ return tree;
+ }
+ else
+ {
+ return tree;
+ }
+}
+
+
+SPLAYTREE.prototype.doubleRotateRight = function(tree)
+{
+ this.cmd("SetText", 0, "Zig-Zag Right");
+ var A = tree.left;
+ var B = tree.left.right;
+ var C = tree;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+ var t4 = C.right;
+
+ this.cmd("SetEdgeHighlight", C.graphicID, A.graphicID, 1);
+ this.cmd("SetEdgeHighlight", A.graphicID, B.graphicID, 1);
+
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t2.graphicID);
+ t2.parent = A;
+ A.right = t2;
+ this.cmd("Connect", A.graphicID, t2.graphicID, SPLAYTREE.LINK_COLOR);
+ }
+ if (t3 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t3.graphicID);
+ t3.parent = C;
+ C.left = t2;
+ this.cmd("Connect", C.graphicID, t3.graphicID, SPLAYTREE.LINK_COLOR);
+ }
+ if (C.parent == null)
+ {
+ B.parent = null;
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect",C.parent.graphicID, C.graphicID);
+ this.cmd("Connect",C.parent.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR);
+ if (C.isLeftChild())
+ {
+ C.parent.left = B
+ }
+ else
+ {
+ C.parent.right = B;
+ }
+ B.parent = C.parent;
+ C.parent = B;
+ }
+ this.cmd("Disconnect", C.graphicID, A.graphicID);
+ this.cmd("Disconnect", A.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR);
+ this.cmd("Connect", B.graphicID, C.graphicID, SPLAYTREE.LINK_COLOR);
+ B.left = A;
+ A.parent = B;
+ B.right=C;
+ C.parent=B;
+ A.right=t2;
+ C.left = t3;
+
+ this.resizeTree();
+
+
+}
+
+SPLAYTREE.prototype.doubleRotateLeft = function(tree)
+{
+ this.cmd("SetText", 0, "Zig-Zag Left");
+ var A = tree;
+ var B = tree.right.left;
+ var C = tree.right;
+ var t1 = A.left;
+ var t2 = B.left;
+ var t3 = B.right;
+ var t4 = C.right;
+
+ this.cmd("SetEdgeHighlight", A.graphicID, C.graphicID, 1);
+ this.cmd("SetEdgeHighlight", C.graphicID, B.graphicID, 1);
+
+ this.cmd("Step");
+
+ if (t2 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t2.graphicID);
+ t2.parent = A;
+ A.right = t2;
+ this.cmd("Connect", A.graphicID, t2.graphicID, SPLAYTREE.LINK_COLOR);
+ }
+ if (t3 != null)
+ {
+ this.cmd("Disconnect",B.graphicID, t3.graphicID);
+ t3.parent = C;
+ C.left = t2;
+ this.cmd("Connect", C.graphicID, t3.graphicID, SPLAYTREE.LINK_COLOR);
+ }
+
+
+ if (A.parent == null)
+ {
+ B.parent = null;
+ this.treeRoot = B;
+ }
+ else
+ {
+ this.cmd("Disconnect",A.parent.graphicID, A.graphicID);
+ this.cmd("Connect",A.parent.graphicID, B.graphicID, SPLAYTREE.LINK_COLOR);
+ if (A.isLeftChild())
+ {
+ A.parent.left = B
+ }
+ else
+ {
+ A.parent.right = B;
+ }
+ B.parent = A.parent;
+ A.parent = B;
+
+ }
+ this.cmd("Disconnect", A.graphicID, C.graphicID);
+ this.cmd("Disconnect", C.graphicID, B.graphicID);
+ this.cmd("Connect", B.graphicID, A.graphicID, SPLAYTREE.LINK_COLOR);
+ this.cmd("Connect", B.graphicID, C.graphicID, SPLAYTREE.LINK_COLOR);
+ B.left = A;
+ A.parent = B;
+ B.right=C;
+ C.parent=B;
+ A.right=t2;
+ C.left = t3;
+
+ this.resizeTree();
+
+
+}
+
+
+
+SPLAYTREE.prototype.resizeTree = function()
+{
+ var startingPoint = this.startingX;
+ this.resizeWidths(this.treeRoot);
+ if (this.treeRoot != null)
+ {
+ if (this.treeRoot.leftWidth > startingPoint)
+ {
+ startingPoint = this.treeRoot.leftWidth;
+ }
+ else if (this.treeRoot.rightWidth > startingPoint)
+ {
+ startingPoint = Math.max(this.treeRoot.leftWidth, 2 * startingPoint - this.treeRoot.rightWidth);
+ }
+ this.setNewPositions(this.treeRoot, startingPoint, SPLAYTREE.STARTING_Y, 0);
+ this.animateNewPositions(this.treeRoot);
+ this.cmd("Step");
+ }
+
+}
+
+SPLAYTREE.prototype.setNewPositions = function(tree, xPosition, yPosition, side)
+{
+ if (tree != null)
+ {
+ tree.y = yPosition;
+ if (side == -1)
+ {
+ xPosition = xPosition - tree.rightWidth;
+ }
+ else if (side == 1)
+ {
+ xPosition = xPosition + tree.leftWidth;
+ }
+ tree.x = xPosition;
+ this.setNewPositions(tree.left, xPosition, yPosition + SPLAYTREE.HEIGHT_DELTA, -1)
+ this.setNewPositions(tree.right, xPosition, yPosition + SPLAYTREE.HEIGHT_DELTA, 1)
+ }
+
+}
+SPLAYTREE.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.animateNewPositions(tree.left);
+ this.animateNewPositions(tree.right);
+ }
+}
+
+SPLAYTREE.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = Math.max(this.resizeWidths(tree.left), SPLAYTREE.WIDTH_DELTA / 2);
+ tree.rightWidth = Math.max(this.resizeWidths(tree.right), SPLAYTREE.WIDTH_DELTA / 2);
+ return tree.leftWidth + tree.rightWidth;
+}
+
+
+
+
+function BSTNode(val, id, initialX, initialY)
+{
+ this.data = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.left = null;
+ this.right = null;
+ this.parent = null;
+}
+
+BSTNode.prototype.isLeftChild = function()
+{
+ if (this. parent == null)
+ {
+ return true;
+ }
+ return this.parent.left == this;
+}
+
+
+SPLAYTREE.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+SPLAYTREE.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new SPLAYTREE(animManag, canvas.width, canvas.height);
+
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/StackArray.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/StackArray.js
new file mode 100644
index 0000000..56eff0e
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/StackArray.js
@@ -0,0 +1,302 @@
+// 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 ``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 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 = 100;
+var ARRAY_START_Y = 200;
+var ARRAY_ELEM_WIDTH = 50;
+var ARRAY_ELEM_HEIGHT = 50;
+
+var ARRRAY_ELEMS_PER_LINE = 15;
+var ARRAY_LINE_SPACING = 130;
+
+var TOP_POS_X = 180;
+var TOP_POS_Y = 100;
+var TOP_LABEL_X = 130;
+var TOP_LABEL_Y = 100;
+
+var PUSH_LABEL_X = 50;
+var PUSH_LABEL_Y = 30;
+var PUSH_ELEMENT_X = 120;
+var PUSH_ELEMENT_Y = 30;
+
+var SIZE = 30;
+
+function StackArray(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+StackArray.prototype = new Algorithm();
+StackArray.prototype.constructor = StackArray;
+StackArray.superclass = Algorithm.prototype;
+
+
+StackArray.prototype.init = function(am, w, h)
+{
+ StackArray.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.setup();
+ this.initialIndex = this.nextIndex;
+}
+
+
+StackArray.prototype.addControls = function()
+{
+ this.controls = [];
+ this.pushField = addControlToAlgorithmBar("Text", "");
+ this.pushField.onkeydown = this.returnSubmit(this.pushField, this.pushCallback.bind(this), 6);
+ this.pushButton = addControlToAlgorithmBar("Button", "Push");
+ this.pushButton.onclick = this.pushCallback.bind(this);
+ this.controls.push(this.pushField);
+ this.controls.push(this.pushButton);
+
+ this.popButton = addControlToAlgorithmBar("Button", "Pop");
+ this.popButton.onclick = this.popCallback.bind(this);
+ this.controls.push(this.popButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "Clear Stack");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+}
+
+StackArray.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+StackArray.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+StackArray.prototype.setup = function()
+{
+ this.nextIndex = 0;
+
+ this.arrayID = new Array(SIZE);
+ this.arrayLabelID = new Array(SIZE);
+ for (var i = 0; i < SIZE; i++)
+ {
+
+ this.arrayID[i]= this.nextIndex++;
+ this.arrayLabelID[i]= this.nextIndex++;
+ }
+ this.topID = this.nextIndex++;
+ this.topLabelID = this.nextIndex++;
+
+ this.arrayData = new Array(SIZE);
+ this.top = 0;
+ this.leftoverLabelID = this.nextIndex++;
+ this.commands = new Array();
+
+ for (var i = 0; i < SIZE; i++)
+ {
+ var xpos = (i % ARRRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ var ypos = Math.floor(i / ARRRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y;
+ this.cmd("CreateRectangle", this.arrayID[i],"", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT,xpos, ypos);
+ this.cmd("CreateLabel",this.arrayLabelID[i], i, xpos, ypos + ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", this.arrayLabelID[i], "#0000FF");
+
+ }
+ this.cmd("CreateLabel", this.topLabelID, "top", TOP_LABEL_X, TOP_LABEL_Y);
+ this.cmd("CreateRectangle", this.topID, 0, ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT, TOP_POS_X, TOP_POS_Y);
+
+ this.cmd("CreateLabel", this.leftoverLabelID, "", PUSH_LABEL_X, PUSH_LABEL_Y);
+
+ this.highlight1ID = this.nextIndex++;
+ this.highlight2ID = this.nextIndex++;
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+
+
+StackArray.prototype.reset = function()
+{
+ this.top = 0;
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+StackArray.prototype.pushCallback = function(event)
+{
+ if (this.top < SIZE && this.pushField.value != "")
+ {
+ var pushVal = this.pushField.value;
+ this.pushField.value = ""
+ this.implementAction(this.push.bind(this), pushVal);
+ }
+}
+
+
+StackArray.prototype.popCallback = function(event)
+{
+ if (this.top > 0)
+ {
+ this.implementAction(this.pop.bind(this), "");
+ }
+}
+
+
+StackArray.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clearData.bind(this), "");
+}
+
+StackArray.prototype.clearData = function(ignored)
+{
+ this.commands = new Array();
+ this.clearAll();
+ return this.commands;
+}
+
+
+StackArray.prototype.push = function(elemToPush)
+{
+ this.commands = new Array();
+
+ var labPushID = this.nextIndex++;
+ var labPushValID = this.nextIndex++;
+ this.arrayData[this.top] = elemToPush;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+ this.cmd("CreateLabel", labPushID, "Pushing Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPushValID,elemToPush, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+
+ this.cmd("Step");
+ this.cmd("CreateHighlightCircle", this.highlight1ID, "#0000FF", TOP_POS_X, TOP_POS_Y);
+ this.cmd("Step");
+
+ var xpos = (this.top % ARRRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ var ypos = Math.floor(this.top / ARRRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y;
+
+ this.cmd("Move", this.highlight1ID, xpos, ypos + ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+
+ this.cmd("Move", labPushValID, xpos, ypos);
+ this.cmd("Step");
+
+ this.cmd("Settext", this.arrayID[this.top], elemToPush);
+ this.cmd("Delete", labPushValID);
+
+ this.cmd("Delete", this.highlight1ID);
+
+ this.cmd("SetHighlight", this.topID, 1);
+ this.cmd("Step");
+ this.top = this.top + 1;
+ this.cmd("SetText", this.topID, this.top)
+ this.cmd("Delete", labPushID);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.topID, 0);
+
+ return this.commands;
+}
+
+StackArray.prototype.pop = function(ignored)
+{
+ this.commands = new Array();
+
+ var labPopID = this.nextIndex++;
+ var labPopValID = this.nextIndex++;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+
+ this.cmd("CreateLabel", labPopID, "Popped Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+
+
+ this.cmd("SetHighlight", this.topID, 1);
+ this.cmd("Step");
+ this.top = this.top - 1;
+ this.cmd("SetText", this.topID, this.top)
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.topID, 0);
+
+ this.cmd("CreateHighlightCircle", this.highlight1ID, "#0000FF", TOP_POS_X, TOP_POS_Y);
+ this.cmd("Step");
+
+ var xpos = (this.top % ARRRAY_ELEMS_PER_LINE) * ARRAY_ELEM_WIDTH + ARRAY_START_X;
+ var ypos = Math.floor(this.top / ARRRAY_ELEMS_PER_LINE) * ARRAY_LINE_SPACING + ARRAY_START_Y;
+
+ this.cmd("Move", this.highlight1ID, xpos, ypos + ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+
+ this.cmd("CreateLabel", labPopValID,this.arrayData[this.top], xpos, ypos);
+ this.cmd("Settext", this.arrayID[this.top], "");
+ this.cmd("Move", labPopValID, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+ this.cmd("Step");
+ this.cmd("Delete", labPopValID)
+ this.cmd("Delete", labPopID);
+ this.cmd("Delete", this.highlight1ID);
+ this.cmd("SetText", this.leftoverLabelID, "Popped Value: " + this.arrayData[this.top]);
+
+
+
+ return this.commands;
+}
+
+
+
+StackArray.prototype.clearAll = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < this.top; i++)
+ {
+ this.cmd("SetText", this.arrayID[i], "");
+ }
+ this.top = 0;
+ this.cmd("SetText", this.topID, "0");
+ return this.commands;
+
+}
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new StackArray(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/StackLL.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/StackLL.js
new file mode 100644
index 0000000..3059881
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/StackLL.js
@@ -0,0 +1,301 @@
+// 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 ``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 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 LINKED_LIST_START_X = 100;
+var LINKED_LIST_START_Y = 200;
+var LINKED_LIST_ELEM_WIDTH = 70;
+var LINKED_LIST_ELEM_HEIGHT = 30;
+
+
+var LINKED_LIST_INSERT_X = 250;
+var LINKED_LIST_INSERT_Y = 50;
+
+var LINKED_LIST_ELEMS_PER_LINE = 8;
+var LINKED_LIST_ELEM_SPACING = 100;
+var LINKED_LIST_LINE_SPACING = 100;
+
+var TOP_POS_X = 180;
+var TOP_POS_Y = 100;
+var TOP_LABEL_X = 130;
+var TOP_LABEL_Y = 100;
+
+var TOP_ELEM_WIDTH = 30;
+var TOP_ELEM_HEIGHT = 30;
+
+var PUSH_LABEL_X = 50;
+var PUSH_LABEL_Y = 30;
+var PUSH_ELEMENT_X = 120;
+var PUSH_ELEMENT_Y = 30;
+
+var SIZE = 32;
+
+function StackLL(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+StackLL.prototype = new Algorithm();
+StackLL.prototype.constructor = StackLL;
+StackLL.superclass = Algorithm.prototype;
+
+
+StackLL.prototype.init = function(am, w, h)
+{
+ StackLL.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.setup();
+ this.initialIndex = this.nextIndex;
+}
+
+
+StackLL.prototype.addControls = function()
+{
+ this.controls = [];
+ this.pushField = addControlToAlgorithmBar("Text", "");
+ this.pushField.onkeydown = this.returnSubmit(this.pushField, this.pushCallback.bind(this), 6);
+ this.pushButton = addControlToAlgorithmBar("Button", "Push");
+ this.pushButton.onclick = this.pushCallback.bind(this);
+ this.controls.push(this.pushField);
+ this.controls.push(this.pushButton);
+
+ this.popButton = addControlToAlgorithmBar("Button", "Pop");
+ this.popButton.onclick = this.popCallback.bind(this);
+ this.controls.push(this.popButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "Clear Stack");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+}
+
+StackLL.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+StackLL.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+StackLL.prototype.setup = function()
+{
+
+ this.linkedListElemID = new Array(SIZE);
+ for (var i = 0; i < SIZE; i++)
+ {
+
+ this.linkedListElemID[i]= this.nextIndex++;
+ }
+ this.topID = this.nextIndex++;
+ this.topLabelID = this.nextIndex++;
+
+ this.arrayData = new Array(SIZE);
+ this.top = 0;
+ this.leftoverLabelID = this.nextIndex++;
+
+ this.cmd("CreateLabel", this.topLabelID, "Top", TOP_LABEL_X, TOP_LABEL_Y);
+ this.cmd("CreateRectangle", this.topID, "", TOP_ELEM_WIDTH, TOP_ELEM_HEIGHT, TOP_POS_X, TOP_POS_Y);
+ this.cmd("SetNull", this.topID, 1);
+
+ this.cmd("CreateLabel", this.leftoverLabelID, "", PUSH_LABEL_X, PUSH_LABEL_Y);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+StackLL.prototype.resetLinkedListPositions = function()
+{
+ for (var i = this.top - 1; i >= 0; i--)
+ {
+ var nextX = (this.top - 1 - i) % LINKED_LIST_ELEMS_PER_LINE * LINKED_LIST_ELEM_SPACING + LINKED_LIST_START_X;
+ var nextY = Math.floor((this.top - 1 - i) / LINKED_LIST_ELEMS_PER_LINE) * LINKED_LIST_LINE_SPACING + LINKED_LIST_START_Y;
+ this.cmd("Move", this.linkedListElemID[i], nextX, nextY);
+ }
+
+}
+
+
+
+
+StackLL.prototype.reset = function()
+{
+ this.top = 0;
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+StackLL.prototype.pushCallback = function(event)
+{
+ if (this.top < SIZE && this.pushField.value != "")
+ {
+ var pushVal = this.pushField.value;
+ this.pushField.value = ""
+ this.implementAction(this.push.bind(this), pushVal);
+ }
+}
+
+
+StackLL.prototype.popCallback = function(event)
+{
+ if (this.top > 0)
+ {
+ this.implementAction(this.pop.bind(this), "");
+ }
+}
+
+
+StackLL.prototype.clearCallback = function(event)
+{
+ this.implementAction(this.clearAll.bind(this), "");
+}
+
+
+
+StackLL.prototype.push = function(elemToPush)
+{
+ this.commands = new Array();
+
+ var labPushID = this.nextIndex++;
+ var labPushValID = this.nextIndex++;
+ this.arrayData[this.top] = elemToPush;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+ this.cmd("CreateLinkedList",this.linkedListElemID[this.top], "" ,LINKED_LIST_ELEM_WIDTH, LINKED_LIST_ELEM_HEIGHT,
+ LINKED_LIST_INSERT_X, LINKED_LIST_INSERT_Y, 0.25, 0, 1, 1);
+
+ this.cmd("CreateLabel", labPushID, "Pushing Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPushValID,elemToPush, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+
+ this.cmd("Step");
+
+
+
+ this.cmd("Move", labPushValID, LINKED_LIST_INSERT_X, LINKED_LIST_INSERT_Y);
+
+ this.cmd("Step");
+ this.cmd("SetText", this.linkedListElemID[this.top], elemToPush);
+ this.cmd("Delete", labPushValID);
+
+ if (this.top == 0)
+ {
+ this.cmd("SetNull", this.topID, 0);
+ this.cmd("SetNull", this.linkedListElemID[this.top], 1);
+ }
+ else
+ {
+ this.cmd("Connect", this.linkedListElemID[this.top], this.linkedListElemID[this.top - 1]);
+ this.cmd("Step");
+ this.cmd("Disconnect", this.topID, this.linkedListElemID[this.top-1]);
+ }
+ this.cmd("Connect", this.topID, this.linkedListElemID[this.top]);
+
+ this.cmd("Step");
+ this.top = this.top + 1;
+ this.resetLinkedListPositions();
+ this.cmd("Delete", labPushID);
+ this.cmd("Step");
+
+ return this.commands;
+}
+
+StackLL.prototype.pop = function(ignored)
+{
+ this.commands = new Array();
+
+ var labPopID = this.nextIndex++;
+ var labPopValID = this.nextIndex++;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+
+ this.cmd("CreateLabel", labPopID, "Popped Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPopValID,this.arrayData[this.top - 1], LINKED_LIST_START_X, LINKED_LIST_START_Y);
+
+ this.cmd("Move", labPopValID, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+ this.cmd("Step");
+ this.cmd("Disconnect", this.topID, this.linkedListElemID[this.top - 1]);
+
+ if (this.top == 1)
+ {
+ this.cmd("SetNull", this.topID, 1);
+ }
+ else
+ {
+ this.cmd("Connect", this.topID, this.linkedListElemID[this.top-2]);
+
+ }
+ this.cmd("Step");
+ this.cmd("Delete", this.linkedListElemID[this.top - 1]);
+ this.top = this.top - 1;
+ this.resetLinkedListPositions();
+
+ this.cmd("Delete", labPopValID)
+ this.cmd("Delete", labPopID);
+ this.cmd("SetText", this.leftoverLabelID, "Popped Value: " + this.arrayData[this.top]);
+
+
+
+ return this.commands;
+}
+
+
+
+StackLL.prototype.clearAll = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < this.top; i++)
+ {
+ this.cmd("Delete", this.linkedListElemID[i]);
+ }
+ this.top = 0;
+ this.cmd("SetNull", this.topID, 1);
+ return this.commands;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new StackLL(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TST.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TST.js
new file mode 100644
index 0000000..f693121
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TST.js
@@ -0,0 +1,876 @@
+// Copyright 2016 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 LIIBTED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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
+
+
+// Constants.
+
+
+Ternary.NODE_WIDTH = 30;
+
+Ternary.CENTER_LINK_COLOR = "#007700";
+Ternary.SIDE_LINK_COLOR = "#8888AA";
+Ternary.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+Ternary.FOREGROUND_COLOR = "#007700";
+Ternary.BACKGROUND_COLOR = "#CCFFCC";
+Ternary.TRUE_COLOR = "#CCFFCC";
+Ternary.PRINT_COLOR = Ternary.FOREGROUND_COLOR;
+Ternary.FALSE_COLOR = "#FFFFFF"
+Ternary.WIDTH_DELTA = 50;
+Ternary.HEIGHT_DELTA = 50;
+Ternary.STARTING_Y = 20;
+Ternary.LeftMargin = 300;
+Ternary.NEW_NODE_Y = 100
+Ternary.NEW_NODE_X = 50;
+Ternary.FIRST_PRINT_POS_X = 50;
+Ternary.PRINT_VERTICAL_GAP = 20;
+Ternary.PRINT_HORIZONTAL_GAP = 50;
+
+
+
+function Ternary(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+Ternary.prototype = new Algorithm();
+Ternary.prototype.constructor = Ternary;
+Ternary.superclass = Algorithm.prototype;
+
+Ternary.prototype.init = function(am, w, h)
+{
+ var sc = Ternary.superclass;
+ this.startingX = w / 2;
+ this.first_print_pos_y = h - 2 * Ternary.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 10, 0);
+ this.cmd("CreateLabel", 1, "", 20, 10, 0);
+ this.cmd("CreateLabel", 2, "", 20, 30, 0);
+ this.nextIndex = 3;
+ this.root = null;
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+Ternary.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeypress = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 12,false);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 12);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 12);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+}
+
+Ternary.prototype.reset = function()
+{
+ this.nextIndex = 3;
+ this.root = null;
+}
+
+Ternary.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value.toUpperCase()
+ insertedValue = insertedValue.replace(/[^a-z]/gi,'');
+
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.add.bind(this), insertedValue);
+ }
+}
+
+
+Ternary.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value.toUpperCase();
+ deletedValue = deletedValue.replace(/[^a-z]/gi,'');
+ if (deletedValue != "")
+ {
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+
+}
+
+
+Ternary.prototype.cleanupAfterDelete = function(tree)
+{
+ if (tree == null)
+ {
+ return;
+ }
+ else if (tree.center != null)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("SetText", 2, "Clerning up after delete ...\nTree has center child, no more cleanup required");
+ this.cmd("step");
+ this.cmd("SetText", 2, "");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ return;
+ }
+ else if (tree.center == null && tree.right == null && tree.left == null && tree.isword == true)
+ {
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("SetText", 2, "Clerning up after delete ...\nLeaf at end of word, no more cleanup required");
+ this.cmd("step");
+ this.cmd("SetText", 2, "");
+ this.cmd("SetHighlight", tree.graphicID, 0);
+ return;
+ }
+ else if (tree.center == null && tree.left == null && tree.right == null)
+ {
+ this.cmd("SetText", 2, "Clearning up after delete ...");
+ this.cmd("SetHighlight", tree.graphicID, 1);
+ this.cmd("step");
+ this.cmd("Delete", tree.graphicID);
+ if (tree.parent == null)
+ {
+ this.root = null;
+ }
+ else if (tree.parent.left == tree)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ tree.parent.left = null;
+ }
+ else if (tree.parent.right == tree)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ tree.parent.right = null;
+ }
+ else if (tree.parent.center == tree)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ tree.parent.center = null;
+ tree.parent.charAt = " ";
+ this.cmd("SetText", tree.parent.graphicID, " ");
+ }
+ this.cleanupAfterDelete(tree.parent);
+ }
+ else if ((tree.left == null && tree.center == null) || (tree.right == null && tree.center == null))
+ {
+ var child = null
+ if (tree.left != null)
+ child = tree.left
+ else
+ child = tree.right;
+ this.cmd("Disconnect", tree.graphicID, child.graphicID);
+ if (tree.parent == null)
+ {
+ this.cmd("Delete", tree.graphicID);
+ this.root = child;
+ }
+ else if (tree.parent.left == tree)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, child.graphicID, Ternary.SIDE_LINK_COLOR, 0.0001, false, "<" + tree.parent.nextChar)
+ tree.parent.left = child;
+ child.parent = tree.parent;
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ }
+ else if (tree.parent.right == tree)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, child.graphicID, Ternary.SIDE_LINK_COLOR, -0.0001, false, ">" + tree.parent.nextChar)
+ tree.parent.right = child;
+ child.parent = tree.parent;
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ }
+ else if (tree.parent.center == tree)
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Connect", tree.parent.graphicID, child.graphicID, Ternary.CENTER_LINK_COLOR, 0.0001, false, "=" + tree.parent.nextChar)
+ child.parent = tree.parent;
+ tree.parent.center = child;
+ this.cmd("Step");
+ this.cmd("Delete", tree.graphicID);
+ }
+ else
+ {
+ throw("What??")
+ }
+ }
+ else if (tree.right != null && tree.center == null && tree.right != null)
+ {
+ var node = tree.left;
+
+ var parent = tree.parent;
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("Move", this.highlightID, node.x, node.y);
+ this.cmd("Step")
+ while (node.right != null)
+ {
+ node = node.right;
+ this.cmd("Move", this.highlightID, node.x, node.y);
+ this.cmd("Step")
+ }
+ if (tree.left != node)
+ {
+ this.cmd("Disconnect", node.parent.graphicID, node.graphicID);
+ node.parent.right = node.left;
+ if (node.left != null)
+ {
+ node.left.parent = node.parent;
+ this.cmd("Disconnect", node.graphicID, node.left.graphicID);
+ this.cmd("Connect", node.parent.graphicID, node.left.graphicID, Ternary.CENTER_LINK_COLOR, -0.0001, false, ">" + node.parent.nextChar)
+ }
+ this.cmd("Disconnect", tree.graphicID, tree.right.graphicID);
+ this.cmd("Disconnect", tree.graphicID, tree.left.graphicID);
+ node.right = tree.right;
+ node.left = tree.left;
+ tree.right.parent = node;
+ tree.left.parent = node;
+ this.cmd("Connect", node.graphicID, node.left.graphicID, Ternary.SIDE_LINK_COLOR, 0.0001, false, "<" + node.nextChar)
+ this.cmd("Connect", node.graphicID, node.right.graphicID, Ternary.SIDE_LINK_COLOR, -0.0001, false, ">" + node.nextChar)
+
+ }
+ else
+ {
+ this.cmd("Disconnect", tree.graphicID, tree.left.graphicID);
+ this.cmd("Disconnect", tree.graphicID, tree.right.graphicID);
+ node.right = tree.right;
+ node.right.parent = node;
+ this.cmd("Connect", node.graphicID, node.right.graphicID, Ternary.SIDE_LINK_COLOR, -0.0001, false, ">" + node.nextChar)
+ }
+ this.cmd("Delete", this.highlightID);
+ this.cmd("Delete", tree.graphicID);
+ this.cmd("Step");
+ node.parent = tree.parent;
+ if (node.parent == null)
+ {
+ this.root = node;
+ }
+ else
+ {
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ if (tree.parent.left == tree)
+ {
+ tree.parent.left = node;
+ node.parent = tree.parent;
+ this.cmd("Connect", node.parent.graphicID, node.graphicID, Ternary.SIDE_LINK_COLOR, 0.0001, false, "<" + node.parent.nextChar)
+
+ }
+ else if (tree.parent.right == tree)
+ {
+ tree.parent.right = node;
+ node.parent = tree.parent;
+ this.cmd("Connect", node.parent.graphicID, node.graphicID, Ternary.SIDE_LINK_COLOR, -0.0001, false, ">" + node.parent.nextChar)
+
+ }
+ else if (tree.parent.center == tree)
+ {
+ tree.parent.center = node;
+ node.parent = tree.parent;
+ this.cmd("Connect", node.parent.graphicID, node.graphicID, Ternary.CENTER_LINK_COLOR, 0.0001, false, "=" + node.parent.nextChar)
+
+ }
+ else
+ {
+
+
+ }
+
+ }
+
+ }
+}
+
+
+Ternary.prototype.deleteElement = function(word)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "正在刪除: ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+
+
+ var node = this.doFind(this.root, word);
+ if (node != null)
+ {
+ this.cmd("SetHighlight", node.graphicID , 1);
+ this.cmd("SetText", 2, "Found \""+word+"\", setting value in tree to False");
+ this.cmd("step")
+ this.cmd("SetBackgroundColor", node.graphicID, Ternary.FALSE_COLOR);
+ node.isword = false
+ this.cmd("SetHighlight", node.graphicID , 0);
+ this.cleanupAfterDelete(node)
+ this.resizeTree()
+ }
+ else
+ {
+ this.cmd("SetText", 2, "\""+word+"\" not in tree, nothing to delete");
+ this.cmd("step")
+ this.cmd("SetHighlightIndex", 1, -1)
+ }
+
+
+
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+ return this.commands;
+}
+
+
+
+Ternary.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+
+Ternary.prototype.printTree = function(unused)
+{
+
+ this.commands = [];
+
+ if (this.root != null)
+ {
+ this.highlightID = this.nextIndex++;
+ this.printLabel1 = this.nextIndex++;
+ this.printLabel2 = this.nextIndex++;
+ var firstLabel = this.nextIndex++;
+ this.cmd("CreateLabel", firstLabel, "Output: ", Ternary.FIRST_PRINT_POS_X, this.first_print_pos_y);
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, this.root.x, this.root.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("CreateLabel", this.printLabel1, "Current String: ", 20, 10, 0);
+ this.cmd("CreateLabel", this.printLabel2, "", 20, 10, 0);
+ this.cmd("AlignRight", this.printLabel2, this.printLabel1);
+ this.xPosOfNextLabel = Ternary.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.root, "");
+
+// this.cmd("SetText", this.printLabel1, "About to delete");
+// this.cmd("Step")
+
+ this.cmd("Delete", this.highlightID);
+ this.cmd("Delete", this.printLabel1);
+ this.cmd("Delete", this.printLabel2);
+ this.cmd("Step")
+
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+
+
+}
+
+Ternary.prototype.printTreeRec = function(tree, stringSoFar)
+{
+ if (tree.isword)
+ {
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, stringSoFar + " ", 20, 10, 0);
+ this.cmd("SetForegroundColor", nextLabelID, Ternary.PRINT_COLOR);
+ this.cmd("AlignRight", nextLabelID, this.printLabel1, Ternary.PRINT_COLOR);
+ this.cmd("MoveToAlignRight", nextLabelID, nextLabelID - 1);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += Ternary.PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = Ternary.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += Ternrary.PRINT_VERTICAL_GAP;
+ }
+
+
+ }
+ if (tree.left != null)
+ {
+ this.cmd("Move", this.highlightID, tree.left.x, tree.left.y);
+ this.cmd("Step");
+ this.printTreeRec(tree.left, stringSoFar);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+
+
+ }
+ if (tree.center != null)
+ {
+ var nextLabelID = this.nextIndex;
+ this.cmd("CreateLabel", nextLabelID, tree.nextChar, tree.x, tree.y, 0);
+ this.cmd("MoveToAlignRight", nextLabelID, this.printLabel2);
+
+ this.cmd("Move", this.highlightID, tree.center.x, tree.center.y);
+ this.cmd("Step");
+ this.cmd("Delete", nextLabelID);
+ this.cmd("SetText", this.printLabel2, stringSoFar + tree.nextChar);
+ this.printTreeRec(tree.center, stringSoFar + tree.nextChar);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", this.printLabel2, stringSoFar);
+ this.cmd("Step");
+
+
+ }
+ if (tree.right != null)
+ {
+ this.cmd("Move", this.highlightID, tree.right.x, tree.right.y);
+ this.cmd("Step");
+ this.printTreeRec(tree.right, stringSoFar);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("Step");
+ }
+}
+
+Ternary.prototype.findCallback = function(event)
+{
+ var findValue = this.findField.value.toUpperCase()
+ finndValue = findValue.replace(/[^a-z]/gi,'');
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+Ternary.prototype.findElement = function(word)
+{
+ this.commands = [];
+
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在搜索: ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+
+
+ var node = this.doFind(this.root, word);
+ if (node != null)
+ {
+ this.cmd("SetText", 0, "Found \""+word+"\"");
+ }
+ else
+ {
+ this.cmd("SetText", 0, "\""+word+"\" not Found");
+ }
+
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+ return this.commands;
+}
+
+
+Ternary.prototype.doFind = function(tree, s)
+{
+
+ if (tree == null)
+ {
+ this.cmd("SetText", 2, "Reached null tree\nWord is not in the tree");
+ this.cmd("Step");
+ return null;
+ }
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ if (s.length == 0)
+ {
+ if (tree.isword == true)
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nCurrent node is True\nWord is in the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return tree
+ }
+ else
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nCurrent node is False\nWord is Not the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null
+
+ }
+ }
+ else
+ {
+ this.cmd("SetHighlightIndex", 1, 1);
+
+ var child = null;
+ if (tree.nextChar == " ")
+ {
+ this.cmd("SetText", 2, "Reached a leaf without a character, still have characeters left in search string \nString is not in the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null;
+ }
+
+ if (tree.nextChar == s.charAt(0))
+ {
+ this.cmd("SetText", 2, "Next character in string matches character at current node\nRecursively look at center child, \nremoving first letter from search string");
+ this.cmd("Step");
+ s = s.substring(1);
+ child = tree.center;
+ }
+ else if (tree.nextChar > s.charAt(0))
+ {
+ this.cmd("SetText", 2, "Next character in string < Character at current node\nRecursively look at left node, \nleaving search string as it is");
+ this.cmd("Step");
+ child = tree.left;
+ }
+ else
+ {
+ this.cmd("SetText", 2, "Next character in string > Character at current node\nRecursively look at left right, \nleaving search string as it is");
+ this.cmd("Step");
+ child = tree.right;
+ }
+ if (child != null)
+ {
+ this.cmd("SetText", 1, "\""+s+"\"");
+ this.cmd("SetHighlightIndex", 1, -1);
+
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("SetHighlight", tree.graphicID , 0);
+
+ this.cmd("Move", this.highlightID, child.x, child.y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+
+ }
+ else
+ {
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ }
+ return this.doFind(child, s)
+ }
+}
+
+Ternary.prototype.insertElement = function(insertedValue)
+{
+ this.cmd("SetText", 0, "");
+ return this.commands;
+}
+
+
+Ternary.prototype.insert = function(elem, tree)
+{
+
+}
+
+
+
+Ternary.prototype.resizeTree = function()
+{
+ this.resizeWidths(this.root);
+ if (this.root != null)
+ {
+ var startingPoint = Ternary.LeftMargin;
+ if (this.root.left == null)
+ {
+ startingPoint += Ternary.NODE_WIDTH / 2;
+ }
+ else
+ {
+ startingPoint += this.root.left.width;
+ }
+
+// var startingPoint = this.root.width / 2 + 1 + Ternary.LeftMargin;
+ this.setNewPositions(this.root, startingPoint, Ternary.STARTING_Y);
+ this.animateNewPositions(this.root);
+ this.cmd("Step");
+ }
+
+}
+
+
+Ternary.prototype.add = function(word)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "Inserting; ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+ if (this.root == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, " ", Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, Ternary.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, Ternary.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Creating a new root");
+ this.root = new TernaryNode(" ", this.nextIndex, Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y)
+ this.cmd("Step");
+ this.resizeTree();
+ this.cmd("SetText", 2, "" );
+ this.nextIndex += 1;
+ this.highlightID = this.nextIndex++;
+
+ }
+ this.addR(word.toUpperCase(), this.root);
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+ return this.commands;
+}
+
+
+Ternary.prototype.createIfNotExtant = function (tree, child, label)
+{
+ if (child == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, " ", Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, Ternary.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, Ternary.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Creating a new node");
+ child = new TernaryNode(" ", this.nextIndex, Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y)
+ this.cmd("Step");
+ var dir = 0.0001;
+ if (label.charAt(0) == '>')
+ {
+ dir = -0.0001
+
+ }
+ var color = Ternary.FOREGROUND_COLOR;
+ if (label.charAt(0) == "=")
+ {
+ color = Ternary.CENTER_LINK_COLOR;
+ }
+ else
+ {
+ color = Ternary.SIDE_LINK_COLOR;
+ }
+ this.cmd("Connect", tree.graphicID, this.nextIndex, color, dir, false, label)
+ this.cmd("SetText", 2, "" );
+ this.nextIndex++;
+ this.highlightID = this.nextIndex++;
+
+ }
+ return child;
+}
+
+
+Ternary.prototype.addR = function(s, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ if (s.length == 0)
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nSet current node to true");
+ this.cmd("Step");
+ this.cmd("SetBackgroundColor", tree.graphicID, Ternary.TRUE_COLOR);
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ tree.isword = true;
+ return;
+ }
+ else
+ {
+ this.cmd("SetHighlightIndex", 1, 1);
+ if (tree.nextChar == ' ')
+ {
+ tree.nextChar = s.charAt(0);
+ this.cmd("SetText", 2, "No character for this node, setting to " + s.charAt(0));
+ this.cmd("SetText", tree.graphicID, s.charAt(0));
+ this.cmd("Step");
+ if (tree.center == null)
+ {
+ tree.center = this.createIfNotExtant(tree, tree.center, "="+s.charAt(0));
+ tree.center.parent = tree;
+ this.resizeTree();
+
+ }
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("Move", this.highlightID, tree.center.x, tree.center.y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+
+ this.addR(s.substring(1), tree.center)
+ }
+ else if (tree.nextChar == s.charAt(0))
+ {
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Making recursive call to center child, passing in \"" + s.substring(1) + "\"");
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+ this.cmd("Move", this.highlightID, tree.center.x, tree.center.y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+ this.addR(s.substring(1), tree.center)
+ }
+ else
+ {
+ var child = null;
+ var label = "";
+ if (tree.nextChar > s.charAt(0))
+ {
+ label = "<" + tree.nextChar;
+ this.cmd("SetText", 2, "Next character in stirng is < value stored at current node \n Making recursive call to left child passing in \"" + s+ "\"");
+ tree.left = this.createIfNotExtant(tree, tree.left, label);
+ tree.left.parent = tree;
+ this.resizeTree();
+ child = tree.left;
+ }
+ else
+ {
+ label = ">" + tree.nextChar;
+ this.cmd("SetText", 2, "Next character in stirng is > value stored at current node \n Making recursive call to right child passing in \"" + s + "\"");
+ tree.right= this.createIfNotExtant(tree, tree.right, label);
+ tree.right.parent = tree;
+ child = tree.right;
+ this.resizeTree();
+
+ }
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlightIndex", 1, -1);
+// this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+
+ this.cmd("Move", this.highlightID, child.x, child.y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+ this.addR(s, child)
+ }
+ }
+}
+Ternary.prototype.setNewPositions = function(tree, xLeft, yPosition)
+{
+ if (tree != null)
+ {
+ tree.x = xLeft + Ternary.NODE_WIDTH / 2;
+ tree.y = yPosition;
+ var newYPos = yPosition + Ternary.HEIGHT_DELTA;
+ if (tree.left != null)
+ {
+ this.setNewPositions(tree.left, xLeft, newYPos);
+ }
+ if (tree.center != null)
+ {
+ this.setNewPositions(tree.center, xLeft + tree.leftWidth, newYPos);
+ tree.x = tree.center.x;
+ }
+ if (tree.right != null)
+ {
+ this.setNewPositions(tree.right, xLeft + tree.leftWidth + tree.centerWidth, newYPos);
+ }
+
+ }
+
+}
+Ternary.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ this.animateNewPositions(tree.left)
+ this.animateNewPositions(tree.center)
+ this.animateNewPositions(tree.right)
+
+ }
+}
+
+Ternary.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = (this.resizeWidths(tree.left));
+ tree.centerWidth = (this.resizeWidths(tree.center));
+ tree.rightWidth = (this.resizeWidths(tree.right));
+ tree.width = Math.max(tree.leftWidth + tree.centerWidth+tree.rightWidth, Ternary.NODE_WIDTH + 4);
+ return tree.width;
+}
+
+
+
+
+function TernaryNode(val, id, initialX, initialY)
+{
+ this.nextChar = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+
+ this.left = null;
+ this.center = null;
+ this.right = null;
+ this.leftWidth = 0;
+ this.centerWidth = 0;
+ this.rightWwidth = 0;
+ this.parent = null;
+}
+
+Ternary.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+Ternary.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Ternary(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TestAlgorithmOld.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TestAlgorithmOld.js
new file mode 100644
index 0000000..2c5e150
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TestAlgorithmOld.js
@@ -0,0 +1,108 @@
+// 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 ``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 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
+
+
+function TestAlgorithm(am)
+{
+ this.init(am);
+
+}
+
+TestAlgorithm.prototype = new Algorithm();
+TestAlgorithm.prototype.constructor = TestAlgorithm;
+TestAlgorithm.superclass = Algorithm.prototype;
+
+TestAlgorithm.prototype.init = function(am)
+{
+ var sc = TestAlgorithm.superclass;
+ var fn = sc.init;
+ fn.call(this,am);
+// TestAlgorithm.superclass.init.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+
+}
+
+TestAlgorithm.prototype.addControls = function()
+{
+ this.doWorkButton = addControlToAlgorithmBar("Button", "Do Work");
+ this.doWorkButton.onclick = this.doWork.bind(this);
+}
+
+TestAlgorithm.prototype.reset = function()
+{
+ this.nextIndex = 0;
+}
+
+TestAlgorithm.prototype.doWork = function()
+{
+ this.implementAction(this.work.bind(this), "ignore");
+}
+
+
+TestAlgorithm.prototype.work = function(ignore)
+{
+ var circle1 = this.nextIndex++;
+ var circle2 = this.nextIndex++;
+ var circle3 = this.nextIndex++;
+ this.commands = [];
+ this.cmd("CreateCircle", circle1, circle1, 100,100);
+ this.cmd("Step");
+ this.cmd("Move", circle1, 200,100);
+ this.cmd("Step");
+ this.cmd("CreateCircle", circle2, circle2, 75,75);
+ this.cmd("Step");
+ this.cmd("Connect", circle1, circle2, "#FF3333", 0, true, "Label");
+ this.cmd("Step");
+ this.cmd("CreateCircle", circle3, "Foo" + String(circle3), 200,200);
+ this.cmd("Step");
+ this.cmd("Delete", circle1);
+ this.cmd("Step");
+ this.cmd("Move", circle2, 100, 200);
+ this.cmd("Step");
+ this.cmd("Move", circle3, 0, 0);
+ return this.commands;
+}
+
+
+TestAlgorithm.prototype.disableUI = function(event)
+{
+ this.doWorkButton.disabled = true;
+}
+
+TestAlgorithm.prototype.enableUI = function(event)
+{
+ this.doWorkButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new TestAlgorithm(animManag);
+}
\ No newline at end of file
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TopoSortDFS.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TopoSortDFS.js
new file mode 100644
index 0000000..6619f64
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TopoSortDFS.js
@@ -0,0 +1,396 @@
+// 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 ``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 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
+
+function TopoSortDFS(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+TopoSortDFS.ORDERING_INITIAL_X = 300;
+TopoSortDFS.ORDERING_INITIAL_Y = 70;
+TopoSortDFS.ORDERING_DELTA_Y = 20;
+
+TopoSortDFS.D_X_POS_SMALL = [760, 685, 915, 610, 910, 685, 915, 760];
+TopoSortDFS.F_X_POS_SMALL = [760, 685, 915, 610, 910, 685, 915, 760];
+
+
+
+TopoSortDFS.D_Y_POS_SMALL = [18, 118, 118, 218, 218, 318, 318, 418];
+TopoSortDFS.F_Y_POS_SMALL = [32, 132, 132, 232, 232, 332, 332, 432];
+
+TopoSortDFS.D_X_POS_LARGE = [560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860];
+
+TopoSortDFS.F_X_POS_LARGE = [560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860,
+ 610, 710, 810,
+ 560, 660, 760, 860];
+
+
+
+TopoSortDFS.D_Y_POS_LARGE = [037, 037, 037, 037,
+ 137, 137, 137,
+ 237, 237, 237, 237,
+ 337, 337, 337,
+ 437, 437, 437, 437];
+
+TopoSortDFS.F_Y_POS_LARGE = [62, 62, 62, 62,
+ 162, 162, 162,
+ 262, 262, 262, 262,
+ 362, 362, 362,
+ 462, 462, 462, 462];
+
+
+TopoSortDFS.HIGHLIGHT_CIRCLE_COLOR = "#000000";
+TopoSortDFS.DFS_TREE_COLOR = "#0000FF";
+
+
+
+TopoSortDFS.prototype = new Graph();
+TopoSortDFS.prototype.constructor = TopoSortDFS;
+TopoSortDFS.superclass = Graph.prototype;
+
+TopoSortDFS.prototype.addControls = function()
+{
+ this.startButton = addControlToAlgorithmBar("Button", "Do Topological Sort");
+ this.startButton.onclick = this.startCallback.bind(this);
+ TopoSortDFS.superclass.addControls.call(this, false);
+}
+
+
+TopoSortDFS.prototype.init = function(am, w, h)
+{
+ this.showEdgeCosts = false;
+ TopoSortDFS.superclass.init.call(this, am, w, h, true, true); // TODO: add no edge label flag to this?
+ // Setup called in base class init function
+}
+
+
+TopoSortDFS.prototype.setup = function()
+{
+ TopoSortDFS.superclass.setup.call(this);
+ this.messageID = new Array();
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+
+ this.highlightCircleL = this.nextIndex++;
+ this.highlightCircleAL = this.nextIndex++;
+ this.highlightCircleAM= this.nextIndex++
+ this.initialIndex = this.nextIndex;
+
+ this.old_adj_matrix = new Array(this.size);
+ this.old_adj_list_list = new Array(this.size);
+ this.old_adj_list_index = new Array(this.size);
+ this.old_adj_list_edges = new Array(this.size);
+ for (var i = 0; i < this.size; i++)
+ {
+ this.old_adj_matrix[i] = new Array(this.size);
+ this.old_adj_list_index[i] = this.adj_list_index[i];
+ this.old_adj_list_list[i] = this.adj_list_list[i];
+ this.old_adj_list_edges[i] = new Array(this.size);
+ for (var j = 0; j < this.size; j++)
+ {
+ this.old_adj_matrix[i][j] = this.adj_matrix[i][j];
+ if (this.adj_matrix[i][j] > 0)
+ {
+ this.old_adj_list_edges[i][j] = this.adj_list_edges[i][j];
+ }
+
+ }
+ }
+}
+
+
+TopoSortDFS.prototype.startCallback = function(event)
+{
+ this.implementAction(this.doTopoSort.bind(this),"");
+}
+
+
+
+TopoSortDFS.prototype.doTopoSort = function(ignored)
+{
+ this.visited = new Array(this.size);
+ this.commands = new Array();
+ this.topoOrderArrayL = new Array();
+ this.topoOrderArrayAL = new Array();
+ this.topoOrderArrayAM = new Array();
+ var i;
+ if (this.messageID != null)
+ {
+ for (i = 0; i < this.messageID.length; i++)
+ {
+ this.cmd("Delete", this.messageID[i], 1);
+ }
+ }
+ this.rebuildEdges(); // HMMM.. do I want this?
+ this.messageID = new Array();
+
+ var headerID = this.nextIndex++;
+ this.messageID.push(headerID);
+ this.cmd("CreateLabel", headerID, "Topological Order", TopoSortDFS.ORDERING_INITIAL_X, TopoSortDFS.ORDERING_INITIAL_Y - 1.5*TopoSortDFS.ORDERING_DELTA_Y);
+
+
+ headerID = this.nextIndex++;
+ this.messageID.push(headerID);
+ this.cmd("CreateRectangle", headerID, "", 100, 0, TopoSortDFS.ORDERING_INITIAL_X, TopoSortDFS.ORDERING_INITIAL_Y - TopoSortDFS.ORDERING_DELTA_Y,"center","center");
+
+
+
+ this.d_timesID_L = new Array(this.size);
+ this.f_timesID_L = new Array(this.size);
+ this.d_timesID_AL = new Array(this.size);
+ this.f_timesID_AL = new Array(this.size);
+ this.d_times = new Array(this.size);
+ this.f_times = new Array(this.size);
+ this.currentTime = 1
+ for (i = 0; i < this.size; i++)
+ {
+ this.d_timesID_L[i] = this.nextIndex++;
+ this.f_timesID_L[i] = this.nextIndex++;
+ this.d_timesID_AL[i] = this.nextIndex++;
+ this.f_timesID_AL[i] = this.nextIndex++;
+ }
+
+ this.messageY = 30;
+ var vertex;
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ if (!this.visited[vertex])
+ {
+ this.cmd("CreateHighlightCircle", this.highlightCircleL, TopoSortDFS.HIGHLIGHT_CIRCLE_COLOR, this.x_pos_logical[vertex], this.y_pos_logical[vertex]);
+ this.cmd("SetLayer", this.highlightCircleL, 1);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAL, TopoSortDFS.HIGHLIGHT_CIRCLE_COLOR,this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + vertex*this.adj_list_height);
+ this.cmd("SetLayer", this.highlightCircleAL, 2);
+
+ this.cmd("CreateHighlightCircle", this.highlightCircleAM, TopoSortDFS.HIGHLIGHT_CIRCLE_COLOR,this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + vertex*this.adj_matrix_height);
+ this.cmd("SetLayer", this.highlightCircleAM, 3);
+
+ if (vertex > 0)
+ {
+ var breakID = this.nextIndex++;
+ this.messageID.push(breakID);
+ this.cmd("CreateRectangle", breakID, "", 200, 0, 10, this.messageY,"left","bottom");
+ this.messageY = this.messageY + 20;
+ }
+ this.dfsVisit(vertex, 10, false);
+ this.cmd("Delete", this.highlightCircleL, 2);
+ this.cmd("Delete", this.highlightCircleAL, 3);
+ this.cmd("Delete", this.highlightCircleAM, 4);
+ }
+ }
+
+ return this.commands
+
+}
+
+
+TopoSortDFS.prototype.setup_large = function()
+{
+ this.d_x_pos = TopoSortDFS.D_X_POS_LARGE;
+ this.d_y_pos = TopoSortDFS.D_Y_POS_LARGE;
+ this.f_x_pos = TopoSortDFS.F_X_POS_LARGE;
+ this.f_y_pos = TopoSortDFS.F_Y_POS_LARGE;
+
+ TopoSortDFS.superclass.setup_large.call(this);
+}
+TopoSortDFS.prototype.setup_small = function()
+{
+
+ this.d_x_pos = TopoSortDFS.D_X_POS_SMALL;
+ this.d_y_pos = TopoSortDFS.D_Y_POS_SMALL;
+ this.f_x_pos = TopoSortDFS.F_X_POS_SMALL;
+ this.f_y_pos = TopoSortDFS.F_Y_POS_SMALL;
+
+ TopoSortDFS.superclass.setup_small.call(this);
+}
+
+TopoSortDFS.prototype.dfsVisit = function(startVertex, messageX, printCCNum)
+{
+ var nextMessage = this.nextIndex++;
+ this.messageID.push(nextMessage);
+ this.cmd("CreateLabel",nextMessage, "DFS(" + String(startVertex) + ")", messageX, this.messageY, 0);
+
+ this.messageY = this.messageY + 20;
+ if (!this.visited[startVertex])
+ {
+ this.d_times[startVertex] = this.currentTime++;
+ this.cmd("CreateLabel", this.d_timesID_L[startVertex], "d = " + String(this.d_times[startVertex]), this.d_x_pos[startVertex], this.d_y_pos[startVertex]);
+ this.cmd("CreateLabel", this.d_timesID_AL[startVertex], "d = " + String(this.d_times[startVertex]), this.adj_list_x_start - 2*this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height - 1/4*this.adj_list_height);
+ this.cmd("SetLayer", this.d_timesID_L[startVertex], 1);
+ this.cmd("SetLayer", this.d_timesID_AL[startVertex], 2);
+
+ this.visited[startVertex] = true;
+ this.cmd("Step");
+ for (var neighbor = 0; neighbor < this.size; neighbor++)
+ {
+ if (this.adj_matrix[startVertex][neighbor] > 0)
+ {
+ this.highlightEdge(startVertex, neighbor, 1);
+ if (this.visited[neighbor])
+ {
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Vertex " + String(neighbor) + " already this.visited.", messageX, this.messageY, 0);
+ }
+ this.cmd("Step");
+ this.highlightEdge(startVertex, neighbor, 0);
+ if (this.visited[neighbor])
+ {
+ this.cmd("Delete", nextMessage, "DNM");
+ }
+
+ if (!this.visited[neighbor])
+ {
+ this.cmd("Disconnect", this.circleID[startVertex], this.circleID[neighbor]);
+ this.cmd("Connect", this.circleID[startVertex], this.circleID[neighbor], TopoSortDFS.DFS_TREE_COLOR, this.curve[startVertex][neighbor], 1, "");
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[neighbor], this.y_pos_logical[neighbor]);
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + neighbor*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + neighbor*this.adj_matrix_height);
+
+ this.cmd("Step");
+ this.dfsVisit(neighbor, messageX + 10, printCCNum);
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Returning from recursive call: DFS(" + String(neighbor) + ")", messageX + 20, this.messageY, 0);
+
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[startVertex], this.y_pos_logical[startVertex]);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + startVertex*this.adj_matrix_height);
+ this.cmd("Step");
+ this.cmd("Delete", nextMessage, 18);
+ }
+ this.cmd("Step");
+
+
+
+ }
+
+ }
+
+
+ this.f_times[startVertex] = this.currentTime++;
+ this.cmd("CreateLabel", this.f_timesID_L[startVertex],"f = " + String(this.f_times[startVertex]), this.f_x_pos[startVertex], this.f_y_pos[startVertex]);
+ this.cmd("CreateLabel", this.f_timesID_AL[startVertex], "f = " + String(this.f_times[startVertex]), this.adj_list_x_start - 2*this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height + 1/4*this.adj_list_height);
+
+ this.cmd("SetLayer", this.f_timesID_L[startVertex], 1);
+ this.cmd("SetLayer", this.f_timesID_AL[startVertex], 2);
+
+ this.cmd("Step");
+
+ var i;
+ for (i = this.topoOrderArrayL.length; i > 0; i--)
+ {
+ this.topoOrderArrayL[i] = this.topoOrderArrayL[i-1];
+ this.topoOrderArrayAL[i] = this.topoOrderArrayAL[i-1];
+ this.topoOrderArrayAM[i] = this.topoOrderArrayAM[i-1];
+ }
+
+ var nextVertexLabel = this.nextIndex++;
+ this.messageID.push(nextVertexLabel);
+ this.cmd("CreateLabel", nextVertexLabel, startVertex, this.x_pos_logical[startVertex], this.y_pos_logical[startVertex]);
+ this.cmd("SetLayer", nextVertexLabel, 1);
+ this.topoOrderArrayL[0] = nextVertexLabel;
+
+ nextVertexLabel = this.nextIndex++;
+ this.messageID.push(nextVertexLabel);
+ this.cmd("CreateLabel", nextVertexLabel, startVertex,this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height);
+ this.cmd("SetLayer", nextVertexLabel, 2);
+ this.topoOrderArrayAL[0] = nextVertexLabel;
+
+ nextVertexLabel = this.nextIndex++;
+ this.messageID.push(nextVertexLabel);
+ this.cmd("CreateLabel", nextVertexLabel, startVertex,this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + startVertex*this.adj_matrix_height);
+ this.cmd("SetLayer", nextVertexLabel, 3);
+ this.topoOrderArrayAM[0] = nextVertexLabel;
+
+ for (i = 0; i < this.topoOrderArrayL.length; i++)
+ {
+ this.cmd("Move", this.topoOrderArrayL[i], TopoSortDFS.ORDERING_INITIAL_X,
+ TopoSortDFS.ORDERING_INITIAL_Y + i * TopoSortDFS.ORDERING_DELTA_Y);
+ this.cmd("Move", this.topoOrderArrayAL[i], TopoSortDFS.ORDERING_INITIAL_X,
+ TopoSortDFS.ORDERING_INITIAL_Y + i * TopoSortDFS.ORDERING_DELTA_Y);
+ this.cmd("Move", this.topoOrderArrayAM[i], TopoSortDFS.ORDERING_INITIAL_X,
+ TopoSortDFS.ORDERING_INITIAL_Y + i * TopoSortDFS.ORDERING_DELTA_Y);
+
+ }
+ this.cmd("Step");
+
+
+
+ }
+
+}
+
+
+TopoSortDFS.prototype.reset = function()
+{
+ // TODO: Fix undo messing with setup vars.
+ this.messageID = new Array();
+ this.nextIndex = this.initialIndex;
+ for (var i = 0; i < this.size; i++)
+ {
+ this.adj_list_list[i] = this.old_adj_list_list[i];
+ this.adj_list_index[i] = this.old_adj_list_index[i];
+
+ for (var j = 0; j < this.size; j++)
+ {
+ this.adj_matrix[i][j] = this.old_adj_matrix[i][j];
+ if (this.adj_matrix[i][j] > 0)
+ {
+ this.adj_list_edges[i][j] = this.old_adj_list_edges[i][j];
+ }
+ }
+ }
+
+}
+
+
+
+TopoSortDFS.prototype.enableUI = function(event)
+{
+ this.startButton.disabled = false;
+
+ TopoSortDFS.superclass.enableUI.call(this,event);
+}
+TopoSortDFS.prototype.disableUI = function(event)
+{
+
+ this.startButton.disabled = true;
+
+ TopoSortDFS.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new TopoSortDFS(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TopoSortIndegree.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TopoSortIndegree.js
new file mode 100644
index 0000000..f27fa59
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TopoSortIndegree.js
@@ -0,0 +1,459 @@
+// 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 ``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 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
+
+function TopoSortIndegree(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+
+
+TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH = 25;
+TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT = 25;
+TopoSortIndegree.INDEGREE_ARRAY_START_X = 50;
+TopoSortIndegree.INDEGREE_ARRAY_START_Y = 60;
+
+
+TopoSortIndegree.STACK_START_X = TopoSortIndegree.INDEGREE_ARRAY_START_X + 100;
+TopoSortIndegree.STACK_START_Y = TopoSortIndegree.INDEGREE_ARRAY_START_Y;
+TopoSortIndegree.STACK_HEIGHT = TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT;
+
+
+TopoSortIndegree.TOPO_ARRAY_START_X = TopoSortIndegree.STACK_START_X + 150;
+TopoSortIndegree.TOPO_ARRAY_START_Y = TopoSortIndegree.INDEGREE_ARRAY_START_Y;
+TopoSortIndegree.TOPO_HEIGHT = TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT;
+
+
+TopoSortIndegree.MESSAGE_LABEL_1_X = 70;
+TopoSortIndegree.MESSAGE_LABEL_1_Y = 10;
+
+TopoSortIndegree.MESSAGE_LABEL_2_X = 70;
+TopoSortIndegree.MESSAGE_LABEL_2_Y = 40;
+
+
+TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR = "#000000";
+TopoSortIndegree.MESSAGE_COLOR = "#0000FF";
+
+
+TopoSortIndegree.prototype = new Graph();
+TopoSortIndegree.prototype.constructor = TopoSortIndegree;
+TopoSortIndegree.superclass = Graph.prototype;
+
+TopoSortIndegree.prototype.addControls = function()
+{
+ this.startButton = addControlToAlgorithmBar("Button", "Do Topological Sort");
+ this.startButton.onclick = this.startCallback.bind(this);
+ TopoSortIndegree.superclass.addControls.call(this, false);
+}
+
+
+TopoSortIndegree.prototype.init = function(am, w, h)
+{
+ this.showEdgeCosts = false;
+ TopoSortIndegree.superclass.init.call(this, am, w, h, true, true); // TODO: add no edge label flag to this?
+ // Setup called in base class init function
+}
+
+
+TopoSortIndegree.prototype.setup = function()
+{
+ TopoSortIndegree.superclass.setup.call(this);
+ this.messageID = new Array();
+ this.animationManager.setAllLayers([0, this.currentLayer]);
+
+
+ this.messageID = new Array();
+ this.commands = new Array();
+ this.indegreeID = new Array(this.size);
+ this.setIndexID = new Array(this.size);
+ this.indegree = new Array(this.size);
+ this.orderID = new Array(this.size);
+
+
+
+ for (var i = 0; i < this.size; i++)
+ {
+ this.indegreeID[i] = this.nextIndex++;
+ this.setIndexID[i] = this.nextIndex++;
+ this.orderID[i] = this.nextIndex++;
+ this.cmd("CreateLabel", this.orderID[i], "", 0, 0); // HACK!!
+ this.cmd("CreateRectangle", this.indegreeID[i], " ", TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH, TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT, TopoSortIndegree.INDEGREE_ARRAY_START_X, TopoSortIndegree.INDEGREE_ARRAY_START_Y + i*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("CreateLabel", this.setIndexID[i], i, TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + i*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("SetForegroundColor", this.setIndexID[i], VERTEX_INDEX_COLOR);
+ }
+ this.cmd("CreateLabel", this.nextIndex++, "Indegree", TopoSortIndegree.INDEGREE_ARRAY_START_X - 1 * TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH, TopoSortIndegree.INDEGREE_ARRAY_START_Y - TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT * 1.5, 0);
+
+
+ this.message1ID = this.nextIndex++;
+ this.message2ID = this.nextIndex++;
+ this.cmd("CreateLabel", this.message1ID, "", TopoSortIndegree.MESSAGE_LABEL_1_X, TopoSortIndegree.MESSAGE_LABEL_1_Y, 0);
+ this.cmd("SetTextColor", this.message1ID, TopoSortIndegree.MESSAGE_COLOR);
+ this.cmd("CreateLabel", this.message2ID, "", TopoSortIndegree.MESSAGE_LABEL_2_X, TopoSortIndegree.MESSAGE_LABEL_2_Y);
+ this.cmd("SetTextColor", this.message2ID, TopoSortIndegree.MESSAGE_COLOR);
+
+ this.stackLabelID = this.nextIndex++;
+ this.topoLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", this.stackLabelID, "", TopoSortIndegree.STACK_START_X, TopoSortIndegree.STACK_START_Y - TopoSortIndegree.STACK_HEIGHT);
+ this.cmd("CreateLabel", this.topoLabelID, "", TopoSortIndegree.TOPO_ARRAY_START_X, TopoSortIndegree.TOPO_ARRAY_START_Y - TopoSortIndegree.TOPO_HEIGHT);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+ this.highlightCircleL = this.nextIndex++;
+ this.highlightCircleAL = this.nextIndex++;
+ this.highlightCircleAM= this.nextIndex++;
+
+ this.initialIndex = this.nextIndex;
+}
+
+
+TopoSortIndegree.prototype.startCallback = function(event)
+{
+ this.implementAction(this.doTopoSort.bind(this),"");
+}
+
+
+
+TopoSortIndegree.prototype.doTopoSort = function(ignored)
+{
+ this.commands = new Array();
+ var stack = new Array(this.size);
+ var stackID = new Array(this.size);
+ var stackTop = 0;
+
+ var vertex;
+ for (var vertex = 0; vertex < this.size; vertex++)
+ {
+ this.cmd("SetText", this.indegreeID[vertex], "0");
+ this.indegree[vertex] = 0;
+ stackID[vertex] = this.nextIndex++;
+ this.cmd("Delete", this.orderID[vertex]);
+ }
+
+ this.cmd("SetText", this.message1ID, "Calculate this.indegree of all verticies by going through every edge of the graph");
+ this.cmd("SetText", this.topoLabelID, "");
+ this.cmd("SetText", this.stackLabelID, "");
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ var adjListIndex = 0;
+ var neighbor;
+ for (neighbor = 0; neighbor < this.size; neighbor++)
+ if (this.adj_matrix[vertex][neighbor] >= 0)
+ {
+ adjListIndex++;
+ this.highlightEdge(vertex, neighbor, 1);
+ this.cmd("Step");
+
+ this.cmd("CreateHighlightCircle", this.highlightCircleL, TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR, this.x_pos_logical[neighbor], this.y_pos_logical[neighbor]);
+ this.cmd("SetLayer", this.highlightCircleL, 1);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAL, TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR,this.adj_list_x_start + adjListIndex * (this.adj_list_width + this.adj_list_spacing), this.adj_list_y_start + vertex*this.adj_list_height);
+ this.cmd("SetLayer", this.highlightCircleAL, 2);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAM, TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR,this.adj_matrix_x_start + neighbor * this.adj_matrix_width, this.adj_matrix_y_start - this.adj_matrix_height);
+ this.cmd("SetLayer", this.highlightCircleAM, 3);
+
+ this.cmd("Move", this.highlightCircleL,TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + neighbor*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+
+ this.cmd("Move", this.highlightCircleAL, TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + neighbor*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("Move", this.highlightCircleAM,TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + neighbor*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+
+ this.cmd("Step");
+ this.indegree[neighbor] = this.indegree[neighbor] + 1;
+ this.cmd("SetText", this.indegreeID[neighbor], this.indegree[neighbor]);
+ this.cmd("SetTextColor", this.indegreeID[neighbor], "#FF0000");
+ this.cmd("Step");
+ this.cmd("Delete", this.highlightCircleL);
+ this.cmd("Delete", this.highlightCircleAL);
+ this.cmd("Delete", this.highlightCircleAM);
+ this.cmd("SetTextColor", this.indegreeID[neighbor], EDGE_COLOR);
+ this.highlightEdge(vertex, neighbor, 0);
+ }
+
+ }
+ this.cmd("SetText", this.message1ID, "Collect all vertices with 0 this.indegree onto a stack");
+ this.cmd("SetText", this.stackLabelID, "Zero Indegree Vertices");
+
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ this.cmd("SetHighlight", this.indegreeID[vertex], 1);
+ this.cmd("Step");
+ if (this.indegree[vertex] == 0)
+ {
+ stack[stackTop] =vertex;
+ this.cmd("CreateLabel", stackID[stackTop], vertex, TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH, TopoSortIndegree.INDEGREE_ARRAY_START_Y + vertex*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("Move", stackID[stackTop], TopoSortIndegree.STACK_START_X, TopoSortIndegree.STACK_START_Y + stackTop * TopoSortIndegree.STACK_HEIGHT);
+ this.cmd("Step")
+ stackTop++;
+ }
+ this.cmd("SetHighlight", this.indegreeID[vertex], 0);
+
+ }
+
+ this.cmd("SetText", this.topoLabelID, "Topological Order");
+
+
+ var nextInOrder = 0;
+ while (stackTop > 0)
+ {
+ stackTop--;
+ var nextElem = stack[stackTop];
+ this.cmd("SetText", this.message1ID, "Pop off top vertex with this.indegree 0, add to topological sort");
+ this.cmd("CreateLabel", this.orderID[nextInOrder], nextElem, TopoSortIndegree.STACK_START_X, TopoSortIndegree.STACK_START_Y + stackTop * TopoSortIndegree.STACK_HEIGHT);
+ this.cmd("Delete", stackID[stackTop]);
+ this.cmd("Step");
+ this.cmd("Move", this.orderID[nextInOrder], TopoSortIndegree.TOPO_ARRAY_START_X, TopoSortIndegree.TOPO_ARRAY_START_Y + nextInOrder * TopoSortIndegree.TOPO_HEIGHT);
+ this.cmd("Step");
+ this.cmd("SetText", this.message1ID, "Find all neigbors of vertex " + String(nextElem) + ", decrease their this.indegree. If this.indegree becomes 0, add to stack");
+ this.cmd("SetHighlight", this.circleID[nextElem], 1);
+ this.cmd("Step")
+
+ adjListIndex = 0;
+
+ for (vertex = 0; vertex < this.size; vertex++)
+ {
+ if (this.adj_matrix[nextElem][vertex] >= 0)
+ {
+ adjListIndex++;
+ this.highlightEdge(nextElem, vertex, 1);
+ this.cmd("Step");
+
+ this.cmd("CreateHighlightCircle", this.highlightCircleL, TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR, this.x_pos_logical[vertex], this.y_pos_logical[vertex]);
+ this.cmd("SetLayer", this.highlightCircleL, 1);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAL, TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR,this.adj_list_x_start + adjListIndex * (this.adj_list_width + this.adj_list_spacing), this.adj_list_y_start + nextElem*this.adj_list_height);
+ this.cmd("SetLayer", this.highlightCircleAL, 2);
+ this.cmd("CreateHighlightCircle", this.highlightCircleAM, TopoSortIndegree.HIGHLIGHT_CIRCLE_COLOR,this.adj_matrix_x_start + vertex * this.adj_matrix_width, this.adj_matrix_y_start - this.adj_matrix_height);
+ this.cmd("SetLayer", this.highlightCircleAM, 3);
+
+ this.cmd("Move", this.highlightCircleL,TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + vertex*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+
+ this.cmd("Move", this.highlightCircleAL, TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + vertex*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("Move", this.highlightCircleAM,TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH ,TopoSortIndegree.INDEGREE_ARRAY_START_Y + vertex*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+
+ this.cmd("Step");
+ this.indegree[vertex] = this.indegree[vertex] - 1;
+ this.cmd("SetText", this.indegreeID[vertex], this.indegree[vertex]);
+ this.cmd("SetTextColor", this.indegreeID[vertex], "#FF0000");
+ this.cmd("Step");
+ if (this.indegree[vertex] == 0)
+ {
+ stack[stackTop] =vertex;
+ this.cmd("CreateLabel", stackID[stackTop], vertex, TopoSortIndegree.INDEGREE_ARRAY_START_X - TopoSortIndegree.INDEGREE_ARRAY_ELEM_WIDTH, TopoSortIndegree.INDEGREE_ARRAY_START_Y + vertex*TopoSortIndegree.INDEGREE_ARRAY_ELEM_HEIGHT);
+ this.cmd("Move", stackID[stackTop], TopoSortIndegree.STACK_START_X, TopoSortIndegree.STACK_START_Y + stackTop * TopoSortIndegree.STACK_HEIGHT);
+ this.cmd("Step");
+ stackTop++;
+ }
+ this.cmd("Delete", this.highlightCircleL);
+ this.cmd("Delete", this.highlightCircleAL);
+ this.cmd("Delete", this.highlightCircleAM);
+ this.cmd("SetTextColor", this.indegreeID[vertex], EDGE_COLOR);
+ this.highlightEdge(nextElem, vertex, 0);
+
+ }
+ }
+ this.cmd("SetHighlight", this.circleID[nextElem], 0);
+
+ nextInOrder++;
+
+
+
+ }
+
+
+ this.cmd("SetText", this.message1ID, "");
+ this.cmd("SetText", this.stackLabelID, "");
+
+ return this.commands
+
+}
+
+
+TopoSortIndegree.prototype.setup_large = function()
+{
+ this.d_x_pos = TopoSortIndegree.D_X_POS_LARGE;
+ this.d_y_pos = TopoSortIndegree.D_Y_POS_LARGE;
+ this.f_x_pos = TopoSortIndegree.F_X_POS_LARGE;
+ this.f_y_pos = TopoSortIndegree.F_Y_POS_LARGE;
+
+ TopoSortIndegree.superclass.setup_large.call(this);
+}
+TopoSortIndegree.prototype.setup_small = function()
+{
+
+ this.d_x_pos = TopoSortIndegree.D_X_POS_SMALL;
+ this.d_y_pos = TopoSortIndegree.D_Y_POS_SMALL;
+ this.f_x_pos = TopoSortIndegree.F_X_POS_SMALL;
+ this.f_y_pos = TopoSortIndegree.F_Y_POS_SMALL;
+
+ TopoSortIndegree.superclass.setup_small.call(this);
+}
+
+TopoSortIndegree.prototype.dfsVisit = function(startVertex, messageX, printCCNum)
+{
+ var nextMessage = this.nextIndex++;
+ this.messageID.push(nextMessage);
+ this.cmd("CreateLabel",nextMessage, "DFS(" + String(startVertex) + ")", messageX, this.messageY, 0);
+
+ this.messageY = this.messageY + 20;
+ if (!this.visited[startVertex])
+ {
+ this.d_times[startVertex] = this.currentTime++;
+ this.cmd("CreateLabel", this.d_timesID_L[startVertex], "d = " + String(this.d_times[startVertex]), this.d_x_pos[startVertex], this.d_y_pos[startVertex]);
+ this.cmd("CreateLabel", this.d_timesID_AL[startVertex], "d = " + String(this.d_times[startVertex]), this.adj_list_x_start - 2*this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height - 1/4*this.adj_list_height);
+ this.cmd("SetLayer", this.d_timesID_L[startVertex], 1);
+ this.cmd("SetLayer", this.d_timesID_AL[startVertex], 2);
+
+ this.visited[startVertex] = true;
+ this.cmd("Step");
+ for (var neighbor = 0; neighbor < this.size; neighbor++)
+ {
+ if (this.adj_matrix[startVertex][neighbor] > 0)
+ {
+ this.highlightEdge(startVertex, neighbor, 1);
+ if (this.visited[neighbor])
+ {
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Vertex " + String(neighbor) + " already this.visited.", messageX, this.messageY, 0);
+ }
+ this.cmd("Step");
+ this.highlightEdge(startVertex, neighbor, 0);
+ if (this.visited[neighbor])
+ {
+ this.cmd("Delete", nextMessage, "DNM");
+ }
+
+ if (!this.visited[neighbor])
+ {
+ this.cmd("Disconnect", this.circleID[startVertex], this.circleID[neighbor]);
+ this.cmd("Connect", this.circleID[startVertex], this.circleID[neighbor], TopoSortIndegree.DFS_TREE_COLOR, this.curve[startVertex][neighbor], 1, "");
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[neighbor], this.y_pos_logical[neighbor]);
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + neighbor*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + neighbor*this.adj_matrix_height);
+
+ this.cmd("Step");
+ this.dfsVisit(neighbor, messageX + 10, printCCNum);
+ nextMessage = this.nextIndex;
+ this.cmd("CreateLabel", nextMessage, "Returning from recursive call: DFS(" + String(neighbor) + ")", messageX + 20, this.messageY, 0);
+
+ this.cmd("Move", this.highlightCircleAL, this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height);
+ this.cmd("Move", this.highlightCircleL, this.x_pos_logical[startVertex], this.y_pos_logical[startVertex]);
+ this.cmd("Move", this.highlightCircleAM, this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + startVertex*this.adj_matrix_height);
+ this.cmd("Step");
+ this.cmd("Delete", nextMessage, 18);
+ }
+ this.cmd("Step");
+
+
+
+ }
+
+ }
+
+
+ this.f_times[startVertex] = this.currentTime++;
+ this.cmd("CreateLabel", this.f_timesID_L[startVertex],"f = " + String(this.f_times[startVertex]), this.f_x_pos[startVertex], this.f_y_pos[startVertex]);
+ this.cmd("CreateLabel", this.f_timesID_AL[startVertex], "f = " + String(this.f_times[startVertex]), this.adj_list_x_start - 2*this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height + 1/4*this.adj_list_height);
+
+ this.cmd("SetLayer", this.f_timesID_L[startVertex], 1);
+ this.cmd("SetLayer", this.f_timesID_AL[startVertex], 2);
+
+ this.cmd("Step");
+
+ var i;
+ for (i = this.topoOrderArrayL.length; i > 0; i--)
+ {
+ this.topoOrderArrayL[i] = this.topoOrderArrayL[i-1];
+ this.topoOrderArrayAL[i] = this.topoOrderArrayAL[i-1];
+ this.topoOrderArrayAM[i] = this.topoOrderArrayAM[i-1];
+ }
+
+ var nextVertexLabel = this.nextIndex++;
+ this.messageID.push(nextVertexLabel);
+ this.cmd("CreateLabel", nextVertexLabel, startVertex, this.x_pos_logical[startVertex], this.y_pos_logical[startVertex]);
+ this.cmd("SetLayer", nextVertexLabel, 1);
+ this.topoOrderArrayL[0] = nextVertexLabel;
+
+ nextVertexLabel = this.nextIndex++;
+ this.messageID.push(nextVertexLabel);
+ this.cmd("CreateLabel", nextVertexLabel, startVertex,this.adj_list_x_start - this.adj_list_width, this.adj_list_y_start + startVertex*this.adj_list_height);
+ this.cmd("SetLayer", nextVertexLabel, 2);
+ this.topoOrderArrayAL[0] = nextVertexLabel;
+
+ nextVertexLabel = this.nextIndex++;
+ this.messageID.push(nextVertexLabel);
+ this.cmd("CreateLabel", nextVertexLabel, startVertex,this.adj_matrix_x_start - this.adj_matrix_width, this.adj_matrix_y_start + startVertex*this.adj_matrix_height);
+ this.cmd("SetLayer", nextVertexLabel, 3);
+ this.topoOrderArrayAM[0] = nextVertexLabel;
+
+ for (i = 0; i < this.topoOrderArrayL.length; i++)
+ {
+ this.cmd("Move", this.topoOrderArrayL[i], TopoSortIndegree.ORDERING_INITIAL_X,
+ TopoSortIndegree.ORDERING_INITIAL_Y + i * TopoSortIndegree.ORDERING_DELTA_Y);
+ this.cmd("Move", this.topoOrderArrayAL[i], TopoSortIndegree.ORDERING_INITIAL_X,
+ TopoSortIndegree.ORDERING_INITIAL_Y + i * TopoSortIndegree.ORDERING_DELTA_Y);
+ this.cmd("Move", this.topoOrderArrayAM[i], TopoSortIndegree.ORDERING_INITIAL_X,
+ TopoSortIndegree.ORDERING_INITIAL_Y + i * TopoSortIndegree.ORDERING_DELTA_Y);
+
+ }
+ this.cmd("Step");
+
+
+
+ }
+
+}
+
+
+TopoSortIndegree.prototype.reset = function()
+{
+ this.nextIndex = this.oldNextIndex;
+ this.messageID = new Array();
+ this.nextIndex = this.initialIndex;
+}
+
+
+
+TopoSortIndegree.prototype.enableUI = function(event)
+{
+ this.startButton.disabled = false;
+
+ TopoSortIndegree.superclass.enableUI.call(this,event);
+}
+TopoSortIndegree.prototype.disableUI = function(event)
+{
+
+ this.startButton.disabled = true;
+
+ TopoSortIndegree.superclass.disableUI.call(this, event);
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new TopoSortIndegree(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Trie.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Trie.js
new file mode 100644
index 0000000..83e991c
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/Trie.js
@@ -0,0 +1,612 @@
+// Copyright 2016 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 LIIBTED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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
+
+
+// Constants.
+
+
+Trie.NODE_WIDTH = 30;
+
+Trie.LINK_COLOR = "#007700";
+Trie.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+Trie.FOREGROUND_COLOR = "#007700";
+Trie.BACKGROUND_COLOR = "#CCFFCC";
+Trie.TRUE_COLOR = "#CCFFCC";
+Trie.PRINT_COLOR = Trie.FOREGROUND_COLOR;
+Trie.FALSE_COLOR = "#FFFFFF"
+Trie.WIDTH_DELTA = 50;
+Trie.HEIGHT_DELTA = 50;
+Trie.STARTING_Y = 80;
+Trie.LeftMargin = 300;
+Trie.NEW_NODE_Y = 100
+Trie.NEW_NODE_X = 50;
+Trie.FIRST_PRINT_POS_X = 50;
+Trie.PRINT_VERTICAL_GAP = 20;
+Trie.PRINT_HORIZONTAL_GAP = 50;
+
+
+
+function Trie(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+Trie.prototype = new Algorithm();
+Trie.prototype.constructor = Trie;
+Trie.superclass = Algorithm.prototype;
+
+Trie.prototype.init = function(am, w, h)
+{
+ var sc = Trie.superclass;
+ this.startingX = w / 2;
+ this.first_print_pos_y = h - 2 * Trie.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 10, 0);
+ this.cmd("CreateLabel", 1, "", 20, 10, 0);
+ this.cmd("CreateLabel", 2, "", 20, 30, 0);
+ this.nextIndex = 3;
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+Trie.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeypress = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 12,false);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+ this.deleteField = addControlToAlgorithmBar("Text", "");
+ this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 12);
+ this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+ this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 12);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+ this.printButton = addControlToAlgorithmBar("Button", "打印");
+ this.printButton.onclick = this.printCallback.bind(this);
+}
+
+Trie.prototype.reset = function()
+{
+ this.nextIndex = 3;
+ this.root = null;
+}
+
+Trie.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value.toUpperCase()
+ insertedValue = insertedValue.replace(/[^a-z]/gi,'');
+
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.add.bind(this), insertedValue);
+ }
+}
+
+Trie.prototype.deleteCallback = function(event)
+{
+ var deletedValue = this.deleteField.value.toUpperCase();
+ deletedValue = deletedValue.replace(/[^a-z]/gi,'');
+ if (deletedValue != "")
+ {
+ this.deleteField.value = "";
+ this.implementAction(this.deleteElement.bind(this),deletedValue);
+ }
+
+}
+
+
+Trie.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+
+
+Trie.prototype.findCallback = function(event)
+{
+ var findValue = this.findField.value.toUpperCase()
+ finndValue = findValue.replace(/[^a-z]/gi,'');
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+
+
+Trie.prototype.printTree = function(unused)
+{
+
+ this.commands = [];
+
+ if (this.root != null)
+ {
+ this.highlightID = this.nextIndex++;
+ this.printLabel1 = this.nextIndex++;
+ this.printLabel2 = this.nextIndex++;
+ var firstLabel = this.nextIndex++;
+ this.cmd("CreateLabel", firstLabel, "Output: ", Trie.FIRST_PRINT_POS_X, this.first_print_pos_y);
+ this.cmd("CreateHighlightCircle", this.highlightID, Trie.HIGHLIGHT_CIRCLE_COLOR, this.root.x, this.root.y);
+ this.cmd("SetWidth", this.highlightID, Trie.NODE_WIDTH);
+ this.cmd("CreateLabel", this.printLabel1, "Current String: ", 20, 10, 0);
+ this.cmd("CreateLabel", this.printLabel2, "", 20, 10, 0);
+ this.cmd("AlignRight", this.printLabel2, this.printLabel1);
+ this.xPosOfNextLabel = Trie.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel = this.first_print_pos_y;
+ this.printTreeRec(this.root, "");
+
+ this.cmd("Delete", this.highlightID);
+ this.cmd("Delete", this.printLabel1);
+ this.cmd("Delete", this.printLabel2);
+ this.cmd("Step")
+
+ for (var i = firstLabel; i < this.nextIndex; i++)
+ {
+ this.cmd("Delete", i);
+ }
+ this.nextIndex = this.highlightID; /// Reuse objects. Not necessary.
+ }
+ return this.commands;
+
+}
+
+
+
+Trie.prototype.printTreeRec = function(tree, stringSoFar)
+{
+ if (tree.wordRemainder != "")
+ {
+ }
+ if (tree.isword)
+ {
+ var nextLabelID = this.nextIndex++;
+ this.cmd("CreateLabel", nextLabelID, stringSoFar + " ", 20, 10, 0);
+ this.cmd("SetForegroundColor", nextLabelID, Trie.PRINT_COLOR);
+ this.cmd("AlignRight", nextLabelID, this.printLabel1, Trie.PRINT_COLOR);
+ this.cmd("MoveToAlignRight", nextLabelID, nextLabelID - 1);
+ this.cmd("Step");
+
+ this.xPosOfNextLabel += Trie.PRINT_HORIZONTAL_GAP;
+ if (this.xPosOfNextLabel > this.print_max)
+ {
+ this.xPosOfNextLabel = Trie.FIRST_PRINT_POS_X;
+ this.yPosOfNextLabel += Trie.PRINT_VERTICAL_GAP;
+ }
+
+
+ }
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+
+ var stringSoFar2 = stringSoFar + tree.children[i].wordRemainder;
+ var nextLabelID = this.nextIndex++;
+ var fromx = (tree.children[i].x + tree.x) / 2 + Trie.NODE_WIDTH / 2;
+ var fromy = (tree.children[i].y + tree.y) / 2;
+ this.cmd("CreateLabel", nextLabelID, tree.children[i].wordRemainder,fromx, fromy, 0);
+ this.cmd("MoveToAlignRight", nextLabelID, this.printLabel2);
+ this.cmd("Move", this.highlightID, tree.children[i].x, tree.children[i].y);
+ this.cmd("Step");
+ this.cmd("Delete", nextLabelID);
+ this.nextIndex--;
+ this.cmd("SetText", this.printLabel2, stringSoFar2);
+
+ this.printTreeRec(tree.children[i], stringSoFar2);
+ this.cmd("Move", this.highlightID, tree.x, tree.y);
+ this.cmd("SetText", this.printLabel2, stringSoFar);
+ this.cmd("Step");
+
+ }
+
+
+ }
+}
+
+
+
+Trie.prototype.findElement = function(word)
+{
+ this.commands = [];
+
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在搜索: ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+
+
+ var node = this.doFind(this.root, word);
+ if (node != null)
+ {
+ this.cmd("SetText", 0, "Found \""+word+"\"");
+ }
+ else
+ {
+ this.cmd("SetText", 0, "\""+word+"\" not Found");
+ }
+
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+ return this.commands;
+}
+
+
+Trie.prototype.doFind = function(tree, s)
+{
+
+ if (tree == null)
+ {
+ return null;
+ }
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ if (s.length == 0)
+ {
+ if (tree.isword == true)
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nCurrent node is True\nWord is in the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return tree
+ }
+ else
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nCurrent node is False\nWord is Not the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null
+
+ }
+ }
+ else
+ {
+ this.cmd("SetHighlightIndex", 1, 1);
+ var index = s.charCodeAt(0) - "A".charCodeAt(0);
+ if (tree.children[index] == null)
+ {
+ this.cmd("SetText", 2, "Child " + s.charAt(0) + " does not exist\nWord is Not the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null
+ }
+ this.cmd("CreateHighlightCircle", this.highlightID, Trie.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Trie.NODE_WIDTH);
+ this.cmd("SetText", 2, "Making recursive call to " + s.charAt(0) + " child, passing in " + s.substring(1));
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+
+ this.cmd("Move", this.highlightID, tree.children[index].x, tree.children[index].y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+ return this.doFind(tree.children[index], s.substring(1))
+ }
+}
+
+Trie.prototype.insertElement = function(insertedValue)
+{
+ this.cmd("SetText", 0, "");
+ return this.commands;
+}
+
+
+Trie.prototype.insert = function(elem, tree)
+{
+
+}
+
+Trie.prototype.deleteElement = function(word)
+{
+ this.commands = [];
+ this.cmd("SetText", 0, "正在刪除: ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+
+
+ var node = this.doFind(this.root, word);
+ if (node != null)
+ {
+ this.cmd("SetHighlight", node.graphicID , 1);
+ this.cmd("SetText", 2, "Found \""+word+"\", setting value in tree to False");
+ this.cmd("step")
+ this.cmd("SetBackgroundColor", node.graphicID, Trie.FALSE_COLOR);
+ node.isword = false
+ this.cmd("SetHighlight", node.graphicID , 0);
+ this.cleanupAfterDelete(node)
+ this.resizeTree()
+ }
+ else
+ {
+ this.cmd("SetText", 2, "\""+word+"\" not in tree, nothing to delete");
+ this.cmd("step")
+ this.cmd("SetHighlightIndex", 1, -1)
+ }
+
+
+
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+ return this.commands;
+}
+
+
+
+Trie.prototype.numChildren = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ var children = 0
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ children++;
+ }
+ }
+ return children;
+
+}
+
+Trie.prototype.cleanupAfterDelete = function(tree)
+{
+ var children = this.numChildren(tree)
+
+ if (children == 0 && !tree.isword)
+ {
+ this.cmd("SetText", 2, "Deletion left us with a \"False\" leaf\nRemoving false leaf");
+ this.cmd("SetHighlight" ,tree.graphicID , 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ if (tree.parent != null)
+ {
+ var index = 0
+ while (tree.parent.children[index] != tree)
+ {
+ index++;
+ }
+ this.cmd("Disconnect", tree.parent.graphicID, tree.graphicID);
+ this.cmd("Delete", tree.graphicID , 0);
+ tree.parent.children[index] = null;
+ this.cleanupAfterDelete(tree.parent);
+ }
+ else
+ {
+ this.cmd("Delete", tree.graphicID , 0);
+ this.root = null;
+ }
+ }
+}
+
+Trie.prototype.resizeTree = function()
+{
+ this.resizeWidths(this.root);
+ if (this.root != null)
+ {
+ var startingPoint = this.root.width / 2 + 1 + Trie.LeftMargin;
+ this.setNewPositions(this.root, startingPoint, Trie.STARTING_Y);
+ this.animateNewPositions(this.root);
+ this.cmd("Step");
+ }
+
+}
+
+
+Trie.prototype.add = function(word)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "Inserting; ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+ if (this.root == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, "", Trie.NEW_NODE_X, Trie.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, Trie.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, Trie.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, Trie.NODE_WIDTH);
+ this.cmd("SetText", 2, "Creating a new root");
+ this.root = new TrieNode("", this.nextIndex, Trie.NEW_NODE_X, Trie.NEW_NODE_Y)
+ this.cmd("Step");
+ this.resizeTree();
+ this.cmd("SetText", 2, "" );
+ this.highlightID = this.nextIndex++;
+ this.nextIndex += 1;
+
+ }
+ this.addR(word.toUpperCase(), this.root);
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+ return this.commands;
+}
+
+
+Trie.prototype.addR = function(s, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ if (s.length == 0)
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nSet current node to true");
+ this.cmd("Step");
+// this.cmd("SetText", tree.graphicID, "T");
+ this.cmd("SetBackgroundColor", tree.graphicID, Trie.TRUE_COLOR);
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ tree.isword = true;
+ return;
+ }
+ else
+ {
+ this.cmd("SetHighlightIndex", 1, 1);
+ var index = s.charCodeAt(0) - "A".charCodeAt(0);
+ if (tree.children[index] == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, s.charAt(0), Trie.NEW_NODE_X, Trie.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, Trie.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, Trie.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, Trie.NODE_WIDTH);
+ this.cmd("SetText", 2, "Child " + s.charAt(0) + " does not exist. Creating ... ");
+ tree.children[index] = new TrieNode(s.charAt(0), this.nextIndex, Trie.NEW_NODE_X, Trie.NEW_NODE_Y)
+ tree.children[index].parent = tree;
+ this.cmd("Connect", tree.graphicID, tree.children[index].graphicID, Trie.FOREGROUND_COLOR, 0, false, s.charAt(0));
+
+ this.cmd("Step");
+ this.resizeTree();
+ this.cmd("SetText", 2, "" );
+ this.nextIndex += 1;
+ this.highlightID = this.nextIndex++;
+
+ }
+ this.cmd("CreateHighlightCircle", this.highlightID, Trie.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Trie.NODE_WIDTH);
+ this.cmd("SetText", 2, "Making recursive call to " + s.charAt(0) + " child, passing in \"" + s.substring(1) + "\"");
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+
+ this.cmd("Move", this.highlightID, tree.children[index].x, tree.children[index].y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+ this.addR(s.substring(1), tree.children[index])
+ }
+}
+Trie.prototype.setNewPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ var newX = xPosition - tree.width / 2;
+ var newY = yPosition + Trie.HEIGHT_DELTA;
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ this.setNewPositions(tree.children[i], newX + tree.children[i].width / 2, newY);
+ newX = newX + tree.children[i].width;
+ }
+ }
+ }
+
+}
+Trie.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ for (var i = 0; i < 26; i++)
+ {
+ this.animateNewPositions(tree.children[i])
+ }
+ }
+}
+
+Trie.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ var size = 0;
+ for (var i = 0; i < 26; i++)
+ {
+ tree.childWidths[i] = this.resizeWidths(tree.children[i]);
+ size += tree.childWidths[i]
+ }
+ tree.width = Math.max(size, Trie.NODE_WIDTH + 4)
+ return tree.width;
+}
+
+
+
+
+function TrieNode(val, id, initialX, initialY)
+{
+ this.wordRemainder = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+ this.children = new Array(26);
+ this.childWidths = new Array(26);
+ for (var i = 0; i < 26; i++)
+ {
+ this.children[i] = null;
+ this.childWidths[i] =0;
+ }
+ this.width = 0;
+ this.parent = null;
+}
+
+Trie.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+ this.printButton.disabled = true;
+}
+
+Trie.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+ this.printButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Trie(animManag, canvas.width, canvas.height);
+
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TrinarySearchTree.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TrinarySearchTree.js
new file mode 100644
index 0000000..1f0b102
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AlgorithmLibrary/TrinarySearchTree.js
@@ -0,0 +1,419 @@
+// Copyright 2016 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 LIIBTED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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
+
+
+// Constants.
+
+
+Ternary.NODE_WIDTH = 30;
+
+Ternary.LINK_COLOR = "#007700";
+Ternary.HIGHLIGHT_CIRCLE_COLOR = "#007700";
+Ternary.FOREGROUND_COLOR = "#007700";
+Ternary.BACKGROUND_COLOR = "#CCFFCC";
+Ternary.TRUE_COLOR = "#CCFFCC";
+Ternary.PRINT_COLOR = Ternary.FOREGROUND_COLOR;
+Ternary.FALSE_COLOR = "#FFFFFF"
+Ternary.WIDTH_DELTA = 50;
+Ternary.HEIGHT_DELTA = 50;
+Ternary.STARTING_Y = 80;
+Ternary.LeftMargin = 300;
+Ternary.NEW_NODE_Y = 100
+Ternary.NEW_NODE_X = 50;
+Ternary.FIRST_PRINT_POS_X = 50;
+Ternary.PRINT_VERTICAL_GAP = 20;
+Ternary.PRINT_HORIZONTAL_GAP = 50;
+
+
+
+function Ternary(am, w, h)
+{
+ this.init(am, w, h);
+}
+
+Ternary.prototype = new Algorithm();
+Ternary.prototype.constructor = Ternary;
+Ternary.superclass = Algorithm.prototype;
+
+Ternary.prototype.init = function(am, w, h)
+{
+ var sc = Ternary.superclass;
+ this.startingX = w / 2;
+ this.first_print_pos_y = h - 2 * Ternary.PRINT_VERTICAL_GAP;
+ this.print_max = w - 10;
+
+ var fn = sc.init;
+ fn.call(this,am);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.cmd("CreateLabel", 0, "", 20, 10, 0);
+ this.cmd("CreateLabel", 1, "", 20, 10, 0);
+ this.cmd("CreateLabel", 2, "", 20, 30, 0);
+ this.nextIndex = 3;
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+}
+
+
+Ternary.prototype.addControls = function()
+{
+ this.insertField = addControlToAlgorithmBar("Text", "");
+ this.insertField.onkeypress = this.returnSubmit(this.insertField, this.insertCallback.bind(this), 12,false);
+ this.insertButton = addControlToAlgorithmBar("Button", "添加");
+ this.insertButton.onclick = this.insertCallback.bind(this);
+// this.deleteField = addControlToAlgorithmBar("Text", "");
+// this.deleteField.onkeydown = this.returnSubmit(this.deleteField, this.deleteCallback.bind(this), 12);
+// this.deleteButton = addControlToAlgorithmBar("Button", "删除");
+// this.deleteButton.onclick = this.deleteCallback.bind(this);
+ this.findField = addControlToAlgorithmBar("Text", "");
+ this.findField.onkeydown = this.returnSubmit(this.findField, this.findCallback.bind(this), 12);
+ this.findButton = addControlToAlgorithmBar("Button", "搜索");
+ this.findButton.onclick = this.findCallback.bind(this);
+// this.printButton = addControlToAlgorithmBar("Button", "打印");
+// this.printButton.onclick = this.printCallback.bind(this);
+}
+
+Ternary.prototype.reset = function()
+{
+ this.nextIndex = 3;
+ this.treeRoot = null;
+}
+
+Ternary.prototype.insertCallback = function(event)
+{
+ var insertedValue = this.insertField.value.toUpperCase()
+ insertedValue = insertedValue.replace(/[^a-z]/gi,'');
+
+ if (insertedValue != "")
+ {
+ // set text value
+ this.insertField.value = "";
+ this.implementAction(this.add.bind(this), insertedValue);
+ }
+}
+
+
+Ternary.prototype.printCallback = function(event)
+{
+ this.implementAction(this.printTree.bind(this),"");
+}
+
+
+
+Ternary.prototype.findCallback = function(event)
+{
+ var findValue = this.findField.value.toUpperCase()
+ finndValue = findValue.replace(/[^a-z]/gi,'');
+ this.findField.value = "";
+ this.implementAction(this.findElement.bind(this),findValue);
+}
+
+Ternary.prototype.findElement = function(word)
+{
+ this.commands = [];
+
+ this.commands = new Array();
+ this.cmd("SetText", 0, "正在搜索: ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+
+
+ var node = this.doFind(this.root, word);
+ if (node != null)
+ {
+ this.cmd("SetText", 0, "Found \""+word+"\"");
+ }
+ else
+ {
+ this.cmd("SetText", 0, "\""+word+"\" not Found");
+ }
+
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+ return this.commands;
+}
+
+
+Ternary.prototype.doFind = function(tree, s)
+{
+
+ if (tree == null)
+ {
+ return null;
+ }
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ if (s.length == 0)
+ {
+ if (tree.isword == true)
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nCurrent node is True\nWord is in the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return tree
+ }
+ else
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nCurrent node is False\nWord is Not the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null
+
+ }
+ }
+ else
+ {
+ this.cmd("SetHighlightIndex", 1, 1);
+ var index = s.charCodeAt(0) - "A".charCodeAt(0);
+ if (tree.children[index] == null)
+ {
+ this.cmd("SetText", 2, "Child " + s.charAt(0) + " does not exist\nWord is Not the tree");
+ this.cmd("Step");
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ return null
+ }
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Making recursive call to " + s.charAt(0) + " child, passing in " + s.substring(1));
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+
+ this.cmd("Move", this.highlightID, tree.children[index].x, tree.children[index].y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+ return this.doFind(tree.children[index], s.substring(1))
+ }
+}
+
+Ternary.prototype.insertElement = function(insertedValue)
+{
+ this.cmd("SetText", 0, "");
+ return this.commands;
+}
+
+
+Ternary.prototype.insert = function(elem, tree)
+{
+
+}
+
+
+
+Ternary.prototype.resizeTree = function()
+{
+ this.resizeWidths(this.root);
+ if (this.root != null)
+ {
+ var startingPoint = this.root.width / 2 + 1 + Ternary.LeftMargin;
+ this.setNewPositions(this.root, startingPoint, Ternary.STARTING_Y);
+ this.animateNewPositions(this.root);
+ this.cmd("Step");
+ }
+
+}
+
+
+Ternary.prototype.add = function(word)
+{
+ this.commands = new Array();
+ this.cmd("SetText", 0, "Inserting; ");
+ this.cmd("SetText", 1, "\"" + word + "\"");
+ this.cmd("AlignRight", 1, 0);
+ this.cmd("Step");
+ if (this.root == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, "", Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, Ternary.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, Ternary.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Creating a new root");
+ this.root = new TernaryNode("", this.nextIndex, Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y)
+ this.cmd("Step");
+ this.resizeTree();
+ this.cmd("SetText", 2, "" );
+ this.highlightID = this.nextIndex++;
+ this.nextIndex += 1;
+
+ }
+ this.addR(word.toUpperCase(), this.root);
+ this.cmd("SetText", 0, "");
+ this.cmd("SetText", 1, "");
+ this.cmd("SetText", 2, "");
+
+ return this.commands;
+}
+
+
+Ternary.prototype.addR = function(s, tree)
+{
+ this.cmd("SetHighlight", tree.graphicID , 1);
+
+ if (s.length == 0)
+ {
+ this.cmd("SetText", 2, "Reached the end of the string \nSet current node to true");
+ this.cmd("Step");
+// this.cmd("SetText", tree.graphicID, "T");
+ this.cmd("SetBackgroundColor", tree.graphicID, Ternary.TRUE_COLOR);
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ tree.isword = true;
+ return;
+ }
+ else
+ {
+ this.cmd("SetHighlightIndex", 1, 1);
+ var index = s.charCodeAt(0) - "A".charCodeAt(0);
+ if (tree.children[index] == null)
+ {
+ this.cmd("CreateCircle", this.nextIndex, s.charAt(0), Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y);
+ this.cmd("SetForegroundColor", this.nextIndex, Ternary.FOREGROUND_COLOR);
+ this.cmd("SetBackgroundColor", this.nextIndex, Ternary.FALSE_COLOR);
+ this.cmd("SetWidth", this.nextIndex, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Child " + s.charAt(0) + " does not exist. Creating ... ");
+ tree.children[index] = new TernaryNode(s.charAt(0), this.nextIndex, Ternary.NEW_NODE_X, Ternary.NEW_NODE_Y)
+ tree.children[index].parent = tree;
+ this.cmd("Connect", tree.graphicID, tree.children[index].graphicID, Ternary.FOREGROUND_COLOR, 0, false, s.charAt(0));
+
+ this.cmd("Step");
+ this.resizeTree();
+ this.cmd("SetText", 2, "" );
+ this.nextIndex += 1;
+ this.highlightID = this.nextIndex++;
+
+ }
+ this.cmd("CreateHighlightCircle", this.highlightID, Ternary.HIGHLIGHT_CIRCLE_COLOR, tree.x, tree.y);
+ this.cmd("SetWidth", this.highlightID, Ternary.NODE_WIDTH);
+ this.cmd("SetText", 2, "Making recursive call to " + s.charAt(0) + " child, passing in \"" + s.substring(1) + "\"");
+ this.cmd("Step")
+ this.cmd("SetHighlight", tree.graphicID , 0);
+ this.cmd("SetHighlightIndex", 1, -1);
+ this.cmd("SetText", 1, "\"" + s.substring(1) + "\"");
+
+ this.cmd("Move", this.highlightID, tree.children[index].x, tree.children[index].y);
+ this.cmd("Step")
+ this.cmd("Delete", this.highlightID);
+ this.addR(s.substring(1), tree.children[index])
+ }
+}
+Ternary.prototype.setNewPositions = function(tree, xPosition, yPosition)
+{
+ if (tree != null)
+ {
+ tree.x = xPosition;
+ tree.y = yPosition;
+ var newX = xPosition - tree.width / 2;
+ var newY = yPosition + Ternary.HEIGHT_DELTA;
+ for (var i = 0; i < 26; i++)
+ {
+ if (tree.children[i] != null)
+ {
+ this.setNewPositions(tree.children[i], newX + tree.children[i].width / 2, newY);
+ newX = newX + tree.children[i].width;
+ }
+ }
+ }
+
+}
+Ternary.prototype.animateNewPositions = function(tree)
+{
+ if (tree != null)
+ {
+ this.cmd("Move", tree.graphicID, tree.x, tree.y);
+ for (var i = 0; i < 26; i++)
+ {
+ this.animateNewPositions(tree.children[i])
+ }
+ }
+}
+
+Ternary.prototype.resizeWidths = function(tree)
+{
+ if (tree == null)
+ {
+ return 0;
+ }
+ tree.leftWidth = (this.resizeWidths(tree.left));
+ tree.centerWidth = (this.resizeWidths(tree.center));
+ tree.rightWidth = (this.resizeWidths(tree.right));
+ tree.width = Math.max(size, Ternary.NODE_WIDTH + 4)
+ return tree.width;
+}
+
+
+
+
+function TernaryNode(val, id, initialX, initialY)
+{
+ this.wordRemainder = val;
+ this.x = initialX;
+ this.y = initialY;
+ this.graphicID = id;
+
+ this.left = null;
+ this.center = null;
+ this.right = null;
+ this.leftWidth = 0;
+ this.centerWidth = 0;
+ this.rightWwidth = 0;
+ this.parent = null;
+}
+
+Ternary.prototype.disableUI = function(event)
+{
+ this.insertField.disabled = true;
+ this.insertButton.disabled = true;
+ this.deleteField.disabled = true;
+ this.deleteButton.disabled = true;
+ this.findField.disabled = true;
+ this.findButton.disabled = true;
+// this.printButton.disabled = true;
+}
+
+Ternary.prototype.enableUI = function(event)
+{
+ this.insertField.disabled = false;
+ this.insertButton.disabled = false;
+ this.deleteField.disabled = false;
+ this.deleteButton.disabled = false;
+ this.findField.disabled = false;
+ this.findButton.disabled = false;
+// this.printButton.disabled = false;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new Ternary(animManag, canvas.width, canvas.height);
+
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Algorithms.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Algorithms.html
new file mode 100644
index 0000000..13f76b2
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Algorithms.html
@@ -0,0 +1,161 @@
+
+
+
+ Data Structure Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+Currently, we have visualizations for the following data structures
+and algorithms:
+
+
+
+ - Basics
+
+
+ - Recursion
+
+
+- Indexing
+
+
+
+- Sorting
+
+
+- Heap-like Data Structures
+
+
+- Graph Algorithms
+
+
+
+- Dynamic Programming
+
+
+
+- Geometric Algorithms
+
+
+
+
+
+
+- Others ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedBTreeNode.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedBTreeNode.js
new file mode 100644
index 0000000..0ea1a97
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedBTreeNode.js
@@ -0,0 +1,309 @@
+// 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 ``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 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
+
+
+function AnimatedBTreeNode(id, widthPerElem, h, numElems, fillColor, edgeColor)
+{
+ fillColor = (fillColor == undefined)? "#FFFFFF" : fillColor;
+ edgeColor = (edgeColor == undefined)? "#000000" : edgeColor;
+ this.init(id, widthPerElem, h, numElems, fillColor, edgeColor);
+}
+
+AnimatedBTreeNode.prototype = new AnimatedObject();
+AnimatedBTreeNode.prototype.constructor = AnimatedBTreeNode;
+AnimatedBTreeNode.superclass = AnimatedObject.prototype;
+
+AnimatedBTreeNode.MIN_WIDTH = 10;
+AnimatedBTreeNode.EDGE_POINTER_DISPLACEMENT = 5;
+
+
+AnimatedBTreeNode.prototype.init = function(id, widthPerElem, h, numElems, fillColor, edgeColor)
+{
+
+ var MIN_WIDTH = 10;
+ AnimatedBTreeNode.superclass.init.call(this);
+ this.objectID = id;
+
+
+ this.backgroundColor = fillColor;
+ this.foregroundColor = edgeColor;
+
+ this.widthPerElement = widthPerElem;
+ this.nodeHeight = h;
+ this.numLabels = numElems;
+ this.labels = new Array(this.numLabels);
+ this.labelColors = new Array(this.numLabels);
+ for (var i = 0; i < this.numLabels; i++)
+ {
+ this.labelColors[i] = this.foregroundColor;
+ }
+}
+
+AnimatedBTreeNode.prototype.getNumElements = function()
+{
+ return this.numLabels;
+}
+
+AnimatedBTreeNode.prototype.getWidth = function()
+{
+ if (this.numLabels > 0)
+ {
+ return (this.widthPerElement * this.numLabels);
+ }
+ else
+ {
+ return AnimatedBTreeNode.MIN_WIDTH;
+ }
+}
+
+
+AnimatedBTreeNode.prototype.setNumElements = function(newNumElements)
+{
+ var i;
+ if (this.numLabels < newNumElements)
+ {
+ for (i = this.numLabels; i < newNumElements; i++)
+ {
+ this.labels[i] = "";
+ this.labelColors[i] = this.foregroundColor;
+ }
+ this.numLabels = newNumElements;
+ }
+ else if (this.numLabels > newNumElements)
+ {
+ for (i = newNumElements; i < this.numLabels; i++)
+ {
+ this.labels[i] = null;
+ }
+ this.numLabels = newNumElements;
+ }
+}
+
+
+AnimatedBTreeNode.prototype.left = function()
+{
+ return this.x - this.getWidth() / 2.0;
+}
+
+AnimatedBTreeNode.prototype.right = function()
+{
+ return this.x + this.getWidth() / 2.0;
+}
+
+AnimatedBTreeNode.prototype.top = function()
+{
+ return this.y - this.nodeHeight / 2.0;
+}
+
+AnimatedBTreeNode.prototype.bottom = function()
+{
+ return this.y + this.nodeHeight / 2.0;
+}
+
+
+AnimatedBTreeNode.prototype.draw = function(context)
+{
+ var startX;
+ var startY;
+
+ startX = this.left();
+ if (startX == NaN)
+ {
+ startX = 0;
+ }
+ startY = this.top();
+
+ if (this.highlighted)
+ {
+ context.strokeStyle = "#ff0000";
+ context.fillStyle = "#ff0000";
+
+ context.beginPath();
+ context.moveTo(startX - this.highlightDiff,startY- this.highlightDiff);
+ context.lineTo(startX+this.getWidth() + this.highlightDiff,startY- this.highlightDiff);
+ context.lineTo(startX+this.getWidth() + this.highlightDiff,startY+this.nodeHeight + this.highlightDiff);
+ context.lineTo(startX - this.highlightDiff,startY+this.nodeHeight + this.highlightDiff);
+ context.lineTo(startX - this.highlightDiff,startY - this.highlightDiff);
+ context.closePath();
+ context.stroke();
+ context.fill();
+ }
+
+ context.strokeStyle = this.foregroundColor;
+ context.fillStyle = this.backgroundColor;
+
+ context.beginPath();
+ context.moveTo(startX ,startY);
+ context.lineTo(startX + this.getWidth(), startY);
+ context.lineTo(startX + this.getWidth(), startY + this.nodeHeight);
+ context.lineTo(startX, startY + this.nodeHeight);
+ context.lineTo(startX, startY);
+ context.closePath();
+ context.stroke();
+ context.fill();
+
+ context.textAlign = 'center';
+ context.textBaseline = 'middle';
+
+
+ for (var i = 0; i < this.numLabels; i++)
+ {
+ var labelx = this.x - this.widthPerElement * this.numLabels / 2 + this.widthPerElement / 2 + i * this.widthPerElement;
+ var labely = this.y
+
+ context.fillStyle = this.labelColors[i];
+ context.fillText(this.labels[i], labelx, labely);
+ }
+}
+
+
+
+AnimatedBTreeNode.prototype.getHeight = function()
+{
+ return this.nodeHeight;
+}
+
+
+
+AnimatedBTreeNode.prototype.setForegroundColor = function(newColor)
+{
+ this.foregroundColor = newColor;
+ for (var i = 0; i < numLabels; i++)
+ {
+ labelColor[i] = newColor;
+ }
+}
+
+
+// TODO: Kill the magic numbers here
+AnimatedBTreeNode.prototype.getTailPointerAttachPos = function(fromX, fromY, anchor)
+{
+ if (anchor == 0)
+ {
+ return [this.left() + AnimatedBTreeNode.EDGE_POINTER_DISPLACEMENT, this.y + this.nodeHeight * 0.5];
+ }
+ else if (anchor == this.numLabels)
+ {
+ return [this.right() - AnimatedBTreeNode.EDGE_POINTER_DISPLACEMENT, this.y + this.nodeHeight * 0.5];
+ }
+ else
+ {
+ return [this.left() + anchor * this.widthPerElement, this.y + this.nodeHeight * 0.5]
+ }
+}
+
+
+AnimatedBTreeNode.prototype.getHeadPointerAttachPos = function(fromX, fromY)
+{
+ if (fromY < this.y - this.nodeHeight / 2)
+ {
+ return [this.x, this.y - this.nodeHeight / 2];
+ }
+ else if (this.fromY > this.y + this.nodeHeight / 2)
+ {
+ return [this.x, this.y + this.nodeHeight / 2];
+ }
+ else if (fromX < this.x - this.getWidth() / 2)
+ {
+ return [this.x - this.getWidth() / 2, this.y];
+ }
+ else
+ {
+ return [this.x + this.getWidth() / 2, this.y];
+ }
+}
+
+
+
+AnimatedBTreeNode.prototype.createUndoDelete = function()
+{
+ return new UndoDeleteBTreeNode(this.objectID, this.numLabels, this.labels, this.x, this.y, this.widthPerElement, this.nodeHeight, this.labelColors, this.backgroundColor, this.foregroundColor, this.layer, this.highlighted);
+}
+
+
+AnimatedBTreeNode.prototype.getTextColor = function(textIndex)
+{
+ textIndex = (textIndex == undefined) ? 0 : textIndex;
+ return this.labelColors[textIndex];
+}
+
+AnimatedBTreeNode.prototype.getText = function(index)
+{
+ index = (index == undefined) ? 0 : index;
+ return this.labels[index];
+}
+
+AnimatedBTreeNode.prototype.setTextColor = function(color, textIndex)
+{
+ textIndex = (textIndex == undefined) ? 0 : textIndex;
+ this.labelColors[textIndex] = color;
+}
+
+
+AnimatedBTreeNode.prototype.setText = function(newText, textIndex)
+{
+ textIndex = (textIndex == undefined) ? 0 : textIndex;
+ this.labels[textIndex] = newText;
+}
+
+
+
+function UndoDeleteBTreeNode(id, numLab, labelText, x, y, wPerElement, nHeight, lColors, bgColor, fgColor, l, highlighted)
+{
+ this.objectID = id;
+ this.posX = x;
+ this.posY = y;
+ this.widthPerElem = wPerElement;
+ this.nodeHeight = nHeight;
+ this.backgroundColor= bgColor;
+ this.foregroundColor = fgColor;
+ this.numElems = numLab;
+ this.labels = labelText;
+
+ this.labelColors = lColors;
+ this.layer = l;
+ this.highlighted = highlighted;
+}
+
+UndoDeleteBTreeNode.prototype = new UndoBlock();
+UndoDeleteBTreeNode.prototype.constructor = UndoDeleteBTreeNode;
+
+UndoDeleteBTreeNode.prototype.undoInitialStep = function(world)
+{
+
+ world.addBTreeNode(this.objectID, this.widthPerElem, this.nodeHeight, this.numElems, this.backgroundColor, this.foregroundColor);
+ world.setNodePosition(this.objectID, this.posX, this.posY);
+ for (var i = 0; i < this.numElems; i++)
+ {
+ world.setText(this.objectID, this.labels[i], i);
+ world.setTextColor(this.objectID, this.labelColors[i],i);
+ }
+ world.setHighlight(this.objectID, this.highlighted);
+ world.setLayer(this.objectID, this.layer);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedCircle.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedCircle.js
new file mode 100644
index 0000000..e6b9a8c
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedCircle.js
@@ -0,0 +1,210 @@
+// 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 ``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 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 AnimatedCircle = function(objectID, objectLabel)
+{
+ this.objectID = objectID;
+ this.label = objectLabel;
+ this.radius = 20;
+ this.thickness = 3;
+ this.x = 0;
+ this.y = 0;
+ this.alpha = 1.0;
+ this.addedToScene = true;
+ this.highlightIndex = -1;
+/* this.foregroundColor = '#007700';
+ this.backgroundColor = '#EEFFEE';
+ */
+}
+
+AnimatedCircle.prototype = new AnimatedObject();
+AnimatedCircle.prototype.constructor = AnimatedCircle;
+
+AnimatedCircle.prototype.getTailPointerAttachPos = function(fromX, fromY, anchorPoint)
+{
+ return this.getHeadPointerAttachPos(fromX, fromY);
+}
+
+
+AnimatedCircle.prototype.getWidth = function()
+{
+ return this.radius * 2;
+}
+
+AnimatedObject.prototype.setWidth = function(newWidth)
+{
+ this.radius = newWidth / 2;
+}
+
+
+
+
+
+AnimatedCircle.prototype.getHeadPointerAttachPos = function(fromX, fromY)
+{
+ var xVec = fromX - this.x;
+ var yVec = fromY - this.y;
+ var len = Math.sqrt(xVec * xVec + yVec*yVec);
+ if (len == 0)
+ {
+ return [this.x, this.y];
+ }
+ return [this.x+(xVec/len)*(this.radius), this.y +(yVec/len)*(this.radius)];
+}
+
+
+AnimatedCircle.prototype.setHighlightIndex = function(hlIndex)
+{
+ this.highlightIndex = hlIndex;
+ this.highlightIndexDirty = true;
+
+}
+
+AnimatedCircle.prototype.draw = function(ctx)
+{
+ ctx.globalAlpha = this.alpha;
+
+ if (this.highlighted)
+ {
+ ctx.fillStyle = "#ff0000";
+ ctx.beginPath();
+ ctx.arc(this.x,this.y,this.radius + this.highlightDiff,0,Math.PI*2, true);
+ ctx.closePath();
+ ctx.fill();
+ }
+
+
+ ctx.fillStyle = this.backgroundColor;
+ ctx.strokeStyle = this.foregroundColor;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.arc(this.x,this.y,this.radius,0,Math.PI*2, true);
+ ctx.closePath();
+ ctx.fill();
+ ctx.stroke();
+ ctx.textAlign = 'center';
+ ctx.font = '16px Consolas';
+ ctx.textBaseline = 'middle';
+ ctx.lineWidth = 1;
+ ctx.fillStyle = this.foregroundColor;
+
+ var strList = this.label.split("\n");
+ if (strList.length == 1)
+ {
+ if (this.highlightIndexDirty && this.highlightIndex != -1)
+ {
+ this.leftWidth = ctx.measureText(this.label.substring(0,this.highlightIndex)).width;
+ this.centerWidth = ctx.measureText(this.label.substring(this.highlightIndex, this.highlightIndex+1)).width;
+ this.textWidth = ctx.measureText(this.label).width;
+ this.highlightIndexDirty = false;
+ }
+ if (this.highlightIndex != -1 && this.highlightIndex < this.label.length) //this.highlghtIndex < this.label.length)
+ {
+ var startingXForHighlight = this.x - this.textWidth / 2;
+ ctx.textAlign = 'left';
+ var leftStr = this.label.substring(0, this.highlightIndex);
+ var highlightStr = this.label.substring(this.highlightIndex, this.highlightIndex + 1)
+ var rightStr = this.label.substring(this.highlightIndex + 1)
+ ctx.fillText(leftStr, startingXForHighlight, this.y)
+ ctx.strokeStyle = "#FF0000";
+ ctx.fillStyle = "#FF0000";
+ ctx.fillText(highlightStr, startingXForHighlight + this.leftWidth, this.y)
+
+
+ ctx.strokeStyle = this.labelColor;
+ ctx.fillStyle = this.labelColor;
+ ctx.fillText(rightStr, startingXForHighlight + this.leftWidth + this.centerWidth, this.y)
+
+
+
+ }
+ else
+ {
+ ctx.fillText(this.label, this.x, this.y);
+ }
+ }
+ else if (strList.length % 2 == 0)
+ {
+ var i;
+ var mid = strList.length / 2;
+ for (i = 0; i < strList.length / 2; i++)
+ {
+ ctx.fillText(strList[mid - i - 1], this.x, this.y - (i + 0.5) * 12);
+ ctx.fillText(strList[mid + i], this.x, this.y + (i + 0.5) * 12);
+
+ }
+ }
+ else
+ {
+ var mid = (strList.length - 1) / 2;
+ var i;
+ ctx.fillText(strList[mid], this.x, this.y);
+ for (i = 0; i < mid; i++)
+ {
+ ctx.fillText(strList[mid - (i + 1)], this.x, this.y - (i + 1) * 12);
+ ctx.fillText(strList[mid + (i + 1)], this.x, this.y + (i + 1) * 12);
+ }
+
+ }
+
+}
+
+
+AnimatedCircle.prototype.createUndoDelete = function()
+{
+ return new UndoDeleteCircle(this.objectID, this.label, this.x, this.y, this.foregroundColor, this.backgroundColor, this.layer, this.radius);
+}
+
+
+function UndoDeleteCircle(id, lab, x, y, foregroundColor, backgroundColor, l, radius)
+{
+ this.objectID = id;
+ this.posX = x;
+ this.posY = y;
+ this.nodeLabel = lab;
+ this.fgColor = foregroundColor;
+ this.bgColor = backgroundColor;
+ this.layer = l;
+ this.radius = radius;
+}
+
+UndoDeleteCircle.prototype = new UndoBlock();
+UndoDeleteCircle.prototype.constructor = UndoDeleteCircle;
+
+UndoDeleteCircle.prototype.undoInitialStep = function(world)
+{
+ world.addCircleObject(this.objectID, this.nodeLabel);
+ world.setWidth(this.objectID, this.radius * 2);
+ world.setNodePosition(this.objectID, this.posX, this.posY);
+ world.setForegroundColor(this.objectID, this.fgColor);
+ world.setBackgroundColor(this.objectID, this.bgColor);
+ world.setLayer(this.objectID, this.layer);
+}
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedLabel.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedLabel.js
new file mode 100644
index 0000000..5e50304
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedLabel.js
@@ -0,0 +1,420 @@
+// 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 ``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 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
+
+function AnimatedLabel(id, val, center, initialWidth)
+{
+ this.centering = center;
+ this.label = val;
+ this.highlighted = false;
+ this.objectID = id;
+ this.alpha = 1.0;
+ this.addedToScene = true;
+ this.labelColor = "#000000";
+ this.textWidth = 0;
+ if (initialWidth != undefined)
+ {
+ this.textWidth = initialWidth;
+ }
+
+ this.leftWidth = -1;
+ this.centerWidth = -1;
+ this.highlightIndex = -1;
+}
+
+AnimatedLabel.prototype = new AnimatedObject();
+AnimatedLabel.prototype.constructor = AnimatedLabel;
+
+AnimatedLabel.prototype.alwaysOnTop = true;
+
+
+AnimatedLabel.prototype.centered = function()
+{
+ return this.centering;
+}
+
+
+AnimatedLabel.prototype.draw = function(ctx)
+{
+ if (!this.addedToScene)
+ {
+ return;
+ }
+
+ ctx.globalAlpha = this.alpha;
+ ctx.font = '16px Consolas';
+
+ var startingXForHighlight = this.x;
+
+ if (this.highlightIndex >= this.label.length)
+ {
+ this.highlightIndex = -1;
+ }
+ if (this.highlightIndexDirty && this.highlightIndex != -1)
+ {
+ this.leftWidth = ctx.measureText(this.label.substring(0,this.highlightIndex)).width;
+ this.centerWidth = ctx.measureText(this.label.substring(this.highlightIndex, this.highlightIndex+1)).width;
+ this.highlightIndexDirty = false;
+ }
+
+ if (this.centering)
+ {
+ if (this.highlightIndex != -1)
+ {
+ startingXForHighlight = this.x - this.width / 2;
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'middle';
+ }
+ else
+ {
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ }
+ }
+ else
+ {
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ }
+ if (this.highlighted)
+ {
+ ctx.strokeStyle = "#ffaaaa";
+ ctx.fillStyle = "#ff0000";
+ ctx.lineWidth = this.highlightDiff;
+ ctx.strokeText(this.label, this.x, this.y);
+ //ctx.fillText(this.label, this.x, this.y);
+ }
+ ctx.strokeStyle = this.labelColor;
+ ctx.fillStyle = this.labelColor;
+ ctx.lineWidth = 1;
+ strList = this.label.split("\n");
+ if (strList.length == 1)
+ {
+ if (this.highlightIndex == -1)
+ {
+ ctx.fillText(this.label, this.x, this.y);
+ }
+ else
+ {
+ var leftStr = this.label.substring(0, this.highlightIndex);
+ var highlightStr = this.label.substring(this.highlightIndex, this.highlightIndex + 1)
+ var rightStr = this.label.substring(this.highlightIndex + 1)
+ ctx.fillText(leftStr, startingXForHighlight, this.y)
+ ctx.strokeStyle = "#FF0000";
+ ctx.fillStyle = "#FF0000";
+ ctx.fillText(highlightStr, startingXForHighlight + this.leftWidth, this.y)
+
+
+ ctx.strokeStyle = this.labelColor;
+ ctx.fillStyle = this.labelColor;
+ ctx.fillText(rightStr, startingXForHighlight + this.leftWidth + this.centerWidth, this.y)
+
+
+ }
+ //this.textWidth = ctx.measureText(this.label).width;
+ }
+ else
+ {
+ var offset = (this.centering)? (1.0 - strList.length) / 2.0 : 0;
+ for (var i = 0; i < strList.length; i++)
+ {
+ ctx.fillText(strList[i], this.x, this.y + offset + i * 12);
+ //this.textWidth = Math.max(this.textWidth, ctx.measureText(strList[i]).width);
+ }
+ }
+ ctx.closePath();
+}
+
+
+AnimatedLabel.prototype.getAlignLeftPos = function(otherObject)
+{
+ if (this.centering)
+ {
+ return [otherObject.left() - this.textWidth / 2, this.y = otherObject.centerY()];
+ }
+ else
+ {
+ return [otherObject.left() - this.textWidth, otherObject.centerY() - 5];
+ }
+}
+
+AnimatedLabel.prototype.alignLeft = function(otherObject)
+{
+ if (this.centering)
+ {
+ this.y = otherObject.centerY();
+ this.x = otherObject.left() - this.textWidth / 2;
+ }
+ else
+ {
+ this.y = otherObject.centerY() - 5;
+ this.x = otherObject.left() - this.textWidth;
+ }
+}
+
+AnimatedLabel.prototype.alignRight = function(otherObject)
+{
+ if (this.centering)
+ {
+ this.y = otherObject.centerY();
+ this.x = otherObject.right() + this.textWidth / 2;
+ }
+ else
+ {
+ this.y = otherObject.centerY() - 5;
+ this.x = otherObject.right();
+ }
+}
+AnimatedLabel.prototype.getAlignRightPos = function(otherObject)
+{
+ if (this.centering)
+ {
+ return [otherObject.right() + this.textWidth / 2, otherObject.centerY()];
+ }
+ else
+ {
+ return [otherObject.right(), otherObject.centerY() - 5];
+ }
+}
+
+
+AnimatedLabel.prototype.alignTop = function(otherObject)
+{
+ if (this.centering)
+ {
+ this.y = otherObject.top() - 5;
+ this.x = otherObject.centerX();
+ }
+ else
+ {
+ this.y = otherObject.top() - 10;
+ this.x = otherObject.centerX() -this.textWidth / 2;
+ }
+}
+
+
+AnimatedLabel.prototype.getAlignTopPos = function(otherObject)
+{
+ if (this.centering)
+ {
+ return [otherObject.centerX(), otherObject.top() - 5];
+ }
+ else
+ {
+ return [otherObject.centerX() -this.textWidth / 2, otherObject.top() - 10];
+ }
+}
+
+
+AnimatedLabel.prototype.alignBottom = function(otherObject)
+{
+ if (this.centering)
+ {
+ this.y = otherObject.bottom() + 5;
+ this.x = otherObject.centerX();
+ }
+ else
+ {
+ this.y = otherObject.bottom();
+ this.x = otherObject.centerX() - this.textWidth / 2;
+ }
+}
+
+
+AnimatedLabel.prototype.getAlignBottomPos = function(otherObject)
+{
+ if (this.centering)
+ {
+ return [otherObject.centerX(), otherObject.bottom() + 5];
+ }
+ else
+ {
+ return [otherObject.centerX() - this.textWidth / 2, otherObject.bottom()];
+ }
+}
+
+
+
+AnimatedLabel.prototype.getWidth = function()
+{
+ return this.textWidth;
+}
+
+AnimatedLabel.prototype.getHeight = function()
+{
+ return 10; // HACK! HACK! HACK! HACK!
+}
+
+
+AnimatedLabel.prototype.setHighlight = function(value)
+{
+ this.highlighted = value;
+}
+
+AnimatedLabel.prototype.createUndoDelete = function()
+{
+ return new UndoDeleteLabel(this.objectID, this.label, this.x, this.y, this.centering, this.labelColor, this.layer, this.highlightIndex);
+}
+
+
+AnimatedLabel.prototype.centerX = function()
+{
+ if (this.centering)
+ {
+ return this.x;
+ }
+ else
+ {
+ return this.x + this.textWidth;
+ }
+
+}
+
+AnimatedLabel.prototype.centerY = function()
+{
+ if (this.centering)
+ {
+ return this.y;
+ }
+ else
+ {
+ return this.y + 5; //
+ }
+
+}
+
+AnimatedLabel.prototype.top = function()
+{
+ if (this.centering)
+ {
+ return this.y - 5; //TODO: Un-Hardwire
+ }
+ else
+ {
+ return this.y;
+ }
+}
+
+
+AnimatedLabel.prototype.bottom = function()
+{
+ if (this.centering)
+ {
+ return this.y + 5; // TODO: + height / 2;
+ }
+ else
+ {
+ return this.y + 10; // TODO: + hieght;
+ }
+}
+
+
+AnimatedLabel.prototype.right = function()
+{
+ if (this.centering)
+ {
+ return this.x + this.textWidth / 2; // TODO: + width / 2;
+ }
+ else
+ {
+ return this.x + this.textWidth; // TODO: + width;
+ }
+}
+
+
+AnimatedLabel.prototype.left = function()
+{
+ if (this.centering)
+ {
+ return this. x - this.textWidth / 2;
+ }
+ else
+ {
+ return this.x; // TODO: - a little?
+ }
+}
+
+
+AnimatedLabel.prototype.setHighlightIndex = function(hlIndex)
+{
+ // Only allow highlight index for labels that don't have End-Of-Line
+ if (this.label.indexOf("\n") == -1 && this.label.length > hlIndex)
+ {
+ this.highlightIndex = hlIndex;
+ this.highlightIndexDirty = true;
+ }
+ else
+ {
+ this.highlightIndex = -1;
+
+ }
+}
+
+
+ AnimatedLabel.prototype.getTailPointerAttachPos = function(fromX, fromY, anchorPoint)
+ {
+ return this.getClosestCardinalPoint(fromX, fromY);
+ }
+
+AnimatedLabel.prototype.getHeadPointerAttachPos = function (fromX, fromY)
+{
+ return this.getClosestCardinalPoint(fromX, fromY);
+}
+
+AnimatedLabel.prototype.setText = function(newText, textIndex, initialWidth)
+{
+ this.label = newText;
+ if (initialWidth != undefined)
+ {
+ this.textWidth = initialWidth;
+ }
+}
+
+
+
+function UndoDeleteLabel(id, lab, x, y, centered, color, l, hli)
+{
+ this.objectID = id;
+ this.posX = x;
+ this.posY = y;
+ this.nodeLabel = lab;
+ this.labCentered = centered;
+ this.labelColor = color;
+ this.layer = l;
+ this.highlightIndex = hli;
+ this.dirty = true;
+}
+
+UndoDeleteLabel.prototype = new UndoBlock();
+UndoDeleteLabel.prototype.constructor = UndoDeleteLabel;
+
+UndoDeleteLabel.prototype.undoInitialStep = function(world)
+{
+ world.addLabelObject(this.objectID, this.nodeLabel, this.labCentered);
+ world.setNodePosition(this.objectID, this.posX, this.posY);
+ world.setForegroundColor(this.objectID, this.labelColor);
+ world.setLayer(this.objectID, this.layer);
+}
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedLinkedList.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedLinkedList.js
new file mode 100644
index 0000000..3a12508
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedLinkedList.js
@@ -0,0 +1,473 @@
+// 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 ``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 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
+
+function AnimatedLinkedList(id, val, wth, hgt, linkPer, verticalOrientation, linkPosEnd, numLab, fillColor, edgeColor)
+{
+ this.init(id, val, wth, hgt, linkPer, verticalOrientation, linkPosEnd, numLab, fillColor, edgeColor);
+}
+
+AnimatedLinkedList.prototype = new AnimatedObject();
+AnimatedLinkedList.prototype.constructor = AnimatedLinkedList;
+AnimatedLinkedList.superclass = AnimatedObject.prototype;
+
+
+AnimatedLinkedList.prototype.init = function(id, val, wth, hgt, linkPer, verticalOrientation, linkPosEnd, numLab, fillColor, edgeColor)
+{
+
+ AnimatedLinkedList.superclass.init.call(this);
+
+ this.w = wth;
+ this.h = hgt;
+ this.backgroundColor = fillColor;
+ this.foregroundColor = edgeColor;
+
+ this.vertical = verticalOrientation;
+ this.linkPositionEnd = linkPosEnd;
+ this.linkPercent = linkPer;
+
+ this.numLabels = numLab;
+
+ this.labels = [];
+ this.labelPosX = [];
+ this.labelPosY = [];
+ this.labelColors = [];
+ this.nullPointer = false;
+
+ this.currentHeightDif = 6;
+ this.maxHeightDiff = 5;
+ this.minHeightDiff = 3;
+
+
+
+ for (var i = 0; i < this.numLabels; i++)
+ {
+ this.labels[i] = "";
+ this.labelPosX[i] = 0;
+ this.labelPosY[i] = 0;
+ this.labelColors[i] = this.foregroundColor;
+ }
+
+ this.labels[0] = val;
+ this.highlighted = false;
+ this.objectID = id;
+}
+
+
+
+AnimatedLinkedList.prototype.left = function()
+{
+ if (this.vertical)
+ {
+ return this.x - this.w / 2.0;
+ }
+ else if (this.linkPositionEnd)
+ {
+ return this.x - ((this.w * (1 - this.linkPercent)) / 2);
+ }
+ else
+ {
+ return this.x - (this.w * (this.linkPercent + 1)) / 2;
+ }
+}
+
+
+AnimatedLinkedList.prototype.setNull = function(np)
+{
+ if (this.nullPointer != np)
+ {
+ this.nullPointer = np;
+ }
+
+}
+
+AnimatedLinkedList.prototype.getNull = function()
+{
+ return this.nullPointer;
+}
+
+AnimatedLinkedList.prototype.right = function()
+{
+ if (this.vertical)
+ {
+ return this.x + this.w / 2.0;
+ }
+ else if (this.linkPositionEnd)
+ {
+ return this.x + ((this.w * (this.linkPercent + 1)) / 2);
+ }
+ else
+ {
+ return this.x + (this.w * (1 - this.linkPercent)) / 2;
+ }
+}
+
+AnimatedLinkedList.prototype.top = function()
+{
+ if (!this.vertical)
+ {
+ return this.y - this.h / 2.0;
+ }
+ else if (this.linkPositionEnd)
+ {
+ return this.y - (this.h * (1 -this.linkPercent)) / 2;
+ }
+ else
+ {
+ return this.y - (this.h * (1 + this.linkPercent)) / 2;
+ }
+}
+
+AnimatedLinkedList.prototype.bottom = function()
+{
+ if (!this.vertical)
+ {
+ return this.y + this.h / 2.0;
+ }
+ else if (this.linkPositionEnd)
+ {
+ return this.y + (this.h * (1 +this.linkPercent)) / 2;
+ }
+ else
+ {
+ return this.y + (this.h * (1 - this.linkPercent)) / 2;
+ }
+}
+
+
+// TODO: Should we move this to the draw function, and save the
+// space of the arrays? Bit of a leftover from the Flash code,
+// which did drawing differently
+AnimatedLinkedList.prototype.resetTextPosition = function()
+{
+ if (this.vertical)
+ {
+ this.labelPosX[0] = this.x;
+
+ this.labelPosY[0] = this.y + this.h * (1-this.linkPercent)/2 *(1/this.numLabels - 1);
+ // labelPosY[0] = -height * (1-linkPercent) / 2 + height*(1-linkPercent)/2*numLabels;
+ for (var i = 1; i < this.numLabels; i++)
+ {
+ this.labelPosY[i] = this.labelPosY[i-1] + this.h*(1-this.linkPercent)/this.numLabels;
+ this.labelPosX[i] = this.x;
+ }
+ }
+ else
+ {
+ this.labelPosY[0] = this.y;
+ this.labelPosX[0] = this.x + this.w * (1-this.linkPercent)/2*(1/this.numLabels - 1);
+ for (var i = 1; i < this.numLabels; i++)
+ {
+ this.labelPosY[i] = this.y;
+ this.labelPosX[i] = this.labelPosX[i-1] + this.w*(1-this.linkPercent)/this.numLabels;
+ }
+ }
+
+}
+
+
+AnimatedLinkedList.prototype.getTailPointerAttachPos = function(fromX, fromY, anchor)
+{
+ if (this.vertical && this.linkPositionEnd)
+ {
+ return [this.x, this.y + this.h / 2.0];
+ }
+ else if (this.vertical && !this.linkPositionEnd)
+ {
+ return [this.x, this.y - this.h / 2.0];
+ }
+ else if (!this.vertical && this.linkPositionEnd)
+ {
+ return [this.x + this.w / 2.0, this.y];
+ }
+ else // (!this.vertical && !this.linkPositionEnd)
+ {
+ return [this.x - this.w / 2.0, this.y];
+ }
+}
+
+
+AnimatedLinkedList.prototype.getHeadPointerAttachPos = function(fromX, fromY)
+{
+ return this.getClosestCardinalPoint(fromX, fromY);
+}
+
+
+AnimatedLinkedList.prototype.setWidth = function(wdth)
+{
+ this.w = wdth;
+ this.resetTextPosition();
+}
+
+
+AnimatedLinkedList.prototype.setHeight = function(hght)
+{
+ this.h = hght;
+ this.resetTextPosition();
+}
+
+AnimatedLinkedList.prototype.getWidth = function()
+{
+ return this.w;
+}
+
+AnimatedLinkedList.prototype.getHeight = function()
+{
+ return this.h;
+}
+
+AnimatedLinkedList.prototype.draw = function(context)
+{
+ var startX;
+ var startY;
+
+ startX = this.left();
+ startY = this.top();
+
+ if (this.highlighted)
+ {
+ context.strokeStyle = "#ff0000";
+ context.fillStyle = "#ff0000";
+
+ context.beginPath();
+ context.moveTo(startX - this.highlightDiff,startY- this.highlightDiff);
+ context.lineTo(startX+this.w + this.highlightDiff,startY- this.highlightDiff);
+ context.lineTo(startX+this.w+ this.highlightDiff,startY+this.h + this.highlightDiff);
+ context.lineTo(startX - this.highlightDiff,startY+this.h + this.highlightDiff);
+ context.lineTo(startX - this.highlightDiff,startY - this.highlightDiff);
+ context.closePath();
+ context.stroke();
+ context.fill();
+ }
+ context.strokeStyle = this.foregroundColor;
+ context.fillStyle = this.backgroundColor;
+
+ context.beginPath();
+ context.moveTo(startX ,startY);
+ context.lineTo(startX + this.w, startY);
+ context.lineTo(startX + this.w, startY + this.h);
+ context.lineTo(startX, startY + this.h);
+ context.lineTo(startX, startY);
+ context.closePath();
+ context.stroke();
+ context.fill();
+
+ var i;
+ if (this.vertical)
+ {
+ startX = this.left();
+ for (i= 1; i < this.numLabels; i++)
+ {
+ //TODO: this doesn't look right ...
+ startY = this.y + this.h*(1-this.linkPercent)*(i / this.numLabels - 1/2);
+
+ context.beginPath();
+ context.moveTo(startX ,startY);
+ context.lineTo(startX + this.w, startY);
+ context.closePath();
+ context.stroke();
+ }
+ }
+ else
+ {
+ startY = this.top();
+ for (i = 1; i < this.numLabels; i++)
+ {
+ startX = this.x + this.w*(1-this.linkPercent)*(i / this.numLabels - 1/2);
+ context.beginPath();
+ context.moveTo(startX ,startY);
+ context.lineTo(startX, startY + this.h);
+ context.closePath();
+ context.stroke();
+ }
+ }
+
+ if (this.vertical && this.linkPositionEnd)
+ {
+ startX = this.left();
+ startY = this.bottom() - this.h * this.linkPercent;
+
+
+ context.beginPath();
+ context.moveTo(startX + this.w ,startY);
+ context.lineTo(startX, startY);
+ if (this.nullPointer)
+ {
+ context.lineTo(this.startX + this.w, this.bottom());
+ }
+ context.closePath();
+ context.stroke();
+ }
+ else if (this.vertical && !this.linkPositionEnd)
+ {
+ startX = this.left();
+ startY = this.top() + this.h * this.linkPercent;
+
+ context.beginPath();
+ context.moveTo(startX + this.w ,startY);
+ context.lineTo(startX, startY);
+ if (this.nullPointer)
+ {
+ context.lineTo(startX + this.w, this.top());
+ }
+ context.closePath();
+ context.stroke();
+
+ }
+ else if (!this.vertical && this.linkPositionEnd)
+ {
+ startX = this.right() - this.w * this.linkPercent;
+ startY = this.top();
+
+ context.beginPath();
+ context.moveTo(startX, startY + this.h);
+ context.lineTo(startX, startY);
+ if (this.nullPointer)
+ {
+ context.lineTo(this.right(), startY + this.h);
+ }
+ context.closePath();
+ context.stroke();
+
+ }
+ else // (!vertical && !linkPositionEnd)
+ {
+ startX = this.left() + this.w * this.linkPercent;
+ startY = this.top() ;
+
+ context.beginPath();
+ context.moveTo(startX, startY + this.h);
+ context.lineTo(startX, startY);
+ if (this.nullPointer)
+ {
+ context.lineTo(this.left(), startY);
+ }
+ context.closePath();
+ context.stroke();
+ }
+
+
+ context.textAlign = 'center';
+ context.font = '16px Consolas';
+ context.textBaseline = 'middle';
+ context.lineWidth = 1;
+
+
+ this.resetTextPosition();
+ for (i = 0; i < this.numLabels; i++)
+ {
+ context.fillStyle = this.labelColors[i];
+ context.fillText(this.labels[i], this.labelPosX[i], this.labelPosY[i]);
+ }
+}
+
+
+
+AnimatedLinkedList.prototype.setTextColor = function(color, textIndex)
+{
+
+ this.labelColors[textIndex] = color;
+}
+
+
+
+AnimatedLinkedList.prototype.getTextColor = function(textIndex)
+{
+ return this.labelColors[textIndex];
+}
+
+
+
+AnimatedLinkedList.prototype.getText = function(index)
+{
+ return this.labels[index];
+}
+
+AnimatedLinkedList.prototype.setText = function(newText, textIndex)
+{
+ this.labels[textIndex] = newText;
+ this.resetTextPosition();
+}
+
+
+
+
+
+
+
+AnimatedLinkedList.prototype.createUndoDelete = function()
+{
+ return new UndoDeleteLinkedList(this.objectID, this.numLabels, this.labels, this.x, this.y, this.w, this.h, this.linkPercent,
+ this.linkPositionEnd, this.vertical, this.labelColors, this.backgroundColor, this.foregroundColor,
+ this.layer, this.nullPointer);
+}
+
+AnimatedLinkedList.prototype.setHighlight = function(value)
+{
+ if (value != this.highlighted)
+ {
+ this.highlighted = value;
+ }
+}
+
+
+
+
+function UndoDeleteLinkedList(id, numlab, lab, x, y, w, h, linkper, posEnd, vert, labColors, bgColor, fgColor, l, np)
+{
+ this.objectID = id;
+ this.posX = x;
+ this.posY = y;
+ this.width = w;
+ this.height = h;
+ this.backgroundColor= bgColor;
+ this.foregroundColor = fgColor;
+ this.labels = lab;
+ this.linkPercent = linkper;
+ this.verticalOrentation = vert;
+ this.linkAtEnd = posEnd;
+ this.labelColors = labColors
+ this.layer = l;
+ this.numLabels = numlab;
+ this.nullPointer = np;
+}
+
+UndoDeleteLinkedList.prototype = new UndoBlock();
+UndoDeleteLinkedList.prototype.constructor = UndoDeleteLinkedList;
+
+
+
+UndoDeleteLinkedList.prototype.undoInitialStep =function(world)
+{
+ world.addLinkedListObject(this.objectID,this.labels[0], this.width, this.height, this.linkPercent, this.verticalOrentation, this.linkAtEnd, this.numLabels, this.backgroundColor, this.foregroundColor);
+ world.setNodePosition(this.objectID, this.posX, this.posY);
+ world.setLayer(this.objectID, this.layer);
+ world.setNull(this.objectID, this.nullPointer);
+ for (var i = 0; i < this.numLabels; i++)
+ {
+ world.setText(this.objectID, this.labels[i], i);
+ world.setTextColor(this.objectID, this.labelColors[i], i);
+ }
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedObject.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedObject.js
new file mode 100644
index 0000000..9ec734c
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedObject.js
@@ -0,0 +1,343 @@
+// 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 ``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 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
+
+function AnimatedObject()
+{
+ this.init();
+}
+
+AnimatedObject.prototype.init = function()
+{
+ this.backgroundColor = "#FFFFFF";
+ this.foregroundColor = "#000000";
+ this.highlighted = false;
+ this.objectID = -1;
+ this.layer = 0;
+ this.addedToScene = true;
+ this.label = "";
+ this.labelColor = "#000000";
+ this.alpha = 1.0;
+ this.x = 0;
+ this.y = 0;
+ this.minHeightDiff = 3;
+ this.range = 5;
+ this.highlightIndex = -1;
+ this.highlightIndexDirty = true;
+}
+
+AnimatedObject.prototype.alwaysOnTop = false;
+
+AnimatedObject.prototype.setBackgroundColor = function(newColor)
+{
+ this.backgroundColor = newColor;
+}
+
+AnimatedObject.prototype.setForegroundColor = function(newColor)
+{
+ this.foregroundColor = newColor;
+}
+
+AnimatedObject.prototype.setNull = function()
+{
+
+}
+
+AnimatedObject.prototype.getNull = function()
+{
+ return false;
+}
+
+AnimatedObject.prototype.setAlpha = function(newAlpha)
+{
+ this.alpha = newAlpha;
+}
+
+AnimatedObject.prototype.getAlpha = function()
+{
+ return this.alpha;
+}
+
+AnimatedObject.prototype.setForegroundColor = function(newColor)
+{
+ this.foregroundColor = newColor;
+ this.labelColor = newColor;
+}
+
+
+AnimatedObject.prototype.getHighlight = function()
+{
+ return this.highlighted;
+}
+
+AnimatedObject.prototype.getWidth = function()
+{
+ // TODO: Do we want to throw here? Should always override this ...
+ return 0;
+}
+
+AnimatedObject.prototype.getHeight = function()
+{
+ // TODO: Do we want to throw here? Should always override this ...
+ return 0;
+}
+
+AnimatedObject.prototype.setHighlight = function(value)
+{
+ this.highlighted = value;
+}
+
+AnimatedObject.prototype.centerX = function()
+{
+ return this.x;
+}
+
+AnimatedObject.prototype.setWidth = function(newWidth)
+{
+ // TODO: Do we want to throw here? Should always override this ...
+}
+
+
+
+AnimatedObject.prototype.centerY = function()
+{
+ return this.y;
+}
+
+
+AnimatedObject.prototype.getAlignLeftPos = function(otherObject)
+{
+ return [otherObject.right()+ this.getWidth() / 2, otherObject.centerY()];
+}
+
+AnimatedObject.prototype.getAlignRightPos = function(otherObject)
+{
+
+ return [otherObject.left() - this.getWidth() / 2, otherObject.centerY()];
+}
+
+AnimatedObject.prototype.getAlignTopPos = function(otherObject)
+{
+
+ return [otherObject.centerX(), otherObject.top() - this.getHeight() / 2];
+}
+AnimatedObject.prototype.getAlignBottomPos = function(otherObject)
+{
+ return [otherObject.centerX(), otherObject.bottom() + this.getHeight() / 2];
+}
+
+
+AnimatedObject.prototype.alignLeft = function(otherObject)
+{
+ // Assuming centering. Overridden method could modify if not centered
+ // (See AnimatedLabel, for instance)
+ this.y = otherObject.centerY();
+ this.x = otherObject.right() + this.getWidth() / 2;
+}
+
+AnimatedObject.prototype.alignRight = function(otherObject)
+{
+ // Assuming centering. Overridden method could modify if not centered
+ // (See AnimatedLabel, for instance)
+ this.y = otherObject.centerY();
+ this.x = otherObject.left() - this.getWidth() / 2;
+}
+
+
+AnimatedObject.prototype.alignTop = function(otherObject)
+{
+ // Assuming centering. Overridden method could modify if not centered
+
+ this.x = otherObject.centerX();
+ this.y = otherObject.top() - this.getHeight() / 2;
+
+
+}
+
+
+AnimatedObject.prototype.alignBottom = function(otherObject)
+{
+ this.x = otherObject.centerX();
+ this.y = otherObject.bottom() + this.getHeight() / 2;
+
+}
+
+
+
+/* TODO: Do we need these in the base?
+ function left(): Number
+ {
+ return x - getWidth() / 2;
+ }
+
+ function right():Number
+ {
+ return x + getWidth() / 2;
+ }
+
+ function top():Number
+ {
+ return y - getHeight() / 2;
+ }
+
+ function bottom():Number
+ {
+ return y + getHeight() / 2;
+ }
+
+ function centerX():Number
+ {
+ return x;
+ }
+
+ function centerY():Number
+ {
+ return y;
+ }
+ */
+
+
+AnimatedObject.prototype.getClosestCardinalPoint = function(fromX, fromY)
+{
+ var xDelta;
+ var yDelta;
+ var xPos;
+ var yPos;
+
+ if (fromX < this.left())
+ {
+ xDelta = this.left() - fromX;
+ xPos = this.left();
+ }
+ else if (fromX > this.right())
+ {
+ xDelta = fromX - this.right();
+ xPos = this.right();
+ }
+ else
+ {
+ xDelta = 0;
+ xPos = this.centerX();
+ }
+
+ if (fromY < this.top())
+ {
+ yDelta = this.top() - fromY;
+ yPos = this.top();
+ }
+ else if (fromY > this.bottom())
+ {
+ yDelta = fromY - this.bottom();
+ yPos = this.bottom();
+ }
+ else
+ {
+ yDelta = 0;
+ yPos = this.centerY();
+ }
+
+ if (yDelta > xDelta)
+ {
+ xPos = this.centerX();
+ }
+ else
+ {
+ yPos = this.centerY();
+ }
+
+ return [xPos, yPos];
+}
+
+
+AnimatedObject.prototype.centered = function()
+{
+ return false;
+}
+
+
+AnimatedObject.prototype.pulseHighlight = function(frameNum)
+{
+ if (this.highlighted)
+ {
+ var frameMod = frameNum / 7.0;
+ var delta = Math.abs((frameMod) % (2 * this.range - 2) - this.range + 1)
+ this.highlightDiff = delta + this.minHeightDiff;
+ }
+
+}
+
+AnimatedObject.prototype.getTailPointerAttachPos = function(fromX, fromY, anchorPoint)
+{
+ return [this.x, this.y];
+}
+
+
+AnimatedObject.prototype.getHeadPointerAttachPos = function(fromX, fromY)
+{
+ return [this.x, this.y];
+}
+
+/*public function createUndoDelete() : UndoBlock
+{
+ // Must be overriden!
+ return null;
+}
+*/
+AnimatedObject.prototype.identifier = function()
+{
+ return this.objectID;
+}
+
+AnimatedObject.prototype.getText = function(index)
+{
+ return this.label;
+}
+
+AnimatedObject.prototype.getTextColor = function(textIndex)
+{
+ return this.labelColor
+}
+
+AnimatedObject.prototype.setTextColor = function(color, textIndex)
+{
+ this.labelColor = color;
+}
+
+AnimatedObject.prototype.setText = function(newText, textIndex)
+{
+ this.label = newText;
+}
+
+AnimatedObject.prototype.setHighlightIndex = function(hlIndex)
+{
+ this.highlightIndex = hlIndex;
+ this.highlightIndexDirty = true;
+}
+
+
+AnimatedObject.prototype.getHighlightIndex = function()
+{
+ return this.highlightIndex;
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedRectangle.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedRectangle.js
new file mode 100644
index 0000000..1f566a1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimatedRectangle.js
@@ -0,0 +1,340 @@
+// 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 ``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 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
+
+// Values for xJust / yJust: "center", "left", "right", "top", "bottom"
+
+AnimatedRectangle = function(id, val, wth, hgt, xJust, yJust, fillColor, edgeColor)
+{
+ this.w = wth;
+ this.h = hgt;
+ this.xJustify = xJust;
+ this.yJustify = yJust;
+ this.label = val;
+ this.labelColor = edgeColor
+
+ this.backgroundColor = fillColor;
+ this.foregroundColor = edgeColor;
+ this.labelColor = this.foregroundColor;
+ this.highlighted = false;
+ this.objectID = id;
+ this.nullPointer = false;
+ this.alpha = 1.0;
+ this.addedToScene = true;
+
+}
+
+AnimatedRectangle.prototype = new AnimatedObject();
+AnimatedRectangle.prototype.constructor = AnimatedRectangle;
+
+AnimatedRectangle.prototype.setNull = function(np)
+{
+ this.nullPointer = np;
+}
+
+AnimatedRectangle.prototype.getNull = function()
+{
+ return this.nullPointer;
+}
+
+
+AnimatedRectangle.prototype.left = function()
+{
+ if (this.xJustify == "left")
+ {
+ return this.x;
+ }
+ else if (this.xJustify == "center")
+ {
+ return this.x - this.w / 2.0;
+ }
+ else // (this.xJustify == "right")
+ {
+ return this.x - this.w;
+ }
+
+}
+
+AnimatedRectangle.prototype.centerX = function()
+{
+ if (this.xJustify == "center")
+ {
+ return this.x;
+ }
+ else if (this.xJustify == "left")
+ {
+ return this.x + this.w / 2.0;
+ }
+ else // (this.xJustify == "right")
+ {
+ return this.x - this.w / 2.0;
+ }
+}
+
+AnimatedRectangle.prototype.centerY = function()
+{
+ if (this.yJustify == "center")
+ {
+ return this.y;
+ }
+ else if (this.yJustify == "top")
+ {
+ return this.y + this.h / 2.0;
+ }
+ else // (this.xJustify == "bottom")
+ {
+ return this.y - this.w / 2.0;
+ }
+
+}
+
+AnimatedRectangle.prototype.top = function()
+{
+ if (this.yJustify == "top")
+ {
+ return this.y;
+ }
+ else if (this.yJustify == "center")
+ {
+ return this.y - this.h / 2.0;
+ }
+ else //(this.xJustify == "bottom")
+ {
+ return this.y - this.h;
+ }
+}
+
+AnimatedRectangle.prototype.bottom = function()
+{
+ if (this.yJustify == "top")
+ {
+ return this.y + this.h;
+ }
+ else if (this.yJustify == "center")
+ {
+ return this.y + this.h / 2.0;
+ }
+ else //(this.xJustify == "bottom")
+ {
+ return this.y;
+ }
+}
+
+
+AnimatedRectangle.prototype.right = function()
+{
+ if (this.xJustify == "left")
+ {
+ return this.x + this.w;
+ }
+ else if (this.xJustify == "center")
+ {
+ return this.x + this.w / 2.0;
+ }
+ else // (this.xJustify == "right")
+ {
+ return this.x;
+ }
+}
+
+
+AnimatedRectangle.prototype.getHeadPointerAttachPos = function(fromX, fromY)
+{
+ return this.getClosestCardinalPoint(fromX, fromY);
+}
+
+
+AnimatedRectangle.prototype.setWidth = function(wdth)
+{
+ this.w = wdth;
+}
+
+
+AnimatedRectangle.prototype.setHeight = function(hght)
+{
+ this.h = hght;
+}
+
+AnimatedRectangle.prototype.getWidth = function()
+{
+ return this.w;
+}
+
+AnimatedRectangle.prototype.getHeight = function()
+{
+ return this.h;
+}
+
+
+// TODO: Fix me!
+AnimatedRectangle.prototype.draw = function(context)
+{
+ if (!this.addedToScene)
+ {
+ return;
+ }
+
+ var startX;
+ var startY;
+ var labelPosX;
+ var labelPosY;
+
+ context.globalAlpha = this.alpha;
+
+ if (this.xJustify == "left")
+ {
+ startX = this.x;
+ labelPosX = this.x + this.w / 2.0;
+ }
+ else if (this.xJustify == "center")
+ {
+ startX = this.x-this.w / 2.0;
+ labelPosX = this.x;
+
+ }
+ else if (this.xJustify == "right")
+ {
+ startX = this.x-this.w;
+ labelPosX = this.x - this.w / 2.0
+ }
+ if (this.yJustify == "top")
+ {
+ startY = this.y;
+ labelPosY = this.y + this.h / 2.0;
+ }
+ else if (this.yJustify == "center")
+ {
+ startY = this.y - this.h / 2.0;
+ labelPosY = this.y;
+
+ }
+ else if (this.yJustify == "bottom")
+ {
+ startY = this.y - this.h;
+ labelPosY = this.y - this.h / 2.0;
+ }
+
+ context.lineWidth = 1;
+
+ if (this.highlighted)
+ {
+ context.strokeStyle = "#ff0000";
+ context.fillStyle = "#ff0000";
+
+ context.beginPath();
+ context.moveTo(startX - this.highlightDiff,startY- this.highlightDiff);
+ context.lineTo(startX+this.w + this.highlightDiff,startY- this.highlightDiff);
+ context.lineTo(startX+this.w+ this.highlightDiff,startY+this.h + this.highlightDiff);
+ context.lineTo(startX - this.highlightDiff,startY+this.h + this.highlightDiff);
+ context.lineTo(startX - this.highlightDiff,startY - this.highlightDiff);
+ context.closePath();
+ context.stroke();
+ context.fill();
+
+ }
+ context.strokeStyle = this.foregroundColor;
+ context.fillStyle = this.backgroundColor;
+
+ context.beginPath();
+ context.moveTo(startX ,startY);
+ context.lineTo(startX + this.w, startY);
+ context.lineTo(startX + this.w, startY + this.h);
+ context.lineTo(startX, startY + this.h);
+ context.lineTo(startX, startY);
+ context.closePath();
+ context.stroke();
+ context.fill();
+
+ if (this.nullPointer)
+ {
+ context.beginPath();
+ context.moveTo(startX ,startY);
+ context.lineTo(startX + this.w, startY + this.h);
+ context.closePath();
+ context.stroke();
+ }
+
+ context.fillStyle = this.labelColor;
+
+ context.textAlign = 'center';
+ context.font = '16px Consolas';
+ context.textBaseline = 'middle';
+ context.lineWidth = 1;
+ context.fillText(this.label, this.x, this.y);
+
+
+
+}
+
+AnimatedRectangle.prototype.setText = function(newText, textIndex)
+{
+ this.label = newText;
+ // TODO: setting text position?
+}
+
+
+AnimatedRectangle.prototype.createUndoDelete = function()
+{
+ // TODO: Add color?
+ return new UndoDeleteRectangle(this.objectID, this.label, this.x, this.y, this.w, this.h, this.xJustify, this.yJustify, this.backgroundColor, this.foregroundColor, this.highlighted, this.layer);
+}
+
+AnimatedRectangle.prototype.setHighlight = function(value)
+{
+ this.highlighted = value;
+}
+
+
+
+function UndoDeleteRectangle(id, lab, x, y, w, h, xJust, yJust, bgColor, fgColor, highlight, lay)
+{
+ this.objectID = id;
+ this.posX = x;
+ this.posY = y;
+ this.width = w;
+ this.height = h;
+ this.xJustify = xJust;
+ this.yJustify = yJust;
+ this.backgroundColor= bgColor;
+ this.foregroundColor = fgColor;
+ this.nodeLabel = lab;
+ this.layer = lay;
+ this.highlighted = highlight;
+}
+
+UndoDeleteRectangle.prototype = new UndoBlock();
+UndoDeleteRectangle.prototype.constructor = UndoDeleteRectangle;
+
+
+UndoDeleteRectangle.prototype.undoInitialStep = function(world)
+{
+ world.addRectangleObject(this.objectID, this.nodeLabel, this.width, this.height, this.xJustify, this.yJustify, this.backgroundColor, this.foregroundColor);
+ world.setNodePosition(this.objectID, this.posX, this.posY);
+ world.setLayer(this.objectID, this.layer);
+ world.setHighlight(this.objectID, this.highlighted);
+}
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimationMain.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimationMain.js
new file mode 100644
index 0000000..8a033be
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/AnimationMain.js
@@ -0,0 +1,1361 @@
+// 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 ``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 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
+
+// Global timer used for doing animation callbacks.
+// TODO: Make this an instance variable of Animation Manager.
+var timer;
+var swapped = false;
+
+
+function reorderSibling(node1, node2)
+{
+ node1.parentNode.replaceChild(node1, node2);
+ node1.parentNode.insertBefore(node2, node1);
+}
+
+
+function swapControlDiv()
+{
+ swapped = !swapped;
+ if (swapped) {
+ reorderSibling(document.getElementById('canvas'), document.getElementById('generalAnimationControlSection'));
+ setCookie("VisualizationControlSwapped", "true", 30);
+
+ } else {
+ reorderSibling(document.getElementById('generalAnimationControlSection'), document.getElementById('canvas'));
+ setCookie("VisualizationControlSwapped", "false", 30);
+
+ }
+}
+
+
+// Utility funciton to read a cookie
+function getCookie(cookieName)
+{
+ var i, x, y;
+ var cookies=document.cookie.split(";");
+ for (i=0; i < cookies.length; i++)
+ {
+ x=cookies[i].substr(0,cookies[i].indexOf("="));
+ y=cookies[i].substr(cookies[i].indexOf("=")+1);
+ x=x.replace(/^\s+|\s+$/g,"");
+ if (x==cookieName)
+ {
+ return unescape(y);
+ }
+ }
+}
+
+// Utility funciton to write a cookie
+function setCookie(cookieName,value,expireDays)
+{
+ var exdate=new Date();
+ exdate.setDate(exdate.getDate() + expireDays);
+ var cookieValue=escape(value) + ((expireDays==null) ? "" : "; expires="+exdate.toUTCString());
+ document.cookie=cookieName + "=" + value;
+}
+
+
+var ANIMATION_SPEED_DEFAULT = 75;
+
+
+// TODO: Move these out of global space into animation manager?
+var objectManager;
+var animationManager;
+var canvas;
+
+var paused = false;
+var playPauseBackButton;
+var skipBackButton;
+var stepBackButton;
+var stepForwardButton;
+var skipForwardButton;
+
+var widthEntry;
+var heightEntry;
+var sizeButton;
+
+
+
+function returnSubmit(field, funct, maxsize, intOnly)
+{
+
+ if (maxsize != undefined)
+ {
+ field.size = maxsize;
+ }
+ return function(event)
+ {
+ var keyASCII = 0;
+ if(window.event) // IE
+ {
+ keyASCII = event.keyCode
+ }
+ else if (event.which) // Netscape/Firefox/Opera
+ {
+ keyASCII = event.which
+ }
+
+ if (keyASCII == 13)
+ {
+ funct();
+ return false;
+ }
+ else if (keyASCII == 59 || keyASCII == 45 || keyASCII == 46 || keyASCII == 190 || keyASCII == 173)
+ {
+ return false;
+ }
+ else if (maxsize != undefined && field.value.length >= maxsize ||
+ intOnly && (keyASCII < 48 || keyASCII > 57))
+
+ {
+ if (!controlKey(keyASCII))
+ return false;
+ }
+ return true;
+
+ }
+
+}
+
+
+function animWaiting()
+{
+ stepForwardButton.disabled = false;
+ if (skipBackButton.disabled == false)
+ {
+ stepBackButton.disabled = false;
+ }
+ objectManager.statusReport.setText("动画暂停");
+ objectManager.statusReport.setForegroundColor("#FF0000");
+}
+
+function animStarted()
+{
+ skipForwardButton.disabled = false;
+ skipBackButton.disabled = false;
+ stepForwardButton.disabled = true;
+ stepBackButton.disabled = true;
+ objectManager.statusReport.setText("动画执行中...");
+ objectManager.statusReport.setForegroundColor("#009900");
+}
+
+function animEnded()
+{
+ skipForwardButton.disabled = true;
+ stepForwardButton.disabled = true;
+ if (skipBackButton.disabled == false && paused)
+ {
+ stepBackButton.disabled = false;
+ }
+ objectManager.statusReport.setText("动画执行完毕");
+ objectManager.statusReport.setForegroundColor("#000000");
+}
+
+
+
+function anumUndoUnavailable()
+{
+ skipBackButton.disabled = true;
+ stepBackButton.disabled = true;
+}
+
+
+function timeout()
+{
+ // We need to set the timeout *first*, otherwise if we
+ // try to clear it later, we get behavior we don't want ...
+ timer = setTimeout('timeout()', 30);
+ animationManager.update();
+ objectManager.draw();
+
+}
+
+
+function doStep()
+{
+ animationManager.step();
+}
+
+
+function doSkip()
+{
+ animationManager.skipForward();
+}
+
+
+function doSkipBack()
+{
+ animationManager.skipBack();
+}
+
+
+function doStepBack()
+{
+ animationManager.stepBack();
+}
+function doPlayPause()
+{
+ paused = !paused;
+ if (paused)
+ {
+ playPauseBackButton.setAttribute("value", "play");
+ if (skipBackButton.disabled == false)
+ {
+ stepBackButton.disabled = false;
+ }
+
+ }
+ else
+ {
+ playPauseBackButton.setAttribute("value", "pause");
+ }
+ animationManager.SetPaused(paused);
+}
+
+
+function addControl(type, name, location) {
+
+ var element = document.createElement("input");
+
+ element.setAttribute("type", type);
+ element.setAttribute("value", name);
+
+ var tableEntry = document.createElement("td");
+
+ tableEntry.appendChild(element);
+
+
+ var controlBar = document.getElementById(tableEntry);
+
+ //Append the element in page (in span).
+ controlBar.appendChild(element);
+ return element;
+
+}
+
+function addControlToAnimationBar(type,name,containerType)
+{
+ if (containerType == undefined)
+ {
+ containerType = "input";
+ }
+ var element = document.createElement(containerType);
+
+ element.setAttribute("type", type);
+ element.setAttribute("value", name);
+
+
+ var tableEntry = document.createElement("td");
+
+ tableEntry.appendChild(element);
+
+ var controlBar = document.getElementById("GeneralAnimationControls");
+
+ //Append the element in page (in span).
+ controlBar.appendChild(tableEntry);
+ return element;
+
+}
+
+
+function initCanvas()
+{
+ canvas = document.getElementById("canvas");
+ objectManager = new ObjectManager();
+ animationManager = new AnimationManager(objectManager);
+
+ skipBackButton = addControlToAnimationBar("Button", "快退");
+ skipBackButton.onclick = animationManager.skipBack.bind(animationManager);
+ stepBackButton = addControlToAnimationBar("Button", "后退");
+ stepBackButton.onclick = animationManager.stepBack.bind(animationManager);
+ playPauseBackButton = addControlToAnimationBar("Button", "暂停");
+ playPauseBackButton.onclick = doPlayPause ;
+ stepForwardButton = addControlToAnimationBar("Button", "前进");
+ stepForwardButton.onclick = animationManager.step.bind(animationManager) ;
+ skipForwardButton = addControlToAnimationBar("Button", "快进");
+ skipForwardButton.onclick = animationManager.skipForward.bind(animationManager);
+
+
+ var element = document.createElement("div");
+ element.setAttribute("display", "inline-block");
+ element.setAttribute("float", "left");
+
+
+ var tableEntry = document.createElement("td");
+
+
+ var controlBar = document.getElementById("GeneralAnimationControls");
+
+
+
+ var newTable = document.createElement("table");
+
+ var midLevel = document.createElement("tr");
+ var bottomLevel = document.createElement("td");
+ midLevel.appendChild(bottomLevel);
+ bottomLevel.appendChild(element);
+ newTable.appendChild(midLevel);
+
+
+
+ midLevel = document.createElement("tr");
+ bottomLevel = document.createElement("td");
+ bottomLevel.align = "center";
+ var txtNode = document.createTextNode("动画速率");
+ midLevel.appendChild(bottomLevel);
+ bottomLevel.appendChild(txtNode);
+ newTable.appendChild(midLevel);
+
+
+
+ tableEntry.appendChild(newTable);
+
+
+
+ //Append the element in page (in span).
+ controlBar.appendChild(tableEntry);
+
+ //tableEntry.appendChild(element);
+
+ var speed = getCookie("VisualizationSpeed");
+ if (speed == null || speed == "")
+ {
+ speed = ANIMATION_SPEED_DEFAULT;
+ }
+ else
+ {
+ speed = parseInt(speed);
+ }
+
+ $(element).slider({
+ animate: true,
+ value: speed,
+ change: function(e, ui)
+ {
+ setCookie("VisualizationSpeed", String(ui.value), 30);
+ },
+ slide : function(e, ui){
+ animationManager.SetSpeed(ui.value);
+ }
+
+ });
+
+ animationManager.SetSpeed(speed);
+
+ element.setAttribute("style", "width:200px");
+
+
+
+ var width=getCookie("VisualizationWidth");
+ if (width == null || width == "")
+ {
+ width = canvas.width;
+ }
+ else
+ {
+ width = parseInt(width);
+ }
+ var height=getCookie("VisualizationHeight");
+ if (height == null || height == "")
+ {
+ height = canvas.height;
+ }
+ else
+ {
+ height = parseInt(height);
+ }
+
+ var swappedControls=getCookie("VisualizationControlSwapped");
+ swapped = swappedControls == "true"
+ if (swapped)
+ {
+ reorderSibling(document.getElementById('canvas'), document.getElementById('generalAnimationControlSection'));
+ }
+
+ canvas.width = width;
+ canvas.height = height;
+
+
+
+ tableEntry = document.createElement("td");
+ txtNode = document.createTextNode(" 宽度 :");
+ tableEntry.appendChild(txtNode);
+ controlBar.appendChild(tableEntry);
+
+
+ widthEntry = addControlToAnimationBar("Text", canvas.width);
+ widthEntry.size = 4;
+ widthEntry.onkeydown = this.returnSubmit(widthEntry, animationManager.changeSize.bind(animationManager), 4, true);
+
+
+ tableEntry = document.createElement("td");
+ txtNode = document.createTextNode(" 高度 :");
+ tableEntry.appendChild(txtNode);
+ controlBar.appendChild(tableEntry);
+
+ heightEntry = addControlToAnimationBar("Text", canvas.height);
+ heightEntry.onkeydown = this.returnSubmit(heightEntry, animationManager.changeSize.bind(animationManager), 4, true);
+
+// heightEntry.size = 4;
+ sizeButton = addControlToAnimationBar("Button", "更改画布大小");
+
+ sizeButton.onclick = animationManager.changeSize.bind(animationManager) ;
+
+
+ swapButton = addControlToAnimationBar("Button", "挪动控制面板");
+ swapButton.onclick = swapControlDiv;
+
+
+ animationManager.addListener("AnimationStarted", this, animStarted);
+ animationManager.addListener("AnimationEnded", this, this.animEnded);
+ animationManager.addListener("AnimationWaiting", this, this.animWaiting);
+ animationManager.addListener("AnimationUndoUnavailable", this, this.anumUndoUnavailable);
+ objectManager.width = canvas.width;
+ objectManager.height = canvas.height;
+ return animationManager;
+}
+
+
+
+function AnimationManager(objectManager)
+{
+ // Holder for all animated objects.
+ // All animation is done by manipulating objects in\
+ // this container
+ this.animatedObjects = objectManager;
+
+ // Control variables for stopping / starting animation
+
+ this.animationPaused = false;
+ this.awaitingStep = false;
+ this.currentlyAnimating = false;
+
+ // Array holding the code for the animation. This is
+ // an array of strings, each of which is an animation command
+ // currentAnimation is an index into this array
+ this.AnimationSteps = [];
+ this.currentAnimation = 0;
+
+ this.previousAnimationSteps = [];
+
+ // Control variables for where we are in the current animation block.
+ // currFrame holds the frame number of the current animation block,
+ // while animationBlockLength holds the length of the current animation
+ // block (in frame numbers).
+ this.currFrame = 0;
+ this.animationBlockLength = 0;
+
+ // The animation block that is currently running. Array of singleAnimations
+ this.currentBlock = null;
+
+ /////////////////////////////////////
+ // Variables for handling undo.
+ ////////////////////////////////////
+ // A stack of UndoBlock objects (subclassed, UndoBlock is an abstract base class)
+ // each of which can undo a single animation element
+ this.undoStack = [];
+ this.doingUndo = false;
+
+ // A stack containing the beginning of each animation block, as an index
+ // into the AnimationSteps array
+ this.undoAnimationStepIndices = [];
+ this.undoAnimationStepIndicesStack = [];
+
+ this.animationBlockLength = 10;
+
+ this.lerp = function(from, to, percent)
+ {
+ return (to - from) * percent + from;
+ }
+
+ // Pause / unpause animation
+ this.SetPaused = function(pausedValue)
+ {
+ this.animationPaused = pausedValue;
+ if (!this.animationPaused)
+ {
+ this.step();
+ }
+ }
+
+ // Set the speed of the animation, from 0 (slow) to 100 (fast)
+ this.SetSpeed = function(newSpeed)
+ {
+ this.animationBlockLength = Math.floor((100-newSpeed) / 2);
+ }
+
+
+ this.parseBool = function(str)
+ {
+ var uppercase = str.toUpperCase();
+ var returnVal = !(uppercase == "False" || uppercase == "f" || uppercase == " 0" || uppercase == "0" || uppercase == "");
+ return returnVal;
+
+ }
+
+ this.parseColor = function(clr)
+ {
+ if (clr.charAt(0) == "#")
+ {
+ return clr;
+ }
+ else if (clr.substring(0,2) == "0x")
+ {
+ return "#" + clr.substring(2);
+ }
+ }
+
+
+ this.changeSize = function()
+ {
+
+ var width = parseInt(widthEntry.value);
+ var height = parseInt(heightEntry.value);
+
+ if (width > 100)
+ {
+ canvas.width = width;
+ this.animatedObjects.width = width;
+ setCookie("VisualizationWidth", String(width), 30);
+
+ }
+ if (height > 100)
+ {
+ canvas.height = height;
+ this.animatedObjects.height = height;
+ setCookie("VisualizationHeight", String(height), 30);
+ }
+ width.value = canvas.width;
+ heightEntry.value = canvas.height;
+
+ this.animatedObjects.draw();
+ this.fireEvent("CanvasSizeChanged",{width:canvas.width, height:canvas.height});
+ }
+
+ this.startNextBlock = function()
+ {
+ this.awaitingStep = false;
+ this.currentBlock = [];
+ var undoBlock = []
+ if (this.currentAnimation == this.AnimationSteps.length )
+ {
+ this.currentlyAnimating = false;
+ this.awaitingStep = false;
+ this.fireEvent("AnimationEnded","NoData");
+ clearTimeout(timer);
+ this.animatedObjects.update();
+ this.animatedObjects.draw();
+
+ return;
+ }
+ this.undoAnimationStepIndices.push(this.currentAnimation);
+
+ var foundBreak= false;
+ var anyAnimations= false;
+
+ while (this.currentAnimation < this.AnimationSteps.length && !foundBreak)
+ {
+ var nextCommand = this.AnimationSteps[this.currentAnimation].split("<;>");
+ if (nextCommand[0].toUpperCase() == "CREATECIRCLE")
+ {
+ this.animatedObjects.addCircleObject(parseInt(nextCommand[1]), nextCommand[2]);
+ if (nextCommand.length > 4)
+ {
+ this.animatedObjects.setNodePosition(parseInt(nextCommand[1]), parseInt(nextCommand[3]), parseInt(nextCommand[4]));
+ }
+ undoBlock.push(new UndoCreate(parseInt(nextCommand[1])));
+
+ }
+ else if (nextCommand[0].toUpperCase() == "CONNECT")
+ {
+
+ if (nextCommand.length > 7)
+ {
+ this.animatedObjects.connectEdge(parseInt(nextCommand[1]),
+ parseInt(nextCommand[2]),
+ this.parseColor(nextCommand[3]),
+ parseFloat(nextCommand[4]),
+ this.parseBool(nextCommand[5]),
+ nextCommand[6],
+ parseInt(nextCommand[7]));
+ }
+ else if (nextCommand.length > 6)
+ {
+ this.animatedObjects.connectEdge(parseInt(nextCommand[1]),
+ parseInt(nextCommand[2]),
+ this.parseColor(nextCommand[3]),
+ parseFloat(nextCommand[4]),
+ this.parseBool(nextCommand[5]),
+ nextCommand[6],
+ 0);
+ }
+ else if (nextCommand.length > 5)
+ {
+ this.animatedObjects.connectEdge(parseInt(nextCommand[1]),
+ parseInt(nextCommand[2]),
+ this.parseColor(nextCommand[3]),
+ parseFloat(nextCommand[4]),
+ this.parseBool(nextCommand[5]),
+ "",
+ 0);
+ }
+ else if (nextCommand.length > 4)
+ {
+ this.animatedObjects.connectEdge(parseInt(nextCommand[1]),
+ parseInt(nextCommand[2]),
+ this.parseColor(nextCommand[3]),
+ parseFloat(nextCommand[4]),
+ true,
+ "",
+ 0);
+ }
+ else if (nextCommand.length > 3)
+ {
+ this.animatedObjects.connectEdge(parseInt(nextCommand[1]),
+ parseInt(nextCommand[2]),
+ this.parseColor(nextCommand[3]),
+ 0.0,
+ true,
+ "",
+ 0);
+ }
+ else
+ {
+ this.animatedObjects.connectEdge(parseInt(nextCommand[1]),
+ parseInt(nextCommand[2]),
+ "#000000",
+ 0.0,
+ true,
+ "",
+ 0);
+
+ }
+ undoBlock.push(new UndoConnect(parseInt(nextCommand[1]), parseInt (nextCommand[2]), false));
+ }
+ else if (nextCommand[0].toUpperCase() == "CREATERECTANGLE")
+ {
+ if (nextCommand.length == 9)
+ {
+ this.animatedObjects.addRectangleObject(parseInt(nextCommand[1]), // ID
+ nextCommand[2], // Label
+ parseInt(nextCommand[3]), // w
+ parseInt(nextCommand[4]), // h
+ nextCommand[7], // xJustify
+ nextCommand[8],// yJustify
+ "#ffffff", // background color
+ "#000000"); // foreground color
+ }
+ else
+ {
+ this.animatedObjects.addRectangleObject(parseInt(nextCommand[1]), // ID
+ nextCommand[2], // Label
+ parseInt(nextCommand[3]), // w
+ parseInt(nextCommand[4]), // h
+ "center", // xJustify
+ "center",// yJustify
+ "#ffffff", // background color
+ "#000000"); // foreground color
+
+ }
+ if (nextCommand.length > 6)
+ {
+ this.animatedObjects.setNodePosition(parseInt(nextCommand[1]), parseInt(nextCommand[5]), parseInt(nextCommand[6]));
+ }
+ undoBlock.push(new UndoCreate(parseInt(nextCommand[1])));
+ }
+
+ else if (nextCommand[0].toUpperCase() == "MOVE")
+ {
+ var objectID = parseInt(nextCommand[1]);
+ var nextAnim = new SingleAnimation(objectID,
+ this.animatedObjects.getNodeX(objectID),
+ this.animatedObjects.getNodeY(objectID),
+ parseInt(nextCommand[2]),
+ parseInt(nextCommand[3]));
+ this.currentBlock.push(nextAnim);
+
+ undoBlock.push(new UndoMove(nextAnim.objectID, nextAnim.toX, nextAnim.toY, nextAnim.fromX, nextAnim.fromY));
+
+ anyAnimations = true;
+ }
+
+ else if (nextCommand[0].toUpperCase() == "MOVETOALIGNRIGHT")
+ {
+ var id = parseInt(nextCommand[1]);
+ var otherId = parseInt(nextCommand[2]);
+ var newXY = this.animatedObjects.getAlignRightPos(id, otherId);
+
+
+ var nextAnim = new SingleAnimation(id,
+ this.animatedObjects.getNodeX(id),
+ this.animatedObjects.getNodeY(id),
+ newXY[0],
+ newXY[1]);
+ this.currentBlock.push(nextAnim);
+ undoBlock.push(new UndoMove(nextAnim.objectID, nextAnim.toX, nextAnim.toY, nextAnim.fromX, nextAnim.fromY));
+ anyAnimations = true;
+ }
+
+ else if (nextCommand[0].toUpperCase() == "STEP")
+ {
+ foundBreak = true;
+ }
+ else if (nextCommand[0].toUpperCase() == "SETFOREGROUNDCOLOR")
+ {
+ var id = parseInt(nextCommand[1]);
+ var oldColor = this.animatedObjects.foregroundColor(id);
+ this.animatedObjects.setForegroundColor(id, this.parseColor(nextCommand[2]));
+ undoBlock.push(new UndoSetForegroundColor(id, oldColor));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETBACKGROUNDCOLOR")
+ {
+ id = parseInt(nextCommand[1]);
+ oldColor = this.animatedObjects.backgroundColor(id);
+ this.animatedObjects.setBackgroundColor(id, this.parseColor(nextCommand[2]));
+ undoBlock.push(new UndoSetBackgroundColor(id, oldColor));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETHIGHLIGHT")
+ {
+ var newHighlight = this.parseBool(nextCommand[2]);
+ this.animatedObjects.setHighlight( parseInt(nextCommand[1]), newHighlight);
+ undoBlock.push(new UndoHighlight( parseInt(nextCommand[1]), !newHighlight));
+ }
+ else if (nextCommand[0].toUpperCase() == "DISCONNECT")
+ {
+ var undoConnect = this.animatedObjects.disconnect(parseInt(nextCommand[1]), parseInt(nextCommand[2]));
+ if (undoConnect != null)
+ {
+ undoBlock.push(undoConnect);
+ }
+ }
+ else if (nextCommand[0].toUpperCase() == "SETALPHA")
+ {
+ var oldAlpha = this.animatedObjects.getAlpha(parseInt(nextCommand[1]));
+ this.animatedObjects.setAlpha(parseInt(nextCommand[1]), parseFloat(nextCommand[2]));
+ undoBlock.push(new UndoSetAlpha(parseInt(nextCommand[1]), oldAlpha));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETTEXT")
+ {
+ if (nextCommand.length > 3)
+ {
+ var oldText = this.animatedObjects.getText(parseInt(nextCommand[1]), parseInt(nextCommand[3]));
+ this.animatedObjects.setText(parseInt(nextCommand[1]), nextCommand[2], parseInt(nextCommand[3]));
+ if (oldText != undefined)
+ {
+ undoBlock.push(new UndoSetText(parseInt(nextCommand[1]), oldText, parseInt(nextCommand[3]) ));
+ }
+ }
+ else
+ {
+ oldText = this.animatedObjects.getText(parseInt(nextCommand[1]), 0);
+ this.animatedObjects.setText(parseInt(nextCommand[1]), nextCommand[2], 0);
+ if (oldText != undefined)
+ {
+ undoBlock.push(new UndoSetText(parseInt(nextCommand[1]), oldText, 0));
+ }
+ }
+ }
+ else if (nextCommand[0].toUpperCase() == "DELETE")
+ {
+ var objectID = parseInt(nextCommand[1]);
+
+ var i;
+ var removedEdges = this.animatedObjects.deleteIncident(objectID);
+ if (removedEdges.length > 0)
+ {
+ undoBlock = undoBlock.concat(removedEdges);
+ }
+ var obj = this.animatedObjects.getObject(objectID);
+ if (obj != null)
+ {
+ undoBlock.push(obj.createUndoDelete());
+ this.animatedObjects.removeObject(objectID);
+ }
+ }
+ else if (nextCommand[0].toUpperCase() == "CREATEHIGHLIGHTCIRCLE")
+ {
+ if (nextCommand.length > 5)
+ {
+ this.animatedObjects.addHighlightCircleObject(parseInt(nextCommand[1]), this.parseColor(nextCommand[2]), parseFloat(nextCommand[5]));
+ }
+ else
+ {
+ this.animatedObjects.addHighlightCircleObject(parseInt(nextCommand[1]), this.parseColor(nextCommand[2]), 20);
+ }
+ if (nextCommand.length > 4)
+ {
+ this.animatedObjects.setNodePosition(parseInt(nextCommand[1]), parseInt(nextCommand[3]), parseInt(nextCommand[4]));
+ }
+ undoBlock.push(new UndoCreate(parseInt(nextCommand[1])));
+
+
+ }
+ else if (nextCommand[0].toUpperCase() == "CREATELABEL")
+ {
+ if (nextCommand.length == 6)
+ {
+ this.animatedObjects.addLabelObject(parseInt(nextCommand[1]), nextCommand[2], this.parseBool(nextCommand[5]));
+ }
+ else
+ {
+ this.animatedObjects.addLabelObject(parseInt(nextCommand[1]), nextCommand[2], true);
+ }
+ if (nextCommand.length >= 5)
+ {
+
+ this.animatedObjects.setNodePosition(parseInt(nextCommand[1]), parseFloat(nextCommand[3]), parseFloat(nextCommand[4]));
+ }
+ undoBlock.push(new UndoCreate(parseInt(nextCommand[1])));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETEDGECOLOR")
+ {
+ var from = parseInt(nextCommand[1]);
+ var to = parseInt(nextCommand[2]);
+ var newColor = this.parseColor(nextCommand[3]);
+ var oldColor = this.animatedObjects.setEdgeColor(from, to, newColor);
+ undoBlock.push(new UndoSetEdgeColor(from, to, oldColor));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETEDGEALPHA")
+ {
+ var from = parseInt(nextCommand[1]);
+ var to = parseInt(nextCommand[2]);
+ var newAlpha = parseFloat(nextCommand[3]);
+ var oldAplpha = this.animatedObjects.setEdgeAlpha(from, to, newAlpha);
+ undoBlock.push(new UndoSetEdgeAlpha(from, to, oldAplpha));
+ }
+
+
+ else if (nextCommand[0].toUpperCase() == "SETEDGEHIGHLIGHT")
+ {
+ var newHighlight = this.parseBool(nextCommand[3]);
+ var from = parseInt(nextCommand[1]);
+ var to = parseInt(nextCommand[2]);
+ var oldHighlight = this.animatedObjects.setEdgeHighlight(from, to, newHighlight);
+ undoBlock.push(new UndoHighlightEdge(from, to, oldHighlight));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETHEIGHT")
+ {
+ id = parseInt(nextCommand[1]);
+ var oldHeight = this.animatedObjects.getHeight(id);
+ this.animatedObjects.setHeight(id, parseInt(nextCommand[2]));
+ undoBlock.push(new UndoSetHeight(id, oldHeight));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETLAYER")
+ {
+ this.animatedObjects.setLayer(parseInt(nextCommand[1]), parseInt(nextCommand[2]));
+ //TODO: Add undo information here
+ }
+
+
+ else if (nextCommand[0].toUpperCase() == "CREATELINKEDLIST")
+ {
+ if (nextCommand.length == 11)
+ {
+ this.animatedObjects.addLinkedListObject(parseInt(nextCommand[1]), nextCommand[2],
+ parseInt(nextCommand[3]), parseInt(nextCommand[4]), parseFloat(nextCommand[7]),
+ this.parseBool(nextCommand[8]), this.parseBool(nextCommand[9]),parseInt(nextCommand[10]), "#FFFFFF", "#000000");
+ }
+ else
+ {
+ this.animatedObjects.addLinkedListObject(parseInt(nextCommand[1]), nextCommand[2], parseInt(nextCommand[3]), parseInt(nextCommand[4]), 0.25, true, false, 1, "#FFFFFF", "#000000");
+ }
+ if (nextCommand.length > 6)
+ {
+ this.animatedObjects.setNodePosition(parseInt(nextCommand[1]), parseInt(nextCommand[5]), parseInt(nextCommand[6]));
+ undoBlock.push(new UndoCreate(parseInt(nextCommand[1])));
+ }
+
+ }
+ else if (nextCommand[0].toUpperCase() == "SETNULL")
+ {
+ var oldNull = this.animatedObjects.getNull(parseInt(nextCommand[1]));
+ this.animatedObjects.setNull(parseInt(nextCommand[1]), this.parseBool(nextCommand[2]));
+ undoBlock.push(new UndoSetNull(parseInt(nextCommand[1]), oldNull));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETTEXTCOLOR")
+ {
+ if (nextCommand.length > 3)
+ {
+ oldColor = this.animatedObjects.getTextColor(parseInt(nextCommand[1]), parseInt(nextCommand[3]));
+ this.animatedObjects.setTextColor(parseInt(nextCommand[1]), this.parseColor(nextCommand[2]), parseInt(nextCommand[3]));
+ undoBlock.push(new UndoSetTextColor(parseInt(nextCommand[1]), oldColor, parseInt(nextCommand[3]) ));
+ }
+ else
+ {
+ oldColor = this.animatedObjects.getTextColor(parseInt(nextCommand[1]), 0);
+ this.animatedObjects.setTextColor(parseInt(nextCommand[1]),this.parseColor(nextCommand[2]), 0);
+ undoBlock.push(new UndoSetTextColor(parseInt(nextCommand[1]), oldColor, 0));
+ }
+ }
+
+
+ else if (nextCommand[0].toUpperCase() == "CREATEBTREENODE")
+ {
+
+ this.animatedObjects.addBTreeNode(parseInt(nextCommand[1]), parseFloat(nextCommand[2]), parseFloat(nextCommand[3]),
+ parseInt(nextCommand[4]),this.parseColor(nextCommand[7]), this.parseColor(nextCommand[8]));
+ this.animatedObjects.setNodePosition(parseInt(nextCommand[1]), parseInt(nextCommand[5]), parseInt(nextCommand[6]));
+ undoBlock.push(new UndoCreate(parseInt(nextCommand[1])));
+ }
+
+ else if (nextCommand[0].toUpperCase() == "SETWIDTH")
+ {
+ var id = parseInt(nextCommand[1]);
+ this.animatedObjects.setWidth(id, parseInt(nextCommand[2]));
+ var oldWidth = this.animatedObjects.getWidth(id);
+ undoBlock.push(new UndoSetWidth(id, oldWidth));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETNUMELEMENTS")
+ {
+ var oldElem = this.animatedObjects.getObject(parseInt(nextCommand[1]));
+ undoBlock.push(new UndoSetNumElements(oldElem, parseInt(nextCommand[2])));
+ this.animatedObjects.setNumElements(parseInt(nextCommand[1]), parseInt(nextCommand[2]));
+ }
+ else if (nextCommand[0].toUpperCase() == "SETPOSITION")
+ {
+ var id = parseInt(nextCommand[1])
+ var oldX = this.animatedObjects.getNodeX(id);
+ var oldY = this.animatedObjects.getNodeY(id);
+ undoBlock.push(new UndoSetPosition(id, oldX, oldY));
+ this.animatedObjects.setNodePosition(id, parseInt(nextCommand[2]), parseInt(nextCommand[3]));
+ }
+ else if (nextCommand[0].toUpperCase() == "ALIGNRIGHT")
+ {
+ var id = parseInt(nextCommand[1])
+ var oldX = this.animatedObjects.getNodeX(id);
+ var oldY = this.animatedObjects.getNodeY(id);
+ undoBlock.push(new UndoSetPosition(id, oldX. oldY));
+ this.animatedObjects.alignRight(id, parseInt(nextCommand[2]));
+ }
+ else if (nextCommand[0].toUpperCase() == "ALIGNLEFT")
+ {
+ var id = parseInt(nextCommand[1])
+ var oldX = this.animatedObjects.getNodeX(id);
+ var oldY = this.animatedObjects.getNodeY(id);
+ undoBlock.push(new UndoSetPosition(id, oldX. oldY));
+ this.animatedObjects.alignLeft(id, parseInt(nextCommand[2]));
+ }
+ else if (nextCommand[0].toUpperCase() == "ALIGNTOP")
+ {
+ var id = parseInt(nextCommand[1])
+ var oldX = this.animatedObjects.getNodeX(id);
+ var oldY = this.animatedObjects.getNodeY(id);
+ undoBlock.push(new UndoSetPosition(id, oldX. oldY));
+ this.animatedObjects.alignTop(id, parseInt(nextCommand[2]));
+ }
+ else if (nextCommand[0].toUpperCase() == "ALIGNBOTTOM")
+ {
+ var id = parseInt(nextCommand[1])
+ var oldX = this.animatedObjects.getNodeX(id);
+ var oldY = this.animatedObjects.getNodeY(id);
+ undoBlock.push(new UndoSetPosition(id, oldX. oldY));
+ this.animatedObjects.alignBottom(id, parseInt(nextCommand[2]));
+ }
+
+
+
+
+
+ else if (nextCommand[0].toUpperCase() == "SETHIGHLIGHTINDEX")
+ {
+ var id = parseInt(nextCommand[1]);
+ var index = parseInt(nextCommand[2]);
+ var oldIndex = this.animatedObjects.getHighlightIndex(id)
+ undoBlock.push(new UndoSetHighlightIndex(id, oldIndex));
+ this.animatedObjects.setHighlightIndex(id,index);
+ }
+ else
+ {
+ // throw "Unknown command: " + nextCommand[0];
+ }
+
+ this.currentAnimation = this.currentAnimation+1;
+ }
+ this.currFrame = 0;
+
+ // Hack: If there are not any animations, and we are currently paused,
+ // then set the current frame to the end of the anumation, so that we will
+ // advance immediagely upon the next step button. If we are not paused, then
+ // animate as normal.
+
+ if (!anyAnimations && this.animationPaused || (!anyAnimations && this.currentAnimation == this.AnimationSteps.length) )
+ {
+ this.currFrame = this.animationBlockLength;
+ }
+
+ this.undoStack.push(undoBlock);
+ }
+
+ // Start a new animation. The input parameter commands is an array of strings,
+ // which represents the animation to start
+ this.StartNewAnimation = function(commands)
+ {
+ clearTimeout(timer);
+ if (this.AnimationSteps != null)
+ {
+ this.previousAnimationSteps.push(this.AnimationSteps);
+ this.undoAnimationStepIndicesStack.push(this.undoAnimationStepIndices);
+ }
+ if (commands == undefined || commands.length == 0)
+ {
+ this.AnimationSteps = ["Step"];
+ }
+ else
+ {
+ this.AnimationSteps = commands;
+ }
+ this.undoAnimationStepIndices = new Array();
+ this.currentAnimation = 0;
+ this.startNextBlock();
+ this.currentlyAnimating = true;
+ this.fireEvent("AnimationStarted","NoData");
+ timer = setTimeout('timeout()', 30);
+
+ }
+
+
+ // Step backwards one step. A no-op if the animation is not currently paused
+ this.stepBack = function()
+ {
+ if (this.awaitingStep && this.undoStack != null && this.undoStack.length != 0)
+ {
+ // TODO: Get events working correctly!
+ this.fireEvent("AnimationStarted","NoData");
+ clearTimeout(timer);
+
+ this.awaitingStep = false;
+ this.undoLastBlock();
+ // Re-kick thie timer. The timer may or may not be running at this point,
+ // so to be safe we'll kill it and start it again.
+ clearTimeout(timer);
+ timer = setTimeout('timeout()', 30);
+
+
+ }
+ else if (!this.currentlyAnimating && this.animationPaused && this.undoAnimationStepIndices != null)
+ {
+ this.fireEvent("AnimationStarted","NoData");
+ this.currentlyAnimating = true;
+ this.undoLastBlock();
+ // Re-kick thie timer. The timer may or may not be running at this point,
+ // so to be safe we'll kill it and start it again.
+ clearTimeout(timer);
+ timer = setTimeout('timeout()', 30);
+
+ }
+
+ }
+ // Step forwards one step. A no-op if the animation is not currently paused
+ this.step = function()
+ {
+ if (this.awaitingStep)
+ {
+ this.startNextBlock();
+ this.fireEvent("AnimationStarted","NoData");
+ this.currentlyAnimating = true;
+ // Re-kick thie timer. The timer should be going now, but we've had some difficulty with
+ // it timing itself out, so we'll be safe and kick it now.
+ clearTimeout(timer);
+ timer = setTimeout('timeout()', 30);
+ }
+ }
+
+
+ /// WARNING: Could be dangerous to call while an animation is running ...
+ this.clearHistory = function()
+ {
+ this.undoStack = [];
+ this.undoAnimationStepIndices = null;
+ this.previousAnimationSteps = [];
+ this.undoAnimationStepIndicesStack = [];
+ this.AnimationSteps = null;
+ this.fireEvent("AnimationUndoUnavailable","NoData");
+ clearTimeout(timer);
+ this.animatedObjects.update();
+ this.animatedObjects.draw();
+
+ }
+
+ this.skipBack = function()
+ {
+ var keepUndoing = this.undoAnimationStepIndices != null && this. undoAnimationStepIndices.length != 0;
+ if (keepUndoing)
+ {
+ var i;
+ for (i = 0; this.currentBlock != null && i < this.currentBlock.length; i++)
+ {
+ var objectID = this.currentBlock[i].objectID;
+ this.animatedObjects.setNodePosition(objectID,
+ this.currentBlock[i].toX,
+ this.currentBlock[i].toY);
+ }
+ if (this.doingUndo)
+ {
+ this.finishUndoBlock(this.undoStack.pop())
+ }
+ while (keepUndoing)
+ {
+ this.undoLastBlock();
+ for (i = 0; i < this.currentBlock.length; i++)
+ {
+ objectID = this.currentBlock[i].objectID;
+ this.animatedObjects.setNodePosition(objectID,
+ this.currentBlock[i].toX,
+ this.currentBlock[i].toY);
+ }
+ keepUndoing = this.finishUndoBlock(this.undoStack.pop());
+
+ }
+ clearTimeout(timer);
+ this.animatedObjects.update();
+ this.animatedObjects.draw();
+ if (this.undoStack == null || this.undoStack.length == 0)
+ {
+ this.fireEvent("AnimationUndoUnavailable","NoData");
+ }
+
+ }
+ }
+
+ this.resetAll = function()
+ {
+ this.clearHistory();
+ this.animatedObjects.clearAllObjects();
+ this.animatedObjects.draw();
+ clearTimeout(timer);
+ }
+
+ this.skipForward = function()
+ {
+ if (this.currentlyAnimating)
+ {
+ this.animatedObjects.runFast = true;
+ while (this.AnimationSteps != null && this.currentAnimation < this.AnimationSteps.length)
+ {
+ var i;
+ for (i = 0; this.currentBlock != null && i < this.currentBlock.length; i++)
+ {
+ var objectID = this.currentBlock[i].objectID;
+ this.animatedObjects.setNodePosition(objectID,
+ this.currentBlock[i].toX,
+ this.currentBlock[i].toY);
+ }
+ if (this.doingUndo)
+ {
+ this.finishUndoBlock(this.undoStack.pop())
+ }
+ this.startNextBlock();
+ for (i= 0; i < this.currentBlock.length; i++)
+ {
+ var objectID = this.currentBlock[i].objectID;
+ this.animatedObjects.setNodePosition(objectID,
+ this.currentBlock[i].toX,
+ this.currentBlock[i].toY);
+ }
+
+ }
+ this.animatedObjects.update();
+ this.currentlyAnimating = false;
+ this.awaitingStep = false;
+ this.doingUndo = false;
+
+ this.animatedObjects.runFast = false;
+ this.fireEvent("AnimationEnded","NoData");
+ clearTimeout(timer);
+ this.animatedObjects.update();
+ this.animatedObjects.draw();
+ }
+ }
+
+
+ this.finishUndoBlock = function(undoBlock)
+ {
+ for (var i = undoBlock.length - 1; i >= 0; i--)
+ {
+ undoBlock[i].undoInitialStep(this.animatedObjects);
+
+ }
+ this.doingUndo = false;
+
+ // If we are at the final end of the animation ...
+ if (this.undoAnimationStepIndices.length == 0)
+ {
+ this.awaitingStep = false;
+ this.currentlyAnimating = false;
+ this.undoAnimationStepIndices = this.undoAnimationStepIndicesStack.pop();
+ this.AnimationSteps = this.previousAnimationSteps.pop();
+ this.fireEvent("AnimationEnded","NoData");
+ this.fireEvent("AnimationUndo","NoData");
+ this.currentBlock = [];
+ if (this.undoStack == null || this.undoStack.length == 0)
+ {
+ this.currentlyAnimating = false;
+ this.awaitingStep = false;
+ this.fireEvent("AnimationUndoUnavailable","NoData");
+ }
+
+ clearTimeout(timer);
+ this.animatedObjects.update();
+ this.animatedObjects.draw();
+
+
+ return false;
+ }
+ return true;
+ }
+
+
+ this.undoLastBlock = function()
+ {
+
+ if (this.undoAnimationStepIndices.length == 0)
+ {
+
+ // Nothing on the undo stack. Return
+ return;
+
+ }
+ if (this.undoAnimationStepIndices.length > 0)
+ {
+ this.doingUndo = true;
+ var anyAnimations = false;
+ this.currentAnimation = this.undoAnimationStepIndices.pop();
+ this.currentBlock = [];
+ var undo = this.undoStack[this.undoStack.length - 1];
+ var i;
+ for (i = undo.length - 1; i >= 0; i--)
+ {
+ var animateNext = undo[i].addUndoAnimation(this.currentBlock);
+ anyAnimations = anyAnimations || animateNext;
+
+ }
+ this.currFrame = 0;
+
+ // Hack: If there are not any animations, and we are currently paused,
+ // then set the current frame to the end of the animation, so that we will
+ // advance immediagely upon the next step button. If we are not paused, then
+ // animate as normal.
+ if (!anyAnimations && this.animationPaused )
+ {
+ this.currFrame = this.animationBlockLength;
+ }
+ this.currentlyAnimating = true;
+ }
+
+ }
+ this.setLayer = function(shown, layers)
+ {
+ this.animatedObjects.setLayer(shown, layers)
+ // Drop in an extra draw call here, just in case we are not
+ // in the middle of an update loop when this changes
+ this.animatedObjects.draw();
+ }
+
+
+ this.setAllLayers = function(layers)
+ {
+ this.animatedObjects.setAllLayers(layers);
+ // Drop in an extra draw call here, just in case we are not
+ // in the middle of an update loop when this changes
+ this.animatedObjects.draw();
+ }
+
+
+ this.update = function()
+ {
+
+ if (this.currentlyAnimating)
+ {
+ this.currFrame = this.currFrame + 1;
+ var i;
+ for (i = 0; i < this.currentBlock.length; i++)
+ {
+ if (this.currFrame == this.animationBlockLength || (this.currFrame == 1 && this.animationBlockLength == 0))
+ {
+ this.animatedObjects.setNodePosition(this.currentBlock[i].objectID,
+ this.currentBlock[i].toX,
+ this.currentBlock[i].toY);
+ }
+ else if (this.currFrame < this.animationBlockLength)
+ {
+ var objectID = this.currentBlock[i].objectID;
+ var percent = 1 / (this.animationBlockLength - this.currFrame);
+ var oldX = this.animatedObjects.getNodeX(objectID);
+ var oldY = this.animatedObjects.getNodeY(objectID);
+ var targetX = this.currentBlock[i].toX;
+ var targety = this.currentBlock[i].toY;
+ var newX = this.lerp(this.animatedObjects.getNodeX(objectID), this.currentBlock[i].toX, percent);
+ var newY = this.lerp(this.animatedObjects.getNodeY(objectID), this.currentBlock[i].toY, percent);
+ this.animatedObjects.setNodePosition(objectID, newX, newY);
+ }
+ }
+ if (this.currFrame >= this.animationBlockLength)
+ {
+ if (this.doingUndo)
+ {
+ if (this.finishUndoBlock(this.undoStack.pop()))
+ {
+ this.awaitingStep = true;
+ this.fireEvent("AnimationWaiting","NoData");
+ }
+
+ }
+ else
+ {
+ if (this.animationPaused && (this.currentAnimation < this.AnimationSteps.length))
+ {
+ this.awaitingStep = true;
+ this.fireEvent("AnimationWaiting","NoData");
+ this.currentBlock = [];
+ }
+ else
+ {
+ this.startNextBlock();
+ }
+ }
+ }
+ this.animatedObjects.update();
+
+ }
+
+
+ }
+
+}
+
+AnimationManager.prototype = new EventListener();
+AnimationManager.prototype.constructor = AnimationManager;
+
+
+function SingleAnimation(id, fromX, fromY, toX, toY)
+{
+ this.objectID = id;
+ this.fromX = fromX;
+ this.fromY = fromY;
+ this.toX = toX;
+ this.toY = toY;
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/CustomEvents.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/CustomEvents.js
new file mode 100644
index 0000000..c276f42
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/CustomEvents.js
@@ -0,0 +1,176 @@
+// 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 ``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 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
+
+
+Function.prototype.bind = function() {
+ var _function = this;
+
+ var args = Array.prototype.slice.call(arguments);
+ var scope = args.shift()
+ return function() {
+ for (var i = 0; i < arguments.length; i++)
+ {
+ args.push(arguments[i]);
+ }
+ return _function.apply(scope, args);
+ }
+}
+
+function EventListener()
+{
+ this.events = [];
+}
+
+
+EventListener.prototype.removeListener = function(kind, scope, func)
+{
+ if (this.events[kind] == undefined)
+ {
+ return;
+ }
+ var scopeFunctions = null;
+ var i;
+ for (i = 0; i < this.events[kind].length; i++)
+ {
+ if (this.events[kind][i].scope == scope)
+ {
+ scopeFunctions = this.events[kind][i];
+ break;
+ }
+ }
+ if (scopeFunctions == null)
+ {
+ return;
+ }
+ for (i = 0; i < scopeFunctions.functions.length; i++)
+ {
+ if (scopeFunctions.functions[i] == func)
+ {
+ scopeFunctions.functions.splice(i,1);
+ return;
+ }
+ }
+}
+
+
+EventListener.prototype.addListener = function(kind, scope, func)
+{
+ if (this.events[kind] === undefined)
+ {
+ this.events[kind] = [];
+ }
+ var i;
+ var scopeFunctions = null;
+ for (i = 0; i < this.events[kind].length; i++)
+ {
+ if (this.events[kind][i].scope == scope)
+ {
+ scopeFunctions = this.events[kind][i];
+ break;
+ }
+ }
+ if (scopeFunctions === null)
+ {
+ this.events[kind].push({scope:scope, functions:[] });
+ scopeFunctions = this.events[kind][this.events[kind].length - 1];
+ }
+ for (i = 0; i < scopeFunctions.functions.length; i++)
+ {
+ if (scopeFunctions.functions[i] == func)
+ {
+ return;
+ }
+ }
+ scopeFunctions.functions.push(func);
+}
+
+EventListener.prototype.fireEvent = function(kind, event)
+{
+ // TODO: Should add a deep clone here ...
+ if (this.events[kind] !== undefined)
+ {
+ for (var i = 0; i < this.events[kind].length; i++)
+ {
+ var objects = this.events[kind][i];
+ var functs = objects.functions;
+ var scope = objects.scope
+ for (var j = 0; j ``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 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
+
+// "Class" animatedCircle
+
+
+var HighlightCircle = function(objectID, color, radius)
+{
+ this.objectID = objectID;
+ this.radius = radius;
+ this.thickness = 4;
+ this.foregroundColor = color;
+ this.x = 0;
+ this.y = 0;
+ this.alpha = 1;
+}
+
+HighlightCircle.prototype = new AnimatedObject();
+HighlightCircle.prototype.constructor = HighlightCircle;
+
+
+HighlightCircle.prototype.draw = function(ctx)
+{
+ ctx.globalAlpha = this.alpha;
+ ctx.strokeStyle = this.foregroundColor;
+ ctx.lineWidth = this.thickness;
+ ctx.beginPath();
+ ctx.arc(this.x,this.y,this.radius,0,Math.PI*2, true);
+ ctx.closePath();
+ ctx.stroke();
+}
+
+
+HighlightCircle.prototype.createUndoDelete = function()
+{
+ return new UndoDeleteHighlightCircle(this.objectID, this.x, this.y, this.foregroundColor, this.radius, this.layer, this.alpha);
+}
+
+
+function UndoDeleteHighlightCircle(objectID, x, y, circleColor, r, layer, alpha)
+{
+ this.objectID = objectID;
+ this.x = x;
+ this.y = y;
+ this.color = circleColor;
+ this.r = r;
+ this.layer = layer;
+ this.alpha = alpha
+}
+
+UndoDeleteHighlightCircle.prototype = new UndoBlock();
+UndoDeleteHighlightCircle.prototype.constructor = UndoDeleteHighlightCircle;
+
+UndoDeleteHighlightCircle.prototype.undoInitialStep = function(world)
+{
+ world.addHighlightCircleObject(this.objectID, this.color, this.r);
+ world.setLayer(this.objectID, this.layer)
+ world.setNodePosition(this.objectID, this.x, this.y);
+ world.setAlpha(this.objectID, this.alpha)
+}
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/Line.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/Line.js
new file mode 100644
index 0000000..2637b47
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/Line.js
@@ -0,0 +1,229 @@
+// 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 ``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 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
+
+
+// This class is somewhat poorly named -- it handles links between vertices in graphs,
+// pointers in linked lists, and so on.
+
+
+var LINE_maxHeightDiff = 5;
+var LINE_minHeightDiff = 3;
+var LINE_range= LINE_maxHeightDiff - LINE_minHeightDiff + 1;
+var LINE_highlightDiff = 3;
+
+
+function Line(n1, n2, color, cv, d, weight, anchorIndex)
+{
+ this.arrowHeight = 8;
+ this.arrowWidth = 4;
+
+ this.Node1 = n1;
+ this.Node2 = n2;
+ this.Dirty = false;
+ this.directed = d;
+ this.edgeColor = color;
+ this.edgeLabel = weight;
+ this.highlighted = false;
+ this.addedToScene = true;
+ this.anchorPoint = anchorIndex;
+ this.highlightDiff = 0;
+ this.curve = cv;
+
+ this.alpha = 1.0;
+ this.color = function color()
+ {
+ return this.edgeColor;
+ }
+
+ this.setColor = function(newColor)
+ {
+ this.edgeColor = newColor;
+ Dirty = true;
+ }
+
+ this.setHighlight = function(highlightVal)
+ {
+ this.highlighted = highlightVal;
+ }
+
+ this.pulseHighlight = function(frameNum)
+ {
+ if (this.highlighted)
+ {
+ var frameMod = frameNum / 14.0;
+ var delta = Math.abs((frameMod) % (2 * LINE_range - 2) - LINE_range + 1)
+ this.highlightDiff = delta + LINE_minHeightDiff;
+ Dirty = true;
+ }
+ }
+
+
+ this.hasNode = function(n)
+ {
+ return ((this.Node1 == n) || (this.Node2 == n));
+ }
+
+
+ this.createUndoDisconnect = function()
+ {
+ return new UndoConnect(this.Node1.objectID, this.Node2.objectID, true, this.edgeColor, this.directed, this.curve, this.edgeLabel, this.anchorPoint);
+ }
+
+
+ this.sign = function(n)
+ {
+ if (n > 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+
+ this.drawArrow = function(pensize, color, context)
+ {
+ context.strokeStyle = color;
+ context.fillStyle = color;
+ context.lineWidth = pensize;
+ // var fromPos = this.Node1.getTailPointerAttachPos(this.Node2.x, this.Node2.y, this.anchorPoint);
+ // var toPos = this.Node2.getHeadPointerAttachPos(this.Node1.x, this.Node1.y);
+
+ var fromPos = this.Node1.getTailPointerAttachPos(this.Node2.x, this.Node2.y, this.anchorPoint);
+ var toPos = this.Node2.getHeadPointerAttachPos(this.Node1.x, this.Node1.y);
+
+ var deltaX = toPos[0] - fromPos[0];
+ var deltaY = toPos[1] - fromPos[1];
+ var midX = (deltaX) / 2.0 + fromPos[0];
+ var midY = (deltaY) / 2.0 + fromPos[1];
+ var controlX = midX - deltaY * this.curve;
+
+ var controlY = midY + deltaX * this.curve;
+
+ context.beginPath();
+ context.moveTo(fromPos[0], fromPos[1]);
+ context.quadraticCurveTo(controlX, controlY, toPos[0], toPos[1]);
+ context.stroke();
+ //context.closePath();
+
+ // Position of the edge label: First, we will place it right along the
+ // middle of the curve (or the middle of the line, for curve == 0)
+ var labelPosX = 0.25* fromPos[0] + 0.5*controlX + 0.25*toPos[0];
+ var labelPosY = 0.25* fromPos[1] + 0.5*controlY + 0.25*toPos[1];
+
+ // Next, we push the edge position label out just a little in the direction of
+ // the curve, so that the label doesn't intersect the cuve (as long as the label
+ // is only a few characters, that is)
+ var midLen = Math.sqrt(deltaY*deltaY + deltaX*deltaX);
+ if (midLen != 0)
+ {
+ labelPosX += (- deltaY * this.sign(this.curve)) / midLen * 10
+ labelPosY += ( deltaX * this.sign(this.curve)) / midLen * 10
+ }
+
+
+
+ context.textAlign = 'center';
+ context.font = '16px Consolas';
+ context.textBaseline = 'middle';
+ context.fillText(this.edgeLabel, labelPosX, labelPosY);
+
+ if (this.directed)
+ {
+ var xVec = controlX - toPos[0];
+ var yVec = controlY - toPos[1];
+ var len = Math.sqrt(xVec * xVec + yVec*yVec);
+
+ if (len > 0)
+ {
+ xVec = xVec / len
+ yVec = yVec / len;
+
+ context.beginPath();
+ context.moveTo(toPos[0], toPos[1]);
+ context.lineTo(toPos[0] + xVec*this.arrowHeight - yVec*this.arrowWidth, toPos[1] + yVec*this.arrowHeight + xVec*this.arrowWidth);
+ context.lineTo(toPos[0] + xVec*this.arrowHeight + yVec*this.arrowWidth, toPos[1] + yVec*this.arrowHeight - xVec*this.arrowWidth);
+ context.lineTo(toPos[0], toPos[1]);
+ context.closePath();
+ context.stroke();
+ context.fill();
+ }
+
+ }
+
+ }
+
+
+ this.draw = function(ctx)
+ {
+ if (!this.addedToScene)
+ {
+ return;
+ }
+ ctx.globalAlpha = this.alpha;
+
+ if (this.highlighted)
+ this.drawArrow(this.highlightDiff, "#FF0000", ctx);
+ this.drawArrow(1, this.edgeColor, ctx);
+ }
+
+
+}
+
+
+
+function UndoConnect(from, to, createConnection, edgeColor, isDirected, cv, lab, anch)
+{
+ this.fromID = from;
+ this.toID = to;
+ this.connect = createConnection;
+ this.color = edgeColor;
+ this.directed = isDirected;
+ this.curve = cv;
+ this.edgeLabel = lab;
+ this.anchorPoint = anch;
+}
+
+
+UndoConnect.prototype.undoInitialStep = function(world)
+{
+ if (this.connect)
+ {
+ world.connectEdge(this.fromID, this.toID, this.color, this.curve, this.directed, this.edgeLabel,this.anchorPoint);
+ }
+ else
+ {
+ world.disconnect(this.fromID,this.toID);
+ }
+}
+
+
+UndoConnect.prototype.addUndoAnimation = function(animationList)
+{
+ return false;
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/ObjectManager.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/ObjectManager.js
new file mode 100644
index 0000000..06c71b5
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/ObjectManager.js
@@ -0,0 +1,858 @@
+// 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 ``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 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
+
+
+// Object Manager
+//
+// Manage all of our animated objects. Control any animated object should occur through
+// this interface (not language enforced, because enforcing such things in Javascript is
+// problematic.)
+//
+// This class is only accessed through:
+//
+// AnimationMain
+// Undo objects (which are themselves controlled by AnimationMain
+
+
+// TODO:
+// 1. Add proper throws for all error conditions (perhaps guarded by
+// an assert-like structure that can be turned off for production?)
+// 2. Refactor this code so that it uses the same object syntax (with
+// prototypes) as te rest of the code. (low priority)
+function ObjectManager()
+{
+ this.Nodes = [];
+ this.Edges = [];
+ this.BackEdges = [];
+ this.activeLayers = [];
+ this.activeLayers[0] = true;
+ this.ctx = document.getElementById('canvas').getContext('2d');
+ this.framenum = 0;
+ this.width = 0;
+ this.height = 0;
+ this.statusReport = new AnimatedLabel(-1, "XXX", false, 30);
+ this.statusReport.x = 30;
+
+ this.draw = function()
+ {
+ this.framenum++;
+ if (this.framenum > 1000)
+ this.framenum = 0;
+
+ this.ctx.clearRect(0,0,this.width,this.height); // clear canvas
+ this.statusReport.y = this.height - 15;
+
+ var i;
+ var j;
+ for (i = 0; i < this.Nodes.length; i++)
+ {
+ if (this.Nodes[i] != null && !this.Nodes[i].highlighted && this.Nodes[i].addedToScene && !this.Nodes[i].alwaysOnTop)
+ {
+ this.Nodes[i].draw(this.ctx);
+ }
+ }
+ for (i = 0; i < this.Nodes.length; i++)
+ {
+ if (this.Nodes[i] != null && (this.Nodes[i].highlighted && !this.Nodes[i].alwaysOnTop) && this.Nodes[i].addedToScene)
+ {
+ this.Nodes[i].pulseHighlight(this.framenum);
+ this.Nodes[i].draw(this.ctx);
+ }
+ }
+
+ for (i = 0; i < this.Nodes.length; i++)
+ {
+ if (this.Nodes[i] != null && this.Nodes[i].alwaysOnTop && this.Nodes[i].addedToScene)
+ {
+ this.Nodes[i].pulseHighlight(this.framenum);
+ this.Nodes[i].draw(this.ctx);
+ }
+ }
+
+
+ for (i = 0; i < this.Edges.length; i++)
+ {
+ if (this.Edges[i] != null)
+ {
+ for (j = 0; j < this.Edges[i].length; j++)
+ {
+ if (this.Edges[i][j].addedToScene)
+ {
+ this.Edges[i][j].pulseHighlight(this.framenum);
+ this.Edges[i][j].draw(this.ctx);
+ }
+
+ }
+
+ }
+ }
+ this.statusReport.draw(this.ctx);
+
+ }
+
+ this.update = function ()
+ {
+
+
+ }
+
+
+ this.setLayers = function(shown,layers)
+ {
+ for (var i = 0; i < layers.length; i++)
+ {
+ this.activeLayers[layers[i]] = shown;
+ }
+ this.resetLayers();
+
+ }
+
+
+ this.addHighlightCircleObject = function(objectID, objectColor, radius)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ throw "addHighlightCircleObject:Object with same ID (" + String(objectID) + ") already Exists!"
+ }
+ var newNode = new HighlightCircle(objectID, objectColor, radius)
+ this.Nodes[objectID] = newNode;
+ }
+
+ this.setEdgeAlpha = function(fromID, toID, alphaVal)
+ {
+ var oldAlpha = 1.0;
+ if (this.Edges[fromID] != null &&
+ this.Edges[fromID] != undefined)
+ {
+ var len = this.Edges[fromID].length;
+ for (var i = len - 1; i >= 0; i--)
+ {
+ if (this.Edges[fromID][i] != null &&
+ this.Edges[fromID][i] != undefined &&
+ this.Edges[fromID][i].Node2 == this.Nodes[toID])
+ {
+ oldAlpha = this.Edges[fromID][i].alpha
+ this.Edges[fromID][i].alpha = alphaVal;
+ }
+ }
+ }
+ return oldAlpha;
+
+ }
+
+ this.setAlpha = function(nodeID, alphaVal)
+ {
+ if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
+ {
+ this.Nodes[nodeID].setAlpha(alphaVal);
+ }
+ }
+
+ this.getAlpha = function(nodeID)
+ {
+ if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
+ {
+ return this.Nodes[nodeID].getAlpha();
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ this.getTextColor = function(nodeID, index)
+ {
+ if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
+ {
+ return this.Nodes[nodeID].getTextColor(index);
+ }
+ else
+ {
+ return "#000000";
+ }
+
+ }
+
+ this.setTextColor = function(nodeID, color, index)
+ {
+ if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
+ {
+ this.Nodes[nodeID].setTextColor(color, index);
+ }
+ }
+
+
+ this.setHighlightIndex = function(nodeID, index)
+ {
+ if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
+ {
+ this.Nodes[nodeID].setHighlightIndex(index);
+ }
+ }
+
+
+
+
+
+ this.setAllLayers = function(layers)
+ {
+ this.activeLayers = [];
+ for(var i = 0; i < layers.length; i++)
+ {
+ this.activeLayers[layers[i]] = true;
+ }
+ this.resetLayers();
+ }
+
+ this.resetLayers = function()
+ {
+ var i
+ for (i = 0; i = 0; i--)
+ {
+ if (this.Edges[i] != null && this.Edges[i] != undefined)
+ {
+ for (var j = 0; j < this.Edges[i].length; j++)
+ {
+ if (this.Edges[i][j] != null && this.Edges[i][j] != undefined)
+ {
+ this.Edges[i][j].addedToScene =
+ this.activeLayers[this.Edges[i][j].Node1.layer] == true &&
+ this.activeLayers[this.Edges[i][j].Node2.layer] == true;
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+
+ this.setLayer = function(objectID, layer)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ this.Nodes[objectID].layer = layer;
+ if (this.activeLayers[layer])
+ {
+ this.Nodes[objectID].addedToScene = true;
+ }
+ else
+ {
+ this.Nodes[objectID].addedToScene = false;
+ }
+ if (this.Edges[objectID] != null && this.Edges[objectID] != undefined)
+ {
+ for (var i = 0; i < this.Edges[objectID].length; i++)
+ {
+ var nextEdge = this.Edges[objectID][i];
+ if (nextEdge != null && nextEdge != undefined)
+ {
+ nextEdge.addedToScene = ((nextEdge.Node1.addedToScene) &&
+ (nextEdge.Node2.addedToScene));
+
+ }
+ }
+ }
+ if (this.BackEdges[objectID] != null && this.BackEdges[objectID] != undefined)
+ {
+ for (var i = 0; i < this.BackEdges[objectID].length; i++)
+ {
+ var nextEdge = this.BackEdges[objectID][i];
+ if (nextEdge != null && nextEdge != undefined)
+ {
+ nextEdge.addedToScene = ((nextEdge.Node1.addedToScene) &&
+ (nextEdge.Node2.addedToScene));
+
+ }
+ }
+ }
+ }
+ }
+
+ this.clearAllObjects = function()
+ {
+ this.Nodes = [];
+ this.Edges = [];
+ this.BackEdges = [];
+ }
+
+
+ this.setForegroundColor = function(objectID, color)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ this.Nodes[objectID].setForegroundColor(color);
+
+ }
+ }
+
+ this.setBackgroundColor = function(objectID, color)
+ {
+ if (this.Nodes[objectID] != null)
+ {
+ this.Nodes[objectID].setBackgroundColor(color);
+
+ }
+ }
+
+ this.setHighlight = function(nodeID, val)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return;
+ }
+ this.Nodes[nodeID].setHighlight(val);
+ }
+
+
+ this.getHighlight = function(nodeID)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return false;
+ }
+ return this.Nodes[nodeID].getHighlight();
+ }
+
+
+ this.getHighlightIndex = function(nodeID)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return false;
+ }
+ return this.Nodes[nodeID].getHighlightIndex();
+ }
+
+ this.setWidth = function(nodeID, val)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return;
+ }
+ this.Nodes[nodeID].setWidth(val);
+ }
+
+ this.setHeight = function(nodeID, val)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return;
+ }
+ this.Nodes[nodeID].setHeight(val);
+ }
+
+
+ this.getHeight = function(nodeID)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return -1;
+ }
+ return this.Nodes[nodeID].getHeight();
+ }
+
+ this.getWidth = function(nodeID)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return -1;
+ }
+ return this.Nodes[nodeID].getWidth();
+ }
+
+ this.backgroundColor = function(objectID)
+ {
+ if (this.Nodes[objectID] != null)
+ {
+ return this.Nodes[objectID].backgroundColor;
+ }
+ else
+ {
+ return '#000000';
+ }
+ }
+
+ this.foregroundColor = function(objectID)
+ {
+ if (this.Nodes[objectID] != null)
+ {
+ return this.Nodes[objectID].foregroundColor;
+ }
+ else
+ {
+ return '#000000';
+ }
+ }
+
+
+ this.disconnect = function(objectIDfrom,objectIDto)
+ {
+ var undo = null;
+ var i;
+ if (this.Edges[objectIDfrom] != null)
+ {
+ var len = this.Edges[objectIDfrom].length;
+ for (i = len - 1; i >= 0; i--)
+ {
+ if (this.Edges[objectIDfrom][i] != null && this.Edges[objectIDfrom][i].Node2 == this.Nodes[objectIDto])
+ {
+ var deleted = this.Edges[objectIDfrom][i];
+ undo = deleted.createUndoDisconnect();
+ this.Edges[objectIDfrom][i] = this.Edges[objectIDfrom][len - 1];
+ len -= 1;
+ this.Edges[objectIDfrom].pop();
+ }
+ }
+ }
+ if (this.BackEdges[objectIDto] != null)
+ {
+ len = this.BackEdges[objectIDto].length;
+ for (i = len - 1; i >= 0; i--)
+ {
+ if (this.BackEdges[objectIDto][i] != null && this.BackEdges[objectIDto][i].Node1 == this.Nodes[objectIDfrom])
+ {
+ deleted = this.BackEdges[objectIDto][i];
+ // Note: Don't need to remove this child, did it above on the regular edge
+ this.BackEdges[objectIDto][i] = this.BackEdges[objectIDto][len - 1];
+ len -= 1;
+ this.BackEdges[objectIDto].pop();
+ }
+ }
+ }
+ return undo;
+ }
+
+ this.deleteIncident = function(objectID)
+ {
+ var undoStack = [];
+
+ if (this.Edges[objectID] != null)
+ {
+ var len = this.Edges[objectID].length;
+ for (var i = len - 1; i >= 0; i--)
+ {
+ var deleted = this.Edges[objectID][i];
+ var node2ID = deleted.Node2.identifier();
+ undoStack.push(deleted.createUndoDisconnect());
+
+ var len2 = this.BackEdges[node2ID].length;
+ for (var j = len2 - 1; j >=0; j--)
+ {
+ if (this.BackEdges[node2ID][j] == deleted)
+ {
+ this.BackEdges[node2ID][j] = this.BackEdges[node2ID][len2 - 1];
+ len2 -= 1;
+ this.BackEdges[node2ID].pop();
+ }
+ }
+ }
+ this.Edges[objectID] = null;
+ }
+ if (this.BackEdges[objectID] != null)
+ {
+ len = this.BackEdges[objectID].length;
+ for (i = len - 1; i >= 0; i--)
+ {
+ deleted = this.BackEdges[objectID][i];
+ var node1ID = deleted.Node1.identifier();
+ undoStack.push(deleted.createUndoDisconnect());
+
+ len2 = this.Edges[node1ID].length;
+ for (j = len2 - 1; j >=0; j--)
+ {
+ if (this.Edges[node1ID][j] == deleted)
+ {
+ this.Edges[node1ID][j] = this.Edges[node1ID][len2 - 1];
+ len2 -= 1;
+ this.Edges[node1ID].pop();
+ }
+ }
+ }
+ this.BackEdges[objectID] = null;
+ }
+ return undoStack;
+ }
+
+
+ this.removeObject = function(ObjectID)
+ {
+ var OldObject = this.Nodes[ObjectID];
+ if (ObjectID == this.Nodes.length - 1)
+ {
+ this.Nodes.pop();
+ }
+ else
+ {
+ this.Nodes[ObjectID] = null;
+ }
+ }
+
+ this.getObject = function(objectID)
+ {
+ if (this.Nodes[objectID] == null || this.Nodes[objectID] == undefined)
+ {
+ throw "getObject:Object with ID (" + String(objectID) + ") does not exist"
+ }
+ return this.Nodes[objectID];
+
+ }
+
+
+ this.addCircleObject = function (objectID, objectLabel)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ throw "addCircleObject:Object with same ID (" + String(objectID) + ") already Exists!"
+ }
+ var newNode = new AnimatedCircle(objectID, objectLabel);
+ this.Nodes[objectID] = newNode;
+ }
+
+ this.getNodeX = function(nodeID)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ throw "getting x position of an object that does not exit";
+ }
+ return this.Nodes[nodeID].x;
+ }
+
+ this.getTextWidth = function(text)
+ {
+ // TODO: Need to make fonts more flexible, and less hardwired.
+ this.ctx.font = '16px Consolas';
+ if (text==undefined)
+ {
+ w = 3;
+ }
+ var strList = text.split("\n");
+ var width = 0;
+ if (strList.length == 1)
+ {
+ width = this.ctx.measureText(text).width;
+ }
+ else
+ {
+ for (var i = 0; i < strList.length; i++)
+ {
+ width = Math.max(width, this.ctx.measureText(strList[i]).width);
+ }
+ }
+
+ return width;
+ }
+
+ this.setText = function(nodeID, text, index)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ return;
+ throw "setting text of an object that does not exit";
+ }
+ this.Nodes[nodeID].setText(text, index, this.getTextWidth(text));
+
+ }
+
+ this.getText = function(nodeID, index)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ throw "getting text of an object that does not exit";
+ }
+ return this.Nodes[nodeID].getText(index);
+
+ }
+
+ this.getNodeY = function(nodeID)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ throw "getting y position of an object that does not exit";
+ }
+ return this.Nodes[nodeID].y;
+ }
+
+
+ this.connectEdge = function(objectIDfrom, objectIDto, color, curve, directed, lab, connectionPoint)
+ {
+ var fromObj = this.Nodes[objectIDfrom];
+ var toObj = this.Nodes[objectIDto];
+ if (fromObj == null || toObj == null)
+ {
+ throw "Tried to connect two nodes, one didn't exist!";
+ }
+ var l = new Line(fromObj,toObj, color, curve, directed, lab, connectionPoint);
+ if (this.Edges[objectIDfrom] == null || this.Edges[objectIDfrom] == undefined)
+ {
+ this.Edges[objectIDfrom] = [];
+ }
+ if (this.BackEdges[objectIDto] == null || this.BackEdges[objectIDto] == undefined)
+ {
+ this.BackEdges[objectIDto] = [];
+ }
+ l.addedToScene = fromObj.addedToScene && toObj.addedToScene;
+ this.Edges[objectIDfrom].push(l);
+ this.BackEdges[objectIDto].push(l);
+
+ }
+
+
+ this.setNull = function(objectID, nullVal)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ this.Nodes[objectID].setNull(nullVal);
+
+ }
+ }
+
+ this.getNull = function(objectID)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ return this.Nodes[objectID].getNull();
+ }
+ return false; // TODO: Error here?
+ }
+
+
+
+ this.setEdgeColor = function(fromID, toID, color) // returns old color
+ {
+ var oldColor ="#000000";
+ if (this.Edges[fromID] != null &&
+ this.Edges[fromID] != undefined)
+ {
+ var len = this.Edges[fromID].length;
+ for (var i = len - 1; i >= 0; i--)
+ {
+ if (this.Edges[fromID][i] != null &&
+ this.Edges[fromID][i] != undefined &&
+ this.Edges[fromID][i].Node2 == this.Nodes[toID])
+ {
+ oldColor = this.Edges[fromID][i].color();
+ this.Edges[fromID][i].setColor(color);
+ }
+ }
+ }
+ return oldColor;
+ }
+
+ this.alignTop = function(id1, id2)
+ {
+ if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
+ this.Nodes[id2] == null || this.Nodes[id2] == undefined)
+ {
+ throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);
+ }
+ this.Nodes[id1].alignTop(this.Nodes[id2]);
+ }
+
+ this.alignLeft = function(id1, id2)
+ {
+ if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
+ this.Nodes[id2] == null || this.Nodes[id2] == undefined)
+ {
+ throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);
+ }
+ this.Nodes[id1].alignLeft(this.Nodes[id2]);
+ }
+
+ this.alignRight = function(id1, id2)
+ {
+ if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
+ this.Nodes[id2] == null || this.Nodes[id2] == undefined)
+ {
+ throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);
+ }
+ this.Nodes[id1].alignRight(this.Nodes[id2]);
+ }
+
+
+
+ this.getAlignRightPos = function(id1, id2)
+ {
+ if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
+ this.Nodes[id2] == null || this.Nodes[id2] == undefined)
+ {
+ throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);
+ }
+ return this.Nodes[id1].getAlignRightPos(this.Nodes[id2]);
+ }
+
+ this.getAlignLeftPos = function(id1, id2)
+ {
+ if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
+ this.Nodes[id2] == null || this.Nodes[id2] == undefined)
+ {
+ throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);
+ }
+ return this.Nodes[id1].getAlignLeftPos(this.Nodes[id2]);
+ }
+
+
+
+ this.alignBottom = function(id1, id2)
+ {
+ if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
+ this.Nodes[id2] == null || this.Nodes[id2] == undefined)
+ {
+ throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);
+ }
+ this.Nodes[id1].alignBottom(this.Nodes[id2]);
+ }
+
+
+ this.setEdgeHighlight = function(fromID, toID, val) // returns old color
+ {
+ var oldHighlight = false;
+ if (this.Edges[fromID] != null &&
+ this.Edges[fromID] != undefined)
+ {
+ var len = this.Edges[fromID].length;
+ for (var i = len - 1; i >= 0; i--)
+ {
+ if (this.Edges[fromID][i] != null &&
+ this.Edges[fromID][i] != undefined &&
+ this.Edges[fromID][i].Node2 == this.Nodes[toID])
+ {
+ oldHighlight = this.Edges[fromID][i].highlighted;
+ this.Edges[fromID][i].setHighlight(val);
+ }
+ }
+ }
+ return oldHighlight;
+ }
+ this.addLabelObject = function(objectID, objectLabel, centering)
+ {
+ if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
+ {
+ throw new Error("addLabelObject: Object Already Exists!");
+ }
+
+ var newLabel = new AnimatedLabel(objectID, objectLabel, centering, this.getTextWidth(objectLabel));
+ this.Nodes[objectID] = newLabel;
+ }
+
+
+ this.addLinkedListObject = function(objectID, nodeLabel, width, height, linkPer, verticalOrientation, linkPosEnd, numLabels, backgroundColor, foregroundColor)
+ {
+ if (this.Nodes[objectID] != null)
+ {
+ throw new Error("addLinkedListObject:Object with same ID already Exists!");
+ return;
+ }
+ var newNode = new AnimatedLinkedList(objectID, nodeLabel, width, height, linkPer, verticalOrientation, linkPosEnd, numLabels, backgroundColor, foregroundColor);
+ this.Nodes[objectID] = newNode;
+ }
+
+
+ this.getNumElements = function(objectID)
+ {
+ return this.Nodes[objectID].getNumElements();
+ }
+
+
+ this.setNumElements = function(objectID, numElems)
+ {
+ this.Nodes[objectID].setNumElements(numElems);
+ }
+ this.addBTreeNode = function(objectID, widthPerElem, height, numElems, backgroundColor, foregroundColor)
+ {
+ backgroundColor = (backgroundColor == undefined) ? "#FFFFFF" : backgroundColor;
+ foregroundColor = (foregroundColor == undefined) ? "#FFFFFF" : foregroundColor;
+
+ if (this.Nodes[objectID] != null && Nodes[objectID] != undefined)
+ {
+ throw "addBTreeNode:Object with same ID already Exists!";
+ }
+
+ var newNode = new AnimatedBTreeNode(objectID,widthPerElem, height, numElems, backgroundColor, foregroundColor);
+ this.Nodes[objectID] = newNode;
+ }
+
+ this.addRectangleObject = function(objectID,nodeLabel, width, height, xJustify , yJustify , backgroundColor, foregroundColor)
+ {
+ if (this.Nodes[objectID] != null || this.Nodes[objectID] != undefined)
+ {
+ throw new Error("addRectangleObject:Object with same ID already Exists!");
+ }
+ var newNode = new AnimatedRectangle(objectID, nodeLabel, width, height, xJustify, yJustify, backgroundColor, foregroundColor);
+ this.Nodes[objectID] = newNode;
+
+ }
+
+
+
+
+ this.setNodePosition = function(nodeID, newX, newY)
+ {
+ if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
+ {
+ // TODO: Error here?
+ return;
+ }
+ if (newX == undefined || newY == undefined)
+ {
+
+ return;
+ }
+ this.Nodes[nodeID].x = newX;
+ this.Nodes[nodeID].y = newY;
+ /* Don't need to dirty anything, since we repaint everything every frame
+ (TODO: Revisit if we do conditional redraws)
+ }*/
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/UndoFunctions.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/UndoFunctions.js
new file mode 100644
index 0000000..563163a
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/AnimationLibrary/UndoFunctions.js
@@ -0,0 +1,398 @@
+// 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 ``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 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
+
+
+// Base "class": UndoBlock
+
+function UndoBlock()
+{
+
+}
+
+UndoBlock.prototype.addUndoAnimation = function(animationList)
+{
+ return false;
+}
+
+UndoBlock.prototype.undoInitialStep = function(world)
+{
+
+}
+
+////////////////////////////////////////////////////////////
+// UndoMove
+////////////////////////////////////////////////////////////
+
+function UndoMove(id, fmX, fmy, tx, ty)
+{
+ this.objectID = id;
+ this.fromX = fmX;
+ this.fromY = fmy;
+ this.toX = tx;
+ this.toY = ty;
+}
+
+
+UndoMove.prototype = new UndoBlock();
+UndoMove.prototype.constructor = UndoMove;
+
+UndoMove.prototype.addUndoAnimation = function (animationList)
+{
+ var nextAnim = new SingleAnimation(this.objectID, this.fromX, this.fromY, this.toX, this.toY);
+ animationList.push(nextAnim);
+ return true;
+}
+
+////////////////////////////////////////////////////////////
+// UndoCreate
+////////////////////////////////////////////////////////////
+
+function UndoCreate(id)
+{
+ this.objectID = id;
+}
+
+UndoCreate.prototype = new UndoBlock();
+UndoCreate.prototype.constructor = UndoCreate;
+
+
+UndoCreate.prototype.undoInitialStep = function(world)
+{
+ world.removeObject(this.objectID);
+}
+
+////////////////////////////////////////////////////////////
+// UndoHighlight
+////////////////////////////////////////////////////////////
+
+function UndoHighlight(id, val)
+{
+ this.objectID = id;
+ this.highlightValue = val;
+}
+
+UndoHighlight.prototype = new UndoBlock();
+UndoHighlight.prototype.constructor = UndoHighlight;
+
+UndoHighlight.prototype.undoInitialStep = function(world)
+{
+ world.setHighlight(this.objectID, this.highlightValue);
+}
+
+
+////////////////////////////////////////////////////////////
+// UndoSetHeight
+////////////////////////////////////////////////////////////
+
+function UndoSetHeight(id, val)
+{
+ this.objectID = id;
+ this.height = val;
+}
+
+UndoSetHeight.prototype = new UndoBlock();
+UndoSetHeight.prototype.constructor = UndoSetHeight;
+
+UndoSetHeight.prototype.undoInitialStep = function(world)
+{
+ world.setHeight(this.objectID, this.height);
+}
+
+////////////////////////////////////////////////////////////
+// UndoSetWidth
+////////////////////////////////////////////////////////////
+
+function UndoSetWidth(id, val)
+{
+ this.objectID = id;
+ this.width = val;
+}
+
+UndoSetWidth.prototype = new UndoBlock();
+UndoSetWidth.prototype.constructor = UndoSetWidth;
+
+UndoSetWidth.prototype.undoInitialStep = function(world)
+{
+ world.setWidth(this.objectID, this.width);
+}
+
+
+////////////////////////////////////////////////////////////
+// UndoSetNumElements
+////////////////////////////////////////////////////////////
+function UndoSetNumElements(obj, newNumElems)
+{
+ this.objectID = obj.objectID;
+ this.sizeBeforeChange = obj.getNumElements();
+ this.sizeAfterChange = newNumElems;
+ if (this.sizeBeforeChange > this.sizeAfterChange)
+ {
+ this.labels = new Array(this.sizeBeforeChange - this.sizeAfterChange);
+ this.colors = new Array(this.sizeBeforeChange - this.sizeAfterChange);
+ for (var i = 0; i < this.sizeBeforeChange - this.sizeAfterChange; i++)
+ {
+ this.labels[i] = obj.getText(i+this.sizeAfterChange);
+ this.colors[i] = obj.getTextColor(i+this.sizeAfterChange);
+ }
+
+ }
+}
+
+UndoSetNumElements.prototype = new UndoBlock();
+UndoSetNumElements.prototype.constructor = UndoSetNumElements;
+
+
+UndoSetNumElements.prototype.undoInitialStep = function(world)
+{
+ world.setNumElements(this.objectID, this.sizeBeforeChange);
+ if (this.sizeBeforeChange > this.sizeAfterChange)
+ {
+ for (var i = 0; i < this.sizeBeforeChange - this.sizeAfterChange; i++)
+ {
+ world.setText(this.objectID, this.labels[i], i+this.sizeAfterChange);
+ world.setTextColor(this.objectID, this.colors[i], i+this.sizeAfterChange);
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// UndoSetAlpha
+////////////////////////////////////////////////////////////
+
+function UndoSetAlpha(id, alph)
+{
+ this.objectID = id;
+ this.alphaVal = alph;
+}
+
+UndoSetAlpha.prototype = new UndoBlock();
+UndoSetAlpha.prototype.constructor = UndoSetAlpha;
+
+UndoSetAlpha.prototype.undoInitialStep = function(world)
+{
+ world.setAlpha(this.objectID, this.alphaVal);
+}
+
+////////////////////////////////////////////////////////////
+// UndoSetNull
+////////////////////////////////////////////////////////////
+
+function UndoSetNull(id, nv)
+{
+ this.objectID = id;
+ this.nullVal = nv;
+}
+
+UndoSetNull.prototype = new UndoBlock();
+UndoSetNull.prototype.constructor = UndoSetNull;
+
+UndoSetNull.prototype.undoInitialStep = function(world)
+{
+ world.setNull(this.objectID, this.nullVal);
+}
+
+////////////////////////////////////////////////////////////
+// UndoSetForegroundColor
+////////////////////////////////////////////////////////////
+
+function UndoSetForegroundColor(id, color)
+{
+ this.objectID = id;
+ this.color = color;
+}
+
+UndoSetForegroundColor.prototype = new UndoBlock();
+UndoSetForegroundColor.prototype.constructor = UndoSetForegroundColor;
+
+UndoSetForegroundColor.prototype.undoInitialStep = function (world)
+{
+ world.setForegroundColor(this.objectID, this.color);
+}
+
+////////////////////////////////////////////////////////////
+// UndoSetBackgroundColor
+////////////////////////////////////////////////////////////
+
+function UndoSetBackgroundColor(id, color)
+{
+ this.objectID = id;
+ this.color = color;
+}
+
+UndoSetBackgroundColor.prototype = new UndoBlock();
+UndoSetBackgroundColor.prototype.constructor = UndoSetBackgroundColor;
+
+UndoSetBackgroundColor.prototype.undoInitialStep = function (world)
+{
+ world.setBackgroundColor(this.objectID, this.color);
+}
+
+
+
+////////////////////////////////////////////////////////////
+// UndoSetHighlightIndex
+////////////////////////////////////////////////////////////
+
+function UndoSetHighlightIndex(id, index)
+{
+ this.objectID = id;
+ this.index = index;
+}
+
+UndoSetHighlightIndex.prototype = new UndoBlock();
+UndoSetHighlightIndex.prototype.constructor = UndoSetHighlightIndex;
+
+UndoSetHighlightIndex.prototype.undoInitialStep = function (world)
+{
+ world.setHighlightIndex(this.objectID, this.index);
+}
+
+
+
+////////////////////////////////////////////////////////////
+// UndoSetText
+////////////////////////////////////////////////////////////
+
+
+
+function UndoSetText(id, str, index)
+{
+ this.objectID = id;
+ this.newText = str;
+ this.labelIndex = index;
+}
+
+UndoSetText.prototype = new UndoBlock();
+UndoSetText.prototype.constructor = UndoSetText;
+
+UndoSetText.prototype.undoInitialStep = function(world)
+{
+ world.setText(this.objectID, this.newText, this.labelIndex);
+}
+////////////////////////////////////////////////////////////
+// UndoSetTextColor
+////////////////////////////////////////////////////////////
+
+
+
+function UndoSetTextColor(id, color, index)
+{
+ this.objectID = id;
+ this.color = color;
+ this.index = index;
+}
+
+UndoSetTextColor.prototype = new UndoBlock();
+UndoSetTextColor.prototype.constructor = UndoSetTextColor;
+
+UndoSetTextColor.prototype.undoInitialStep = function(world)
+{
+ world.setTextColor(this.objectID, this.color, this.index);
+}
+
+
+
+////////////////////////////////////////////////////////////
+// UndoHighlightEdge
+////////////////////////////////////////////////////////////
+
+function UndoHighlightEdge(from, to, val)
+{
+ this.fromID = from;
+ this.toID = to;
+ this.highlightValue = val;
+}
+
+UndoHighlightEdge.prototype = new UndoBlock();
+UndoHighlightEdge.prototype.constructor = UndoHighlightEdge;
+
+UndoHighlightEdge.prototype.undoInitialStep = function(world)
+{
+ world.setEdgeHighlight(this.fromID, this.toID, this.highlightValue);
+}
+
+
+////////////////////////////////////////////////////////////
+// UndoSetEdgeColor
+////////////////////////////////////////////////////////////
+
+function UndoSetEdgeColor(from, to, oldColor)
+{
+ this.fromID = from;
+ this.toID = to;
+ this.color = oldColor;
+}
+
+UndoSetEdgeColor.prototype = new UndoBlock();
+UndoSetEdgeColor.prototype.constructor = UndoSetEdgeColor;
+
+UndoSetEdgeColor.prototype.undoInitialStep = function(world)
+{
+ world.setEdgeColor(this.fromID, this.toID, this.color);
+}
+
+
+////////////////////////////////////////////////////////////
+// UndoSetEdgeAlpha
+////////////////////////////////////////////////////////////
+
+function UndoSetEdgeAlpha(from, to, oldAplha)
+{
+ this.fromID = from;
+ this.toID = to;
+ this.alpha = oldAplha;
+}
+
+UndoSetEdgeAlpha.prototype = new UndoBlock();
+UndoSetEdgeAlpha.prototype.constructor = UndoSetEdgeAlpha;
+
+UndoSetEdgeAlpha.prototype.undoInitialStep = function(world)
+{
+ world.setEdgeAlpha(this.fromID, this.toID, this.alpha);
+}
+
+////////////////////////////////////////////////////////////
+// UndoSetPosition
+////////////////////////////////////////////////////////////
+
+function UndoSetPosition(id, x, y)
+{
+ this.objectID = id;
+ this.x = x;
+ this.y = y;
+}
+
+UndoSetPosition.prototype = new UndoBlock();
+UndoSetPosition.prototype.constructor = UndoSetPosition;
+
+
+UndoSetPosition.prototype.undoInitialStep = function(world)
+{
+ world.setNodePosition(this.objectID, this.x, this.y);
+}
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BFS.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BFS.html
new file mode 100644
index 0000000..c95c4f1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BFS.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Breadth-First Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BPlusTree.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BPlusTree.html
new file mode 100644
index 0000000..19cf938
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BPlusTree.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ B+ Tree Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BST.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BST.html
new file mode 100644
index 0000000..cd0c735
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BST.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+ Binary Search Tree Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BTree.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BTree.html
new file mode 100644
index 0000000..09ce0e9
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BTree.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+ B-Tree Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BinomialQueue.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BinomialQueue.html
new file mode 100644
index 0000000..e305f99
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BinomialQueue.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Binomial Queue Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BucketSort.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BucketSort.html
new file mode 100644
index 0000000..2986ebe
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/BucketSort.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+ Bucket Sort Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ChangingCoordinates2D.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ChangingCoordinates2D.html
new file mode 100644
index 0000000..7279a5c
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ChangingCoordinates2D.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Changing Coordinate Spaces Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ChangingCoordinates3D.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ChangingCoordinates3D.html
new file mode 100644
index 0000000..3962137
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ChangingCoordinates3D.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Changing Coordinate Spaces (3D) Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHash.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHash.html
new file mode 100644
index 0000000..33a1d51
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHash.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Closed Hashing Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHash2.JS b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHash2.JS
new file mode 100644
index 0000000..18aa323
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHash2.JS
@@ -0,0 +1,388 @@
+function ClosedHash(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+var ARRAY_ELEM_WIDTH = 90;
+var ARRAY_ELEM_HEIGHT = 30;
+var ARRAY_ELEM_START_X = 50;
+var ARRAY_ELEM_START_Y = 100;
+var ARRAY_VERTICAL_SEPARATION = 100;
+var ELEMENTS_PER_ROW = 10;
+
+var CLOSED_HASH_TABLE_SIZE = 29;
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+
+var MAX_DATA_VALUE = 999;
+
+var HASH_TABLE_SIZE = 13;
+
+var ARRAY_Y_POS = 350;
+
+
+var INDEX_COLOR = "#0000FF";
+
+
+
+ClosedHash.prototype = new Hash();
+ClosedHash.prototype.constructor = ClosedHash;
+ClosedHash.superclass = Hash.prototype;
+
+
+ClosedHash.prototype.init = function(am, w, h)
+{
+ var sc = ClosedHash.superclass;
+ var fn = sc.init;
+ fn.call(this,am, w, h);
+
+ //Change me!
+ this.nextIndex = 0;
+ //this.POINTER_ARRAY_ELEM_Y = h - POINTER_ARRAY_ELEM_WIDTH;
+ this.setup();
+}
+
+ClosedHash.prototype.addControls = function()
+{
+ ClosedHash.superclass.addControls.call(this);
+
+
+ var radioButtonList = addRadioButtonGroupToAlgorithmBar(["Linear Probing: f(i) = i",
+ "Quadratic Probing: f(i) = i * i",
+ "Double Hashing: f(i) = i * hash2(elem)"],
+ "CollisionStrategy");
+ this.linearProblingButton = radioButtonList[0];
+ this.linearProblingButton.onclick = this.linearProbeCallback.bind(this);
+ this.quadraticProbingButton = radioButtonList[1];
+ this.quadraticProbingButton.onclick = this.quadraticProbeCallback.bind(this);
+ this.doubleHashingButton = radioButtonList[2];
+ this.doubleHashingButton.onclick = this.doubleHashingCallback.bind(this);
+
+ this.linearProblingButton.checked = true;
+ this.currentHashingTypeButtonState = this.linearProblingButton;
+
+ // Add new controls
+
+}
+
+
+ClosedHash.prototype.changeProbeType = function(newProbingType)
+{
+ if (newProbingType == this.linearProblingButton)
+ {
+ this.linearProblingButton.checked = true;
+ this.currentHashingTypeButtonState = this.linearProblingButton;
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.skipDist[i] = i;
+ }
+
+ }
+ else if (newProbingType == this.quadraticProbingButton)
+ {
+ this.quadraticProbingButton.checked = true;
+ this.currentHashingTypeButtonState = this.quadraticProbingButton;
+
+ for (var i = 0; i < this. table_size; i++)
+ {
+ this.skipDist[i] = i * i;
+ }
+
+
+ }
+ else if (newProbingType == this.doubleHashingButton)
+ {
+ this.doubleHashingButton.checked = true;
+ this.currentHashingTypeButtonState = this.doubleHashingButton;
+
+
+ }
+ this.commands = this.resetAll();
+ return this.commands;
+}
+
+
+
+ClosedHash.prototype.quadraticProbeCallback = function(event)
+{
+ if (this.currentHashingTypeButtonState != this.quadraticProbingButton)
+ {
+ this.implementAction(this.changeProbeType.bind(this),this.quadraticProbingButton);
+ }
+
+}
+
+
+ClosedHash.prototype.doubleHashingCallback = function(event)
+{
+ if (this.currentHashingTypeButtonState != this.doubleHashingButton)
+ {
+ this.implementAction(this.changeProbeType.bind(this),this.doubleHashingButton);
+ }
+
+}
+
+ClosedHash.prototype.linearProbeCallback = function(event)
+{
+ if (this.currentHashingTypeButtonState != this.linearProblingButton)
+ {
+ this.implementAction(this.changeProbeType.bind(this),this.linearProblingButton);
+ }
+
+}
+
+ClosedHash.prototype.insertElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "Inserting element: " + String(elem));
+ var index = this.doHash(elem);
+
+ index = this.getEmptyIndex(index, elem);
+ this.cmd("SetText", this.ExplainLabel, "");
+ if (index != -1)
+ {
+ var labID = this.nextIndex++;
+ this.cmd("CreateLabel", labID, elem, 20, 25);
+ this.cmd("Move", labID, this.indexXPos[index], this.indexYPos[index] - ARRAY_ELEM_HEIGHT);
+ this.cmd("Step");
+ this.cmd("Delete", labID);
+ this.cmd("SetText", this.hashTableVisual[index], elem);
+ this.hashTableValues[index] = elem;
+ this.empty[index] = false;
+ this.deleted[index] = false;
+ }
+ return this.commands;
+
+}
+
+
+ClosedHash.prototype.resetSkipDist = function(elem, labelID)
+{
+ var skipVal = 7 - (this.currHash % 7);
+ this.cmd("CreateLabel", labelID, "hash2("+String(elem) +") = 1 - " + String(this.currHash) +" % 7 = " + String(skipVal), 20, 45, 0);
+ this.skipDist[0] = 0;
+ for (var i = 1; i < this.table_size; i++)
+ {
+ this.skipDist[i] = this.skipDist[i-1] + skipVal;
+ }
+
+
+}
+
+ClosedHash.prototype.getEmptyIndex = function(index, elem)
+{
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ this.resetSkipDist(elem, this.nextIndex++);
+ }
+ var foundIndex = -1;
+ for (var i = 0; i < this.table_size; i++)
+ {
+ var candidateIndex = (index + this.skipDist[i]) % this.table_size;
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+ if (this.empty[candidateIndex])
+ {
+ foundIndex = candidateIndex;
+ break;
+ }
+ }
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ this.cmd("Delete", --this.nextIndex);
+ }
+ return foundIndex;
+}
+
+ClosedHash.prototype.getElemIndex = function(index, elem)
+{
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ resetSkipDist(elem, this.nextIndex++);
+ }
+ var foundIndex = -1;
+ for (var i = 0; i < this.table_size; i++)
+ {
+ var candidateIndex = (index + this.skipDist[i]) % this.table_size;
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 1);
+ this.cmd("Step");
+ this.cmd("SetHighlight", this.hashTableVisual[candidateIndex], 0);
+ if (!this.empty[candidateIndex] && this.hashTableValues[candidateIndex] == elem)
+ {
+ foundIndex= candidateIndex;
+ break;
+ }
+ else if (this.empty[candidateIndex] && !this.deleted[candidateIndex])
+ {
+ break; }
+ }
+ if (this.currentHashingTypeButtonState == this.doubleHashingButton)
+ {
+ this.cmd("Delete", --this.nextIndex);
+ }
+ return foundIndex;
+}
+
+ClosedHash.prototype.deleteElement = function(elem)
+{
+ this.commands = new Array();
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem);
+ var index = this.doHash(elem);
+
+ index = getElemIndex(index, elem);
+
+ if (index > 0)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " 元素已删除");
+ this.empty[index] = true;
+ this.deleted[index] = true;
+ this.cmd("SetText", this.hashTableVisual[index], "");
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在删除元素: " + elem + " Element not in table");
+ }
+ return this.commands;
+
+}
+ClosedHash.prototype.findElement = function(elem)
+{
+ this.commands = new Array();
+
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem);
+ var index = this.doHash(elem);
+
+ var found = getElemIndex(index, elem) != -1;
+ if (found)
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem+ " 已找到!")
+ }
+ else
+ {
+ this.cmd("SetText", this.ExplainLabel, "正在搜索元素: " + elem+ " 未找到!")
+
+ }
+ return this.commands;
+}
+
+
+
+
+ClosedHash.prototype.setup = function()
+{
+ this.table_size = CLOSED_HASH_TABLE_SIZE;
+ this.skipDist = new Array(this.table_size);
+ this.hashTableVisual = new Array(this.table_size);
+ this.hashTableIndices = new Array(this.table_size);
+ this.hashTableValues = new Array(this.table_size);
+
+ this.indexXPos = new Array(this.table_size);
+ this.indexYPos = new Array(this.table_size);
+
+ this.empty = new Array(this.table_size);
+ this.deleted = new Array(this.table_size);
+
+ this.ExplainLabel = this.nextIndex++;
+
+ this.commands = [];
+
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.skipDist[i] = i; // Start with linear probing
+ var nextID = this.nextIndex++;
+ this.empty[i] = true;
+ this.deleted[i] = false;
+
+ var nextXPos = ARRAY_ELEM_START_X + (i % ELEMENTS_PER_ROW) * ARRAY_ELEM_WIDTH;
+ var nextYPos = ARRAY_ELEM_START_Y + Math.floor(i / ELEMENTS_PER_ROW) * ARRAY_VERTICAL_SEPARATION;
+ this.cmd("CreateRectangle", nextID, "", ARRAY_ELEM_WIDTH, ARRAY_ELEM_HEIGHT,nextXPos, nextYPos)
+ this.hashTableVisual[i] = nextID;
+ nextID = this.nextIndex++;
+ this.hashTableIndices[i] = nextID;
+ this.indexXPos[i] = nextXPos;
+ this.indexYPos[i] = nextYPos + ARRAY_ELEM_HEIGHT
+
+ this.cmd("CreateLabel", nextID, i,this.indexXPos[i],this.indexYPos[i]);
+ this.cmd("SetForegroundColor", nextID, INDEX_COLOR);
+ }
+ this.cmd("CreateLabel", this.ExplainLabel, "", 10, 25, 0);
+ animationManager.StartNewAnimation(this.commands);
+ animationManager.skipForward();
+ animationManager.clearHistory();
+ this.resetIndex = this.nextIndex;
+}
+
+
+
+ClosedHash.prototype.resetAll = function()
+{
+ this.commands = [];
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.empty[i] = true;
+ this.deleted[i] = false;
+ this.cmd("SetText", this.hashTableVisual[i], "");
+ }
+ return this.commands;
+ // Clear array, etc
+}
+
+
+
+// NEED TO OVERRIDE IN PARENT
+ClosedHash.prototype.reset = function()
+{
+ for (var i = 0; i < this.table_size; i++)
+ {
+ this.empty[i]= true;
+ this.deleted[i] = false;
+ }
+ this.nextIndex = this.resetIndex ;
+ ClosedHash.superclass.reset.call(this);
+
+}
+
+
+function resetCallback(event)
+{
+
+}
+
+
+
+
+
+ClosedHash.prototype.disableUI = function(event)
+{
+ ClosedHash.superclass.disableUI.call(this);
+ this.linearProblingButton.disabled = true;
+ this.quadraticProbingButton.disabled = true;
+ this.doubleHashingButton.disabled = true;
+}
+
+ClosedHash.prototype.enableUI = function(event)
+{
+ ClosedHash.superclass.enableUI.call(this);
+ this.linearProblingButton.disabled = false;
+ this.quadraticProbingButton.disabled = false;
+ this.doubleHashingButton.disabled = false;
+}
+
+
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new ClosedHash(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHashBucket.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHashBucket.html
new file mode 100644
index 0000000..4f05449
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ClosedHashBucket.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Closed Hashing (Buckets) Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ComparisonSort.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ComparisonSort.html
new file mode 100644
index 0000000..3390121
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ComparisonSort.html
@@ -0,0 +1,68 @@
+
+
+
+
+ Comparison Sorting Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ConnectedComponent.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ConnectedComponent.html
new file mode 100644
index 0000000..f536ce5
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ConnectedComponent.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Connected Component Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/CountingSort.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/CountingSort.html
new file mode 100644
index 0000000..9b058e1
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/CountingSort.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+ Counting Sort Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DFS.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DFS.html
new file mode 100644
index 0000000..da75f61
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DFS.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Depth-First Search Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPChange.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPChange.html
new file mode 100644
index 0000000..d49b2db
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPChange.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Dynamic Programming (Making Change)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPFib.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPFib.html
new file mode 100644
index 0000000..a6bf6ec
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPFib.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Dynamic Programming (Fibonacci)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPLCS.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPLCS.html
new file mode 100644
index 0000000..09f82f4
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DPLCS.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Dynamic Programming (Longest Common Subsequence)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Dijkstra.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Dijkstra.html
new file mode 100644
index 0000000..de6f191
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Dijkstra.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Dijkstra Visualzation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DisjointSets.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DisjointSets.html
new file mode 100644
index 0000000..d5249c0
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/DisjointSets.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Disjoint Sets Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/FibonacciHeap.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/FibonacciHeap.html
new file mode 100644
index 0000000..12c9bc2
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/FibonacciHeap.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Fibonacci Heap Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Floyd.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Floyd.html
new file mode 100644
index 0000000..9193d32
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Floyd.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Floyd-Warshall All-Pairs Shortest Path
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Heap.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Heap.html
new file mode 100644
index 0000000..2ec0fbe
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Heap.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Heap Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/HeapSort.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/HeapSort.html
new file mode 100644
index 0000000..196b0d2
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/HeapSort.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+ Heap Sort Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Kruskal.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Kruskal.html
new file mode 100644
index 0000000..d34eb1d
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Kruskal.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Kruskal MST Visualzation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/LeftistHeap.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/LeftistHeap.html
new file mode 100644
index 0000000..94f58b2
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/LeftistHeap.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Leftist Heap Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/OpenHash.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/OpenHash.html
new file mode 100644
index 0000000..075325e
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/OpenHash.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Open Hashing Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Prim.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Prim.html
new file mode 100644
index 0000000..b206d4e
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Prim.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Prim MST Visualzation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueArray.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueArray.html
new file mode 100644
index 0000000..3677497
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueArray.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Array Queue Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueLL b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueLL
new file mode 100644
index 0000000..ba7ba0b
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueLL
@@ -0,0 +1,275 @@
+var LINKED_LIST_START_X = 100;
+var LINKED_LIST_START_Y = 200;
+var LINKED_LIST_ELEM_WIDTH = 70;
+var LINKED_LIST_ELEM_HEIGHT = 30;
+
+
+var LINKED_LIST_INSERT_X = 250;
+var LINKED_LIST_INSERT_Y = 50;
+
+var LINKED_LIST_ELEMS_PER_LINE = 8;
+var LINKED_LIST_ELEM_SPACING = 100;
+var LINKED_LIST_LINE_SPACING = 100;
+
+var TOP_POS_X = 180;
+var TOP_POS_Y = 100;
+var TOP_LABEL_X = 130;
+var TOP_LABEL_Y = 100;
+
+var TOP_ELEM_WIDTH = 30;
+var TOP_ELEM_HEIGHT = 30;
+
+var PUSH_LABEL_X = 50;
+var PUSH_LABEL_Y = 30;
+var PUSH_ELEMENT_X = 120;
+var PUSH_ELEMENT_Y = 30;
+
+var SIZE = 32;
+
+function StackLL(am, w, h)
+{
+ this.init(am, w, h);
+
+}
+
+StackLL.prototype = new Algorithm();
+StackLL.prototype.constructor = StackLL;
+StackLL.superclass = Algorithm.prototype;
+
+
+StackLL.prototype.init = function(am, w, h)
+{
+ StackLL.superclass.init.call(this, am, w, h);
+ this.addControls();
+ this.nextIndex = 0;
+ this.commands = [];
+ this.setup();
+ this.initialIndex = this.nextIndex;
+}
+
+
+StackLL.prototype.addControls = function()
+{
+ this.controls = [];
+ this.pushField = addControlToAlgorithmBar("Text", "");
+ this.pushField.onkeydown = this.returnSubmit(this.pushField, this.pushCallback.bind(this), 6);
+ this.pushButton = addControlToAlgorithmBar("Button", "Push");
+ this.pushButton.onclick = this.pushCallback.bind(this);
+ this.controls.push(this.pushField);
+ this.controls.push(this.pushButton);
+
+ this.popButton = addControlToAlgorithmBar("Button", "Pop");
+ this.popButton.onclick = this.popCallback.bind(this);
+ this.controls.push(this.popButton);
+
+ this.clearButton = addControlToAlgorithmBar("Button", "Clear Stack");
+ this.clearButton.onclick = this.clearCallback.bind(this);
+ this.controls.push(this.clearButton);
+
+}
+
+StackLL.prototype.enableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = false;
+ }
+
+
+}
+StackLL.prototype.disableUI = function(event)
+{
+ for (var i = 0; i < this.controls.length; i++)
+ {
+ this.controls[i].disabled = true;
+ }
+}
+
+
+StackLL.prototype.setup = function()
+{
+
+ this.linkedListElemID = new Array(SIZE);
+ for (var i = 0; i < SIZE; i++)
+ {
+
+ this.linkedListElemID[i]= this.nextIndex++;
+ }
+ this.topID = this.nextIndex++;
+ this.topLabelID = this.nextIndex++;
+
+ this.arrayData = new Array(SIZE);
+ this.top = 0;
+ this.leftoverLabelID = this.nextIndex++;
+
+ this.cmd("CreateLabel", this.topLabelID, "Top", TOP_LABEL_X, TOP_LABEL_Y);
+ this.cmd("CreateRectangle", this.topID, "", TOP_ELEM_WIDTH, TOP_ELEM_HEIGHT, TOP_POS_X, TOP_POS_Y);
+ this.cmd("SetNull", this.topID, 1);
+
+ this.cmd("CreateLabel", this.leftoverLabelID, "", PUSH_LABEL_X, PUSH_LABEL_Y);
+
+ this.animationManager.StartNewAnimation(this.commands);
+ this.animationManager.skipForward();
+ this.animationManager.clearHistory();
+
+}
+
+StackLL.prototype.resetLinkedListPositions = function()
+{
+ for (var i = this.top - 1; i >= 0; i--)
+ {
+ var nextX = (this.top - 1 - i) % LINKED_LIST_ELEMS_PER_LINE * LINKED_LIST_ELEM_SPACING + LINKED_LIST_START_X;
+ var nextY = Math.floor((this.top - 1 - i) / LINKED_LIST_ELEMS_PER_LINE) * LINKED_LIST_LINE_SPACING + LINKED_LIST_START_Y;
+ this.cmd("Move", this.linkedListElemID[i], nextX, nextY);
+ }
+
+}
+
+
+
+
+StackLL.prototype.reset = function()
+{
+ this.top = 0;
+ this.nextIndex = this.initialIndex;
+
+}
+
+
+StackLL.prototype.pushCallback = function(event)
+{
+ if (this.top < SIZE && this.pushField.value != "")
+ {
+ var pushVal = this.pushField.value;
+ this.pushField.value = ""
+ this.implementAction(this.push.bind(this), pushVal);
+ }
+}
+
+
+StackLL.prototype.popCallback = function(event)
+{
+ if (this.top > 0)
+ {
+ this.implementAction(this.pop.bind(this), "");
+ }
+}
+
+
+StackLL.prototype.clearCallback = function(event)
+{
+ implementAction(this.clearData.bind(this), "");
+}
+
+
+
+StackLL.prototype.push = function(elemToPush)
+{
+ this.commands = new Array();
+
+ var labPushID = this.nextIndex++;
+ var labPushValID = this.nextIndex++;
+ this.arrayData[this.top] = elemToPush;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+ this.cmd("CreateLinkedList",this.linkedListElemID[this.top], "" ,LINKED_LIST_ELEM_WIDTH, LINKED_LIST_ELEM_HEIGHT,
+ LINKED_LIST_INSERT_X, LINKED_LIST_INSERT_Y, 0.25, 0, 1, 1);
+
+ this.cmd("CreateLabel", labPushID, "Pushing Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPushValID,elemToPush, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+
+ this.cmd("Step");
+
+
+
+ this.cmd("Move", labPushValID, LINKED_LIST_INSERT_X, LINKED_LIST_INSERT_Y);
+
+ this.cmd("Step");
+ this.cmd("SetText", this.linkedListElemID[this.top], elemToPush);
+ this.cmd("Delete", labPushValID);
+
+ if (this.top == 0)
+ {
+ this.cmd("SetNull", this.topID, 0);
+ this.cmd("SetNull", this.linkedListElemID[this.top], 1);
+ }
+ else
+ {
+ this.cmd("Connect", this.linkedListElemID[this.top], this.linkedListElemID[this.top - 1]);
+ this.cmd("Step");
+ this.cmd("Disconnect", this.topID, this.linkedListElemID[this.top-1]);
+ }
+ this.cmd("Connect", this.topID, this.linkedListElemID[this.top]);
+
+ this.cmd("Step");
+ this.top = this.top + 1;
+ this.resetLinkedListPositions();
+ this.cmd("Delete", labPushID);
+ this.cmd("Step");
+
+ return this.commands;
+}
+
+StackLL.prototype.pop = function(ignored)
+{
+ this.commands = new Array();
+
+ var labPopID = this.nextIndex++;
+ var labPopValID = this.nextIndex++;
+
+ this.cmd("SetText", this.leftoverLabelID, "");
+
+
+ this.cmd("CreateLabel", labPopID, "Popped Value: ", PUSH_LABEL_X, PUSH_LABEL_Y);
+ this.cmd("CreateLabel", labPopValID,this.arrayData[this.top - 1], LINKED_LIST_START_X, LINKED_LIST_START_Y);
+
+ this.cmd("Move", labPopValID, PUSH_ELEMENT_X, PUSH_ELEMENT_Y);
+ this.cmd("Step");
+ this.cmd("Disconnect", this.topID, this.linkedListElemID[this.top - 1]);
+
+ if (this.top == 1)
+ {
+ this.cmd("SetNull", this.topID, 1);
+ }
+ else
+ {
+ this.cmd("Connect", this.topID, this.linkedListElemID[this.top-2]);
+
+ }
+ this.cmd("Step");
+ this.cmd("Delete", this.linkedListElemID[this.top - 1]);
+ this.top = this.top - 1;
+ this.resetLinkedListPositions();
+
+ this.cmd("Delete", labPopValID)
+ this.cmd("Delete", labPopID);
+ this.cmd("SetText", this.leftoverLabelID, "Popped Value: " + this.arrayData[this.top]);
+
+
+
+ return this.commands;
+}
+
+
+
+StackLL.prototype.clearAll = function()
+{
+ this.commands = new Array();
+ for (var i = 0; i < this.top; i++)
+ {
+ cmd("Delete", this.linkedListElemID[i]);
+ }
+ this.top = 0;
+ this.cmd("SetNull", this.topID, 1);
+ return this.commands;
+}
+
+
+var currentAlg;
+
+function init()
+{
+ var animManag = initCanvas();
+ currentAlg = new StackLL(animManag, canvas.width, canvas.height);
+}
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueLL.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueLL.html
new file mode 100644
index 0000000..9e00a2f
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/QueueLL.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Linked List Queue Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RadixSort.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RadixSort.html
new file mode 100644
index 0000000..a4f8e0d
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RadixSort.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Radix Sort Visualzation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RadixTree.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RadixTree.html
new file mode 100644
index 0000000..2d9e88a
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RadixTree.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+ Radix Tree Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecFact.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecFact.html
new file mode 100644
index 0000000..496c60a
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecFact.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Recursive Factorial
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecQueens.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecQueens.html
new file mode 100644
index 0000000..3b50e11
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecQueens.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Recursive N-Queens
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecReverse.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecReverse.html
new file mode 100644
index 0000000..a554433
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RecReverse.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Recursive Reverse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RedBlack.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RedBlack.html
new file mode 100644
index 0000000..6dbdfec
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RedBlack.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Red/Black Tree Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateScale2D.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateScale2D.html
new file mode 100644
index 0000000..18ff17f
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateScale2D.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Rotation and Scaling (2D)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateScale3D.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateScale3D.html
new file mode 100644
index 0000000..e5a22b0
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateScale3D.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Rotation and Scaling (3D)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateTranslate2D.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateTranslate2D.html
new file mode 100644
index 0000000..65bc0e9
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/RotateTranslate2D.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Rotation and Translation (2D)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Screenshot.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Screenshot.png
new file mode 100644
index 0000000..91f435e
Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Screenshot.png differ
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Search.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Search.html
new file mode 100644
index 0000000..12b40ba
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Search.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Binary and Linear Search Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SimpleStack.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SimpleStack.html
new file mode 100644
index 0000000..7167322
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SimpleStack.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Simple Stack Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SkewHeap.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SkewHeap.html
new file mode 100644
index 0000000..43bd0df
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SkewHeap.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Skew Heap Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SplayTree.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SplayTree.html
new file mode 100644
index 0000000..baf32da
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/SplayTree.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Splay Tree Visualzation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/StackArray.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/StackArray.html
new file mode 100644
index 0000000..e6e16da
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/StackArray.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Array Stack Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/StackLL.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/StackLL.html
new file mode 100644
index 0000000..93410ec
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/StackLL.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Linked List Stack Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TST.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TST.html
new file mode 100644
index 0000000..6ef6349
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TST.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+ Ternary Search Tree Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-1.5.2.min.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-1.5.2.min.js
new file mode 100644
index 0000000..f78f96a
--- /dev/null
+++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-1.5.2.min.js
@@ -0,0 +1,16 @@
+/*!
+ * jQuery JavaScript Library v1.5.2
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Mar 31 15:28:23 2011 -0400
+ */
+(function(a,b){function ci(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cf(a){if(!b_[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";b_[a]=c}return b_[a]}function ce(a,b){var c={};d.each(cd.concat.apply([],cd.slice(0,b)),function(){c[this]=a});return c}function b$(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bZ(){try{return new a.XMLHttpRequest}catch(b){}}function bY(){d(a).unload(function(){for(var a in bW)bW[a](0,1)})}function bS(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g=0===c})}function P(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function H(a,b){return(a&&a!=="*"?a+".":"")+b.replace(t,"`").replace(u,"&")}function G(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,p=[],q=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function E(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function y(){return!0}function x(){return!1}function i(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function h(a,c,e){if(e===b&&a.nodeType===1){e=a.getAttribute("data-"+c);if(typeof e==="string"){try{e=e==="true"?!0:e==="false"?!1:e==="null"?null:d.isNaN(e)?g.test(e)?d.parseJSON(e):e:parseFloat(e)}catch(f){}d.data(a,c,e)}else e=b}return e}var c=a.document,d=function(){function G(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(G,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x,y,z=Object.prototype.toString,A=Object.prototype.hasOwnProperty,B=Array.prototype.push,C=Array.prototype.slice,D=String.prototype.trim,E=Array.prototype.indexOf,F={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.2",length:0,size:function(){return this.length},toArray:function(){return C.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?B.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),x.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(C.apply(this,arguments),"slice",C.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:B,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;x.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=d._Deferred();if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",y,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",y),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&G()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):F[z.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!A.call(a,"constructor")&&!A.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||A.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1?f.call(arguments,0):c,--g||h.resolveWith(h,f.call(b,0))}}var b=arguments,c=0,e=b.length,g=e,h=e<=1&&a&&d.isFunction(a.promise)?a:d.Deferred();if(e>1){for(;ca";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0,reliableMarginRight:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e)}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(a.style.width="1px",a.style.marginRight="0",d.support.reliableMarginRight=(parseInt(c.defaultView.getComputedStyle(a,null).marginRight,10)||0)===0),b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function");return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}}();var g=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!i(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,g=b.nodeType,h=g?d.cache:b,j=g?b[d.expando]:d.expando;if(!h[j])return;if(c){var k=e?h[j][f]:h[j];if(k){delete k[c];if(!i(k))return}}if(e){delete h[j][f];if(!i(h[j]))return}var l=h[j][f];d.support.deleteExpando||h!=a?delete h[j]:h[j]=null,l?(h[j]={},g||(h[j].toJSON=d.noop),h[j][f]=l):g&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var f=this[0].attributes,g;for(var i=0,j=f.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var j=i?f:0,k=i?f+1:h.length;j=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=m.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&n.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var k=a.getAttributeNode("tabIndex");return k&&k.specified?k.value:o.test(a.nodeName)||p.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var l=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return l===null?b:l}h&&(a[c]=e);return a[c]}});var r=/\.(.*)$/,s=/^(?:textarea|input|select)$/i,t=/\./g,u=/ /g,v=/[^\w\s.|`]/g,w=function(a){return a.replace(v,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=x;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(a){return typeof d!=="undefined"&&d.event.triggered!==a.type?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=x);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),w).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(r,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=a.type,l[m]())}catch(p){}k&&(l["on"+m]=k),d.event.triggered=b}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},D=function D(a){var c=a.target,e,f;if(s.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=C(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:D,beforedeactivate:D,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&D.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&D.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",C(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in B)d.event.add(this,c+".specialChange",B[c]);return s.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return s.test(this.nodeName)}},B=d.event.special.change.filters,B.focus=B.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function f(a){var c=d.event.fix(a);c.type=b,c.originalEvent={},d.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var e=0;d.event.special[b]={setup:function(){e++===0&&c.addEventListener(a,f,!0)},teardown:function(){--e===0&&c.removeEventListener(a,f,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return"text"===c&&(b===c||b===null)},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=N.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(P(c[0])||P(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=M.call(arguments);I.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!O[a]?d.unique(f):f,(this.length>1||K.test(e))&&J.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var R=/ jQuery\d+="(?:\d+|null)"/g,S=/^\s+/,T=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,U=/<([\w:]+)/,V=/",""],legend:[1,""],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""],_default:[0,"",""]};Z.optgroup=Z.option,Z.tbody=Z.tfoot=Z.colgroup=Z.caption=Z.thead,Z.th=Z.td,d.support.htmlSerialize||(Z._default=[1,"div","
"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(R,""):null;if(typeof a!=="string"||X.test(a)||!d.support.leadingWhitespace&&S.test(a)||Z[(U.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(T,"<$1>$2>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){ba(a,e),f=bb(a),g=bb(e);for(h=0;f[h];++h)ba(f[h],g[h])}if(b){_(a,e);if(c){f=bb(a),g=bb(e);for(h=0;f[h];++h)_(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||W.test(i)){if(typeof i==="string"){i=i.replace(T,"<$1>$2>");var j=(U.exec(i)||["",""])[1].toLowerCase(),k=Z[j]||Z._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=V.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&S.test(i)&&m.insertBefore(b.createTextNode(S.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bd=/alpha\([^)]*\)/i,be=/opacity=([^)]*)/,bf=/-([a-z])/ig,bg=/([A-Z]|^ms)/g,bh=/^-?\d+(?:px)?$/i,bi=/^-?\d/,bj={position:"absolute",visibility:"hidden",display:"block"},bk=["Left","Right"],bl=["Top","Bottom"],bm,bn,bo,bp=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bm(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bm)return bm(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bf,bp)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bq(a,b,e):d.swap(a,bj,function(){f=bq(a,b,e)});if(f<=0){f=bm(a,b,b),f==="0px"&&bo&&(f=bo(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bh.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return be.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bd.test(f)?f.replace(bd,e):c.filter+" "+e}}),d(function(){d.support.reliableMarginRight||(d.cssHooks.marginRight={get:function(a,b){var c;d.swap(a,{display:"inline-block"},function(){b?c=bm(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bn=function(a,c,e){var f,g,h;e=e.replace(bg,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bo=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bh.test(d)&&bi.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bm=bn||bo,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var br=/%20/g,bs=/\[\]$/,bt=/\r?\n/g,bu=/#.*$/,bv=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bw=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bx=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,by=/^(?:GET|HEAD)$/,bz=/^\/\//,bA=/\?/,bB=/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+