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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 + + + + + +
+

Data Structure Visualizations

+ + +
+ + +Currently, we have visualizations for the following data structures +and algorithms: + + + + +
+ + +
+ + + 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(;c
a";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="
t
";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>");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>");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=/)<[^<]*)*<\/script>/gi,bC=/^(?:select|textarea)/i,bD=/\s+/,bE=/([?&])_=[^&]*/,bF=/(^|\-)([a-z])/g,bG=function(a,b,c){return b+c.toUpperCase()},bH=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bI=d.fn.load,bJ={},bK={},bL,bM;try{bL=c.location.href}catch(bN){bL=c.createElement("a"),bL.href="",bL=bL.href}bM=bH.exec(bL.toLowerCase())||[],d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bI)return bI.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("
").append(c.replace(bB,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bC.test(this.nodeName)||bw.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(bt,"\r\n")}}):{name:b.name,value:c.replace(bt,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bL,isLocal:bx.test(bM[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bO(bJ),ajaxTransport:bO(bK),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bR(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bS(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bF,bG)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bv.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bu,"").replace(bz,bM[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bD),e.crossDomain==null&&(q=bH.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bM[1]||q[2]!=bM[2]||(q[3]||(q[1]==="http:"?80:443))!=(bM[3]||(bM[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bP(bJ,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!by.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(bA.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bE,"$1_="+w);e.url=x+(x===e.url?(bA.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bP(bK,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bQ(g,a[g],c,f);return e.join("&").replace(br,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bT=d.now(),bU=/(\=)\?(&|$)|\?\?/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bT++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bU.test(b.url)||f&&bU.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bU,l),b.url===j&&(f&&(k=k.replace(bU,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bV=d.now(),bW,bX;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bZ()||b$()}:bZ,bX=d.ajaxSettings.xhr(),d.support.ajax=!!bX,d.support.cors=bX&&"withCredentials"in bX,bX=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),!a.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bW[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bW||(bW={},bY()),h=bV++,g.onreadystatechange=bW[h]=c):c()},abort:function(){c&&c(0,1)}}}});var b_={},ca=/^(?:toggle|show|hide)$/,cb=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cc,cd=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(ce("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:ce("show",1),slideUp:ce("hide",1),slideToggle:ce("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!cc&&(cc=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=(e==="absolute"||e==="fixed")&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=ch.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!ch.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=ci(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=ci(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window); \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-ui-1.8.11.custom.css b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-ui-1.8.11.custom.css new file mode 100644 index 0000000..945876f --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-ui-1.8.11.custom.css @@ -0,0 +1,318 @@ +/* + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.ui-widget-content a { color: #333333; } +.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Slider 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; } \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-ui-1.8.11.custom.min.js b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-ui-1.8.11.custom.min.js new file mode 100644 index 0000000..09a60f3 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/ThirdParty/jquery-ui-1.8.11.custom.min.js @@ -0,0 +1,99 @@ +/*! + * jQuery UI 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.11",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106, +NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this, +"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position"); +if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f, +"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h, +d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}}); +c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate); +if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); +;/* + * jQuery UI Position 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Position + */ +(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, +left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= +k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= +m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= +d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= +a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), +g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); +;/* + * jQuery UI Slider 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */ +(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");a.disabled&&this.element.addClass("ui-slider-disabled ui-disabled"); +this.range=d([]);if(a.range){if(a.range===true){this.range=d("
");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("
");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("").appendTo(this.element).addClass("ui-slider-handle"); +if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur(); +else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e= +false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h=== +b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"); +this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b, +g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true}, +_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a; +if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value= +this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max}, +_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate); +if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1, +1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.11"})})(jQuery); +; \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TopoSortDFS.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TopoSortDFS.html new file mode 100644 index 0000000..a199bb5 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TopoSortDFS.html @@ -0,0 +1,75 @@ + + + + + + Topological Sort (DFS) Visualization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + +
+
+ + + + + +
+ + +
+
+ +
+ + + +
+ + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TopoSortIndegree.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TopoSortIndegree.html new file mode 100644 index 0000000..9303228 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/TopoSortIndegree.html @@ -0,0 +1,75 @@ + + + + + + Topological Sort (Indegree) Visualization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + +
+
+ + + + + +
+ + +
+
+ +
+ + + +
+ + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Trie.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Trie.html new file mode 100644 index 0000000..f6bf05b --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/Trie.html @@ -0,0 +1,71 @@ + + + + + + Trie Visualization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + +
+
+ + + + +
+ + +
+
+ +
+ + + +
+ + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/USFlogo.jpg b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/USFlogo.jpg new file mode 100644 index 0000000..5b14b7d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/USFlogo.jpg differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/VisualizationLibrary b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/VisualizationLibrary new file mode 100644 index 0000000..d92d593 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/VisualizationLibrary @@ -0,0 +1,11 @@ +function addJavascript(jsname, pos) { + var th = document.getElementsByTagName(pos)[0]; + var s = document.createElement('script'); + s.setAttribute('type','text/javascript'); + s.setAttribute('src',jsname); + th.appendChild(s); +} + +addJavascript('CustomEvents.js', 'head'); +addJavascript('ObjectManager.js', 'head'); +addJavascript('AnimationMain.js', 'head'); diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/about.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/about.html new file mode 100644 index 0000000..63f9a95 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/about.html @@ -0,0 +1,119 @@ + + + + Data Structure Visualization + + + + + +
+

Data Structure Visualizations

+ + +
+ +

Visualizing Algorithms

+ +The best way to understand complex data structures is to see them in action. We've developed interactive animations for a +variety of data structures and algorithms. Our visualization tool is written in javascript using the HTML5 canvas element, +and run in just about any modern browser -- including iOS devices like the iPhone and iPad, and even the web browser in +the Kindle! (The frame rate is low enough in the Kindle that the visualizations aren't terribly useful, but the tree-based +visualizations -- BSTs and AVL Trees -- seem to work well enough) + +

+Check the Algorithms menu for all of the latest javascript implementations. + +

How to Use the Visualizations

+ +This visualizations are meant to be fairly self- explainitory, though there are some subleties for advanced usage. Take a look at a +typical visualization, for Binary Search Trees: + +

+ +BST Screenshot +
+ +

Algorithm Specific Controls

+At the top of the screen (boxed in red in the above screenshot) are the algorithm specific controls -- these will change depending upon +what algorithm you are visualizing. In this example, you could insert, delete, or find an element in the BST by entering text in the +appropriate field and either pressing return or clicking the relevant button. The tree can be printed by clicking the print button. +Once you give a command, the visualiztion will start, and can be controlled by the general animation controls at the bottom of the screen. + +

General Animation Controls

+ +
    +
  • Skip Back If you are in the middle of an animation, this button will completly undo the current command. If you are +not in the middle of an animation, this button will undo the previous command
  • +
  • Step Back This button is only active if you have paused the current animation (using the play/pause button). Step back +one step in the current animation. If you are not currently animating, step back into the previous command. You could use this button +(with sufficient keypresses) to back up through the entire history of everything you've done
  • +
  • Play/Pause Toggle between play mode (in which the algorithm runs free until it completes) and paused mode (where you need to +press the Step Forward or Step Back button to advance the animation)
  • +
  • Step Forward This button is only active if you have paused the current animation (using the play/pause button), and the current +animation has not yet completed. Step +forward one step in the current animation.
  • +
  • Skip Forward This button is only active if the current animation has not completed. Skip to the end of the current animation +
  • +
  • Animation Speed (slider) Change the speed of the animation. The value of this slider is saved in a cookie, so you should +only need to set it once if you have a preferred speed
  • +
  • w, h, Chnage Canvas Size Change the width / height of the display area. While the change is immediate, the animations will +not be centered in this new field until you reload the page. This will clear out the currnet animation, but the width and hight values +are also saved in a cookie, so you should only need to change this field once, and then everything should work well if you are on +a smart phone or a desktop with loads of screen real estate. +
  • +
  • Move Controls Toggle between the general controls being at the top or bottom of the webpage
  • + +
    + +Note that it can be easy to confuse yourself by stepping forward an backwards through an animation -- you can confuse the next +step in the animation with the previous step, and misunderstand how the algorithm works. You may wish to only step +forward when you are first delving into a particular algorithm. + +
+ + +

Java/Swing Version

+This work is based on visualizations that we created in Java using Swing -- that code is still available here, +though that code is no longer being maintained. There are a few algorithms that we have not yet ported to the new system, +so the older version may still be of use. + +

Flash Version

+We have also developed a flash version of the visualizations, which contains a subset of +the algoritms developed in javascript. The Flash version is not as well supported as the main javascript version, +but we will keep the flash version available for those who may get a better frameate out of flash than javascript. +However, the javascript versions are the preferred ones, and will get updates and bug fixes the quickest. + +

Writing your Own

+ The tutorial for creating your own visualizations is now online! +All source code is available there as well. If you want to create your own visualizations, but are having trouble +getting things to work, please let me know. Everything is licensed under FreeBSD, and you +can use it for whatever you like. Please let me know if you using the code -- I'm curious to see what +it does in the wild. + +
+ + +
+ + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/bugfeature.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/bugfeature.html new file mode 100644 index 0000000..322e29a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/bugfeature.html @@ -0,0 +1,127 @@ + + + + Data Structure Visualization + + + + +
+

Data Structure Visualizations

+ + +
+ +

Known Bugs

+ +There are likely a whole host of bugs and issues with this software -- it should be considred "Beta" for the moment. Here are +the ones we know about: + +
    + +
  • DeleteMin fails on a heap with a single element.
  • +
      +
    • Fixed on 12/19/2013
    • +
    +
  • None of the visualizations work for older versions of explorer
  • +
      +
    • Fixed on 8/23/2012. Thanks to Stefan German for fiding this one.
    • +
    + + + +
  • Putting a semicolon in any of the input fields causes the application to die
  • +
      +
    • Fixed on 5/3/2011. Semicolons can no longer be entered. Thanks to Stefan German for fiding this one.
    • +
    +
  • BST and AVL trees have broken undos in HTML5 version
  • +
      +
    • Fixed on 5/3/2011.
    • +
    + +
  • Find and Delete broken in open hashing + +
  • +
      +
    • Fixed on 5/10/2011. (thanks to Eduardo Bonet, of Santa Catarina Federal University, Brazil, for finding this one!)
    • +
    + + + +
  • All algorithms that compute an ordering (BST, AVL Trees, etc) don't sort floating point numbers correctly -- 9.2 > 10.3
  • +
      +
    • This one is a design decision -- since those algoritms can take any string, the decision was made to sort based on lexicographic order. +We tried to mitigate confusion somehwat by automatically converting positive integers into equivalent numbers with leading zeroes, so that positive +integers would always be ordered as expected (though negative numbers are alas off). It turns out that if you are trying to sort a group of any strings, + using a mixed comparison strategy gets confusing +fast -- how should 10.4 compare to 3.1.2? What about 3A -- is that a string or a hexidecimal number? +What about AF? Should BC come before or after AFF? We made the executive decision to just do string comparisons. +
    +
  • When running connected components, if you run the algorithm, then undo, then run it again, the application breaks. We're working on a fix -- +the current workaroud is to create a new graph after undo before running the algorithm again.
  • +
      +
    • Fixed on 5/10/2011.
    • +
    + + +
  • Undoing deleting an element from a B-Tree or B+ tree broken + +
  • +
      +
    • Fixed on 6/13/2011.
    • +
    + + +
  • Radix sort broken on Safari browser + +
  • +
      +
    • Fixed on 6/13/2011.
    • +
    + + + +
  • Various typos
  • +
      +
    • Please continue to send in any typos you see, and I will correct them as I get to them (at a somewhat lower priority than functionaility +bugs, of course). Typo corrections will not appear on this page. +
    • + +
    +
+ + +

Featue Requests

+ +Find a bug? Have a feature or new algorithm to request? Send an email to galles <at> usfca <dot> edu + +











+ + + +
+ + +
+ + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/contact.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/contact.html new file mode 100644 index 0000000..ec613b2 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/contact.html @@ -0,0 +1,73 @@ + + + + Data Structure Visualization + + + + +
+

Data Structure Visualizations

+ + +
+ +

Contact Information

+ + +
+
+Do you find this tool useful? Find a bug? Have a feature request? Drop me +a line and let me know! + +
+
+ +
+David Galles
+Harney Science Center, Rm 542
+Department of Computer Science
+ +University of San Francisco
+2130 Fulton St.
+San Francisco, CA 94117-1080 USA
+
+galles (at) usfca.edu
+
+ +
+
+
+
+
+ +











+ + + +
+ + +
+ + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/debug.log b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/debug.log new file mode 100644 index 0000000..0322136 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/debug.log @@ -0,0 +1 @@ +[0110/001719.927:ERROR:directory_reader_win.cc(43)] FindFirstFile: ϵͳҲָ· (0x3) diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/faq.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/faq.html new file mode 100644 index 0000000..674d352 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/faq.html @@ -0,0 +1,127 @@ + + + + Data Structure Visualization + + + + +
+

Data Structure Visualizations

+ + +
+ +

Frequently Asked Questions

+ +
    +
  1. Sometimes when I insert a element into a BST or other ordered data structure, I get strange behavior -- "-2" seems to be smaller +than "-3". What's going on?
  2. + +
      +
    • We use string comparisons for everything, so "-2" is in fact less than "-3" lexicographically. +We tried to mitigate confusion somewhat by automatically converting positive integers into equivalent numbers with leading zeroes, + so that positive integers would always be ordered as expected (though negative numbers are alas off). + It turns out that if you are trying to sort a group of any strings, using a mixed comparison strategy gets confusing +fast -- how should 10.4 compare to 3.1.2? What about 3A -- is that a string or a hexidecimal number? +What about AF? Should BC come before or after AFF? We made the executive decision to just do string comparisons everywhere +for consitency. +
    + + +
  3. How can I get this to work on my cellphone, which has a very small screen?
  4. + +
      +
    • +If you change the canvas size to something that seems reasonable for your device, we will use a cookie to remember your +preferred size. Then reload the page, and you should be set! Cell Phones are a little tricky, since their screens are so +small -- the iPhone 4 seems to work well for most algorithms, with a width of 500 and a height of 300 (though the +sorting algorithms really require a width of 900 to see everything, and graph algorithms need a width of 1000 to see +everything.) With iOS devices, you can set the canvas size to a larger value than can be dipslayed at once, though +you will then need to do a bit of zooming in/out or scrolling. +
    • +
    + +
  5. Wait ... you are using cookies?
  6. +
      +
    • +Only for remembering your preferred width/height/speed. Everything will still work if you disable cookies, you just +won't get the extra convienence of having the exact right size for your device. We aren't doing tracking of any kind. +
    • +
    + +
  7. I think I've found a bug ... +
      +
    • Please email me any bug reports, at galles <at> usfca <dot> edu. The more specific, the better (that is, +excatly what sequence of operations lead to the undesired behavior). + +
    + + +
  8. Can I use these materials in my classes? +
      +
    • Certainly! I'd prefer that you just link to my pages rather than cache anything locally so that your +students will get the most up-to-date version of everything. If you do use this in your class, please drop me +a line to let me know about it, I'm curious to see who else will find this useful. + +
    + +
  9. Can I use this material as a base for my own visualizations?
  10. +
      +
    • Yes! See the source code page for a simple tutorial and a tarball with everything you need. +Note that updates to the source code release are not made as quickly as updates to the visualziations themselves, +so not all of the visualziations may be in the tarball at any given time. I plan to update the source code at +least once a month or so, so it shouldn't get too far out of date. If you do use my code, +please leave in the copyright information at the beginning of each source file, and put a link to these pages from the page +where your visualizations are located. If you create something really cool, let me know and I can link to it. +
    • +
    + + +
  11. What's next?
  12. +
      +
    • Converting the remainder of the java-only visualziations to javascript (only Huffman Coding and lists left!)
    • +
    • Adding a suite of simple recursion visualziations (factorial, reversing a list, generic tree operations, etc). +Similar to the Dynamic Programming: Fibonacci visualziation, but with some more detail +(contents of the call stack, etc)
    • +
    • Adding more Dynamic Programming visualziations
    • +
    • Adding visualzations of translations and rotations of simple objects (in 2D, or 3D if I'm feeling ambitious). +Mostly because those visualziations would be handy for my Game Engineering classes.
    • + +
    + + +
+
+
+
+ + + + +
+ + +
+ + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/favicon.ico b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/favicon.ico new file mode 100644 index 0000000..263fd77 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/favicon.ico differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/flash.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/flash.html new file mode 100644 index 0000000..c495198 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/flash.html @@ -0,0 +1,18 @@ + + + + +Untitled Document + + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/scratch b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/scratch new file mode 100644 index 0000000..e69de29 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/slideTest.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/slideTest.html new file mode 100644 index 0000000..312d947 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/slideTest.html @@ -0,0 +1,38 @@ + + + + + jQuery UI Slider - Default functionality + + + + + + + + + + + + + +
+ +
+ +
+ + + +
+

The basic slider is horizontal and has a single handle that can be moved with the mouse or by using the arrow keys.

+
+ + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/source.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/source.html new file mode 100644 index 0000000..ad426e1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/source.html @@ -0,0 +1,1217 @@ + + + + + Data Structure Visualization + + + + +
+

Data Structure Visualizations

+ + +
+ +

Source Code

+ +You can download the complete source for the HTML5/Javascript version of the visualizations (both compressed and uncompressed) here: + +
+ + + +
+ +A few notes / warnings: + +
    +
  1. Do not try to look at the code to understand the algorithms. I have done one or two tricky +things to get the visualizations to work property that rather obscure the algorithms themselves. Your +favorte textbook, or even wikipedia, is a better bet for appropriate source code.
  2. +
  3. Like all software projects, this one is a bit of a living thing -- it started life as a Java project, +was rewritten in ActionScript3 (that is, flash), and then ported to Javascript. It was also my opportunity to +learn flash and javascript, so by the time I figured out the best way to do things, half of the software was +already written. I've done some going back to clean stuff up, but there is still a quite a lot of ugliness. +Next time all my code will be pretty :).
  4. +
+ + +

Visualization Creation Tutorial

+ +To creeate a new visualization, you need to create a javascript file and an HTML file. The HTML file should + just be copied from a template, changing only one or two items (like the name of the javascript file). + Examples of the HTML template and how to change it are at the end of this tutorial. + + In the javascript file, you will create a function (an object, really, but functions are objects in javascript) that: + +
    +
  1. Creates any appropriate controls to control you visualization (inserting elements, deletig elements, etc)
  2. +
  3. Creates callbacks for these controls that implement the visualizations. The visualizations are implemented +by sending an array of strings to the animation manager -- the animation manager will then implement the animation, and +handle all of the animation controls for you
  4. +
  5. Listen for an undo event from the animation manager. When an undo event is detected, roll back the last operation
  6. +
+ + + +

Using Algorithm function

+ +Creating the javascript function is stil farily complicated, even when using the rest of the library. + +Many of the ugly details can be automated if your function "subclasses" the Algorithm function (located +in AlgorithmLibrary/Algorithm.js +(which is sort of a faux "class"). Consider the skeleton "MyAlgorithm" function included in the tarfile: + + + +Looking at various pieces of the file in turn: +
+
+Copyright: Code is released under in a FreeBSD license. + +
+
+// 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
+
+
+ +Next, the algorithm definition. We are doing a sort of "faked" inheritance within javascript. +We define our function, set the prototype of our function to the prototype of our superclass, +reset the constructor to be our own constructor, and then cache the superclass prototype, +for simulating a java-style "super" call. Notice that to make inheritance work well on +counstructors, we don't do anything in the main constructor function other than call an init +function (that way we can have our init function call the init function of the superclass. +Yes, this is a bit of a hack.) + +
+
+function MyAlgorithm(am, w, h)
+{
+	this.init(am, w, h);
+}
+
+MyAlgorithm.prototype = new Algorithm();
+MyAlgorithm.prototype.constructor = MyAlgorithm;
+MyAlgorithm.superclass = Algorithm.prototype;
+
+
+ +Next, we have our constructor. In general, we will need to do the following +in our counstructor: + +
    +
  • Call the superclass counstructor. Note the syntax, it's a little odd, +but we are forcing javascript into an tradtional object-oriented paradigm, so it will +complain a little at us.
  • +
  • Add necessary controls
  • +
  • Initialize our "Memory Manager". For the most part, we will use a very +simple memory manager -- the old Pascal-style "Never free" memory manager. Start the +free list at 0, and then increment it every time you need a new piece of memory.
  • +
  • Initialize any data structures we will be using
  • + +
+ +
+
+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.
+}
+
+
+ +Next we have the function to add controls. There are several helper functions to add +controls. See the Algorithm.js file for more +information on these helper functions. + +
+
+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)
+}
+
+
+ +We will need to "override" the reset method. Whenever the animation manager wants to +undo an operation: + +
    +
  • This reset method is called, which resets the state of your object to exactly how it was +before any operations were performed +
  • All of the operations up until the last one are replayed (though the animation information is +thrown away
  • +
  • We end up in the same state that we were in right before the last operation was done
  • +
+ +
+
+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, doing actual work + +
+
+//////////////////////////////////////////////
+// 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;
+//}
+
+
+
+ + +Enabling, disabling UI + +
+
+// 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 = true;
+	}
+}
+
+
+ +Script to start everything + +
+
+////////////////////////////////////////////////////////////
+// Script to start up your function, called from the webapge:
+////////////////////////////////////////////////////////////
+
+var currentAlg;
+
+function init()
+{
+	var animManag = initCanvas();
+	currentAlg = new MyAlgorithm(animManag, canvas.width, canvas.height);
+	
+}
+
+
+ +

Animation Commands

+ +The commands that we give to the animatino manager are a list (array) of strings. Each string starts with +the name of the command (case-insensitive) followed by a list of arguments, separated by the token <;>. +The first argument of (almost) every command is the ID of the object you want to create or access. So, the string +to Move element 37 to position (100, 120) would be: + +
    +
  • "Move<;>37<;>100<;>120"
  • +
+Commands can be separated into two groups: Commands that create animated objects, and commands +that manipulate previously created objects. + +

Object Creation and Deletion Commands

+ +Object creation commands take as a first argument an integer +representing the index of the object to create. This integer must not be the same as another +object that is currently active in the system (though you can reuse numbers once the objects have been +deleted). Like all commands, the creation commands have some required and some optional parameters. + +
+
    +
  • CreateCircle: objectID, label, [initial_x, initial_y]
  • +
      +
    • objectID: Non-negative integer that represents the ID of this object. Must be different from any +ID currently active. Should be as small as posslbe for better performance.
    • +
    • label: the label that appears in the middle of the circle. It may contain end of line (\n) characters, +which allows you to place a multi-line label in the circle. Labels are centered in circles.
    • +
    • initial_x: (optional, defaults to 0) the initial x position of the circle
    • +
    • initial_y: (optional, defaults to 0) the initial u position of the circle
    • +
    +
  • CreateRectange: objectID, label, width, height, [initial_x, initial_y, xJustify, yJustufy, backgroundColor, foregroundColor]
  • +
      +
    • objectID: Non-negative integer that represents the ID of this object. Must be different from any +ID currently active. Should be as small as posslbe for better performance.
    • + +
    • label: the label that appears in the middle of the rectangle. It may contain end of line (\n) characters, +which allows you to place a multi-line label in the rectangle. Labels are centered in rectangles.
    • +
    • width: The width of the rectangle, in pixels
    • +
    • height: The height of the rectangle, in pixels
    • +
    • initial_x: (optional, defaults to 0) the initial x position of the rectangle
    • +
    • initial_y: (optional, defaults to 0) the initial u position of the rectangle
    • +
    • xJustify: (optional, defaults to "center"). One of "center", "left", "right" -- If the rectangle is at location (x, y), +does x stand for the left, center, or right of the rectangle
    • +
    • yJustify: (optional, defaults to "center"). One of "center", "top", "bottom" -- If the rectangle is at location (x,y0 does + y stand for the top, center, or bottom of the rectangle
    • +
    • foregroundColor: The initial color of the foregorund of the rectangle, using string representations of HTML colors ("#FF0000" for red, "#00FF00" for green, + and so on). Defaults to black +
    • backgroundColor: The initial color of the background of the rectangle, using HTML colors (#FF0000 for red, #00FF00 for green, + and so on). Defaults to white. +
    + +
  • CreateHighlightCircle: objectID, color, [initial_x, initial_y, radius]
    +A highlight circle is much like a standard circle, except that it has no label, and no background color, so that +it does not obscure other objects like a circle does. +
      +
    • objectID: Non-negative integer that represents the ID of this object. Must be different from any +ID currently active. Should be as small as posslbe for better performance.
    • +
    • color: The initial color of the circle, using HTML colors ("#FF0000" for red, "#00FF00" for green, + and so on) + +
    • initial_x: (optional, defaults to 0) the initial x position of the circle
    • +
    • initial_y: (optional, defaults to 0) the initial u position of the circle
    • +
    • radius: (optional, defaults to 20) The radius of the circle. + +
    +
  • CreateLabel: objectID, label, [initial_x, initial_x, centered]
  • +
      +
    • objectID: Non-negative integer that represents the ID of this object. Must be different from any +ID currently active. Should be as small as posslbe for better performance.
    • +
    • label: the text of the label. It may contain end of line (\n) characters, +which allows you to place a multi-line labels.
    • +
    • initial_x: (optional, defaults to 0) the initial x position of the label
    • +
    • initial_y: (optional, defaults to 0) the initial y position of the label
    • +
    • centered: (optional, defaults to true) true or 1 if the label should be centered, false or 0 if it should not.
    • + +
    + +
  • CreateLinkedList: objectID, label, width, height, [initial_x, initial_y, linkPercent, verticalOrientation, linkPosEnd, numLabels] +
      +
    • objectID: Non-negative integer that represents the ID of this object. Must be different from any +ID currently active. Should be as small as posslbe for better performance.
    • +
    • label: The label inside this linked list element (or the first label, if there are more than one) +
    • width: The width of the linked list element, in pixels
    • +
    • height: The height of the linked list element, in pixels
    • +
    • initial_x: (optional, defaults to 0) the initial x position of the linked list element
    • +
    • initial_y: (optional, defaults to 0) the initial y position of the linked list element
    • +
    • linkPercent: (optional, defaults to 0.25) The percentage of the linked list element that the outgoing pointer takes up.
    • +
    • verticalOrientation: (optional, defaults to true). Should the linked list element be vertial (true) or horizontal (false)
    • +
    • linkPosEnd: (optional, defaults to false). Should the poiner appear at the bottom or left of the linked list element (true), or the +top or right of the linked list element (false)
    • +
    • numLabels: (optional, defaults to 1). The number of labels that the linked lists element can hold. See the adjacency +list implementat of a graph visualization for an example of a linked list element with more than 1 label. +
    + +
  • CreateBTreeNode: objectID, widthPerLabel, height, numLabels, inital_x, initial_y, backgroundColor, foregroundColor
  • +Somewhat special-purpose animated object created for B-Trees. Single rectangle containing any number of labels, with no dividing +lines between the labels. Edges can be attached between each label, and to the left of the leftmost label, and to the right of the rightmost +label. See the BTree and B+ Tree visualizations for examples. +
      +
    • objectID: Non-negative integer that represents the ID of this object. Must be different from any +ID currently active. Should be as small as posslbe for better performance.
    • +
    • widthPerLabel: The width of the B-Tree node is the number of labels * the width per label. Value is in pixels.
    • +
    • height: Height of the B-Tree node in pixels
    • +
    • numLabels: The number of labels in the BTree node.
    • +
    • initial_x: The initial x position of the B-Tree node
    • +
    • initial_y: The initial y position of the B-Tree node
    • +
    • backgroundColor: The initial color of the background of the rectangle, using HTML colors (#FF0000 for red, #00FF00 for green, + and so on)
    • +
    • backgroundColor: The initial color of the forground of the rectangle, using HTML colors (#FF0000 for red, #00FF00 for green, + and so on)
    • +
    + +
  • Delete: objectID
  • +
      +
    • objectID: The ID of the object to delete. All edges incident on this object will be removed. (If the delete is undone, then +all such edges will be restored). Once an Animated Element has been deleted, its ID is free to be used again. +Note that overly complicated ID management (which is really memory management, since IDs are just indicies into a +"memory array" of active animated objects) is not necessarily recommended, since it can lead to some subtle bugs. +
    +
+ +Note that creation of an object using an objectID that already is in use will throw an exception. +Deleting an ID that is not currently in use will also throw an exception. + +

Object Manipulation Commands

+ + +
    +
  • Move: objectID, toX, toY
  • +Move the object smoothly over the next step from the current position to +the new position +
      +
    • objectID: The ID of the object to move. The object must exists, or an exception will be +thrown
    • +
    • toX: The new X location to move to
    • +
    • toY: The new Y location to move to
    • +
    + +
  • SetPosition: objectID, toX, toY
  • +Move the object immediately to the new position at the beginning of the next step +
      +
    • objectID: The ID of the object to move. The object must exists, or an exception will be +thrown
    • +
    • toX: The new X location to move to
    • +
    • toY: The new Y location to move to
    • +
    + + + +
  • SetForegroundColor: objectID, color
  • +Sets the foreground color (outline color and label color) of an object. Note that if +an object has several labels this will set the color of all labels. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • color: New foreground color (string representing HTML color, like "#ff0000")
    • +
    + + +
  • SetBackgroundColor: objectID, color
  • +Sets the background color of current object. Note that if +an object has several labels this will set the color of an object. +
      +
    • objectID: The ID of the object to modify. The object must exist, or an exception will be +thrown
    • +
    • color: New background color
    • +
    + +
  • SetHighlight: objectID, highlightVal
  • +Mark an object as either highlighted or unhighlighted, based on the value of highlightVal. +Objects that are highlighted will pulse red. Any object can be highlighted (thought labels +are slightly harder to read when highlighted) Note that if an object is left highlighted +after an animation is ended, it will not pulse until the animation starts again. Edges +can be highlighted using the highlight edge command. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • highlightVal: 1 or true, turn on highlighting. 0 or false, turn off highlighting.
    • +
    + + +
  • SetText: objectID, newText, [textIndex]
  • +Sets the value of the label associated with the object (the printing withing a circle, for instance). +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • newText: The new text of the label
    • +
    • textIndex: (optional, defaults to 0) Index of the text label to change. Only used in +objects that have more than one text label (B-Tree nodes, Linked List nodes). If the object does +not support multiple labels, this is ignored.
    • +
    + +
  • SetAlpha: objectID
  • +Sets the alpha (transparency) of the object. 0 is completely transparent, 1 is completely opaque. Works for all objects. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown.
    • +
    + + +
  • SetHeight: objectID, newHeight
  • +Sets the height (in pixels) of the object. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • newHeight: The new height of the object.
    • +
    + + +
  • SetWidth: objectID, newWIdth
  • +Sets the width (in pixels) of the object. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • newWidth: The new width of the object.
    • +
    + + + +
  • SetTextColor: objectID, newColor, [textIndex]
  • +Sets the color of the label associated with the object +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • newColor: The new color to set. As with all colors, should be a html color string
    • +
    • textIndex: (optional, defaults to 0) If the object contain multiple labels (such as a linked-list node, +or a B-Tree node) determine which label to change the color of. If the object only has one label, this parameter +is ignored.
    • +
    + + +
  • SetNull: objectID, nullValue
  • +Currently only used for linked-list elements. Should the area set aside for the pointer in the +linked list object be drawn as a null pointer (slash through the field)? This should probably +be automated (draw the slash if and only if the node is not connected to anything), but for now +this must be done manually. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • nullValue: 0 or false for do not draw the slash, 1 or true for draw the slash.
    • +
    + + +
  • SetNumElements: objectID, numElements
  • +Currently only used for B-Tree nodes. Changes the number of labels stored in this B-tree node. +Should probably be extended to at least Linked-list nodes. +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • numElements: integer, the number of elements this B-Tree node should have
    • +
    + +
  • AlignRight: object1ID, object2ID
  • +Align object1 so that it is immediately to the right of object2. Very handy for lining up labels +(where you don't necessarily know the width of the label), but can be used with any two objects. +
      +
    • object1ID: The ID of the object to move. The object must exists, or an exception will be +thrown
    • +
    • object2ID: The ID of the object used to align object1. The object must exists, or an exception will be +thrown
    • +
    + +
  • AlignLeft: object1ID, object2ID
  • +Align object1 so that it is immediately to the left of object2. Very handy for lining up labels +(where you don't necessarily know the width of the label), but can be used with any two objects. +
      +
    • object1ID: The ID of the object to move. The object must exists, or an exception will be +thrown
    • +
    • object2ID: The ID of the object used to align object1. The object must exists, or an exception will be +thrown
    • +
    + +
  • AlignTop: object1ID, object2ID
  • +Align object1 so that it is immediately on top of of object2. Very handy for lining up labels +(where you don't necessarily know the width of the label), but can be used with any two objects. +
      +
    • object1ID: The ID of the object to move. The object must exists, or an exception will be +thrown
    • +
    • object2ID: The ID of the object used to align object1. The object must exists, or an exception will be +thrown
    • +
    + +
  • AlignBottom: object1ID, object2ID
  • +Align object1 so that it is immediately below object2. Very handy for lining up labels +(where you don't necessarily know the width of the label), but can be used with any two objects. +
      +
    • object1ID: The ID of the object to move. The object must exists, or an exception will be +thrown
    • +
    • object2ID: The ID of the object used to align object1. The object must exists, or an exception will be +thrown
    • +
    + + + +
+ +

Edge Manipulation Commands

+ +Edges are manipulated by giving the two objects associated with the edge. While edges +can be graphically directed or undirected, all edges under the hood have a direction, +which is the direction that they were given when the edge was created. There can +only be one edge from any object to any other object (though there can be +an edge from object1 to object2, and a different edge from object2 to object1.) Edges +are always referred to by two IDs - the objectID of the "from" object, followed by the +objectID of the "to" object. Any object can be connected to any other object. + + +
    +
  • Connect: fromID, toID, [linkColor, curve, directed, label, anchorPosition]
  • +
      , +
    • fromID: The ID of the object at the tail of the new edge
    • +
    • toID: The ID of the object at the head of the new edge
    • +
    • linkColor: (optional, defaults to "#000000") The color of the edge
    • +
    • linkColor: (optional, defaults to false) true for a diected edge, false for an undirected edge
    • +
    • curve: (optional, defaults to 0.0) The "curviness" of the edge. 0.0 is perfectly straight, positive values +arc to the right, negative values arc to the left.
    • +
    • directed (optional, defaults to true). True if the edge is directed, false if the edge is undirected
    • +
    • label (optional, defaults to ""). The label that appears along the edge (useful for things like edge +costs in graphs)
    • +
    • anchorPosition (optional, defaults to 0) If the edge could have more than one attachment +postion at the "from" node, (currently only used for B-Tree nodes, but could well be expanded to things like +doubly-linked lists) the index of the attachment position to use. Ignored for animated objects that +do not have multiple attachment positions
    • +
    + +
  • Disconnect: fromID, toID
  • +Removes an edge between two elements. If there is no edge, then this operation is a no-op. +
      +
    • fromID: The ID of the "From" direction of the edge
    • +
    • toID: The ID of the "To" direction of the edge
    • +
    +Note that even "undirected" edges have a "from" and a "to" -- determined by how the +edge was created using the Connect command. + +
  • SetAlpha: objectID
  • +Sets the alpha (transparency) of the object. 0 is completely transparent, 1 is completely opaque +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    + +
  • SetEdgeHighlight: fromID, toID, highlightVal
  • +Mark an edge as either highlighted or unhighlighted, based on the value of highlightVal. +Edges that are highlighted will pulse red. +
      +
    • fromID: The ID of the "From" direction of the edge
    • +
    • toID: The ID of the "To" direction of the edge
    • +
    • higlightVal: 0 or false, turn of higlighting. 1 or true, turn on highlighting.
    • +
    + +
+ +

Special Commands

+ +
    +
  • Step: <No parameters>
  • +The step command allows you to keep everything from happening at once. The way that most +animations will work is that you will create a group of objects, then do a step, then do +some movements, then do a step, then do more movements, then do a step, and so on. All +commands that appear between adjacent steps will happen simultaneously. Each step represents where +the animation will pause when it is in single-step mode. + + +
  • SetLayer objectID, newLayer
  • +Sets the layer of the object. All objects default to layer 0, and the "shown" layer always defaults +to 0. You can change the layers of different objects, and then change the list of which layers +are currently shown, to show or hide objects dynamically. (This is often useful for allowing the +user to show or hide information, or to alternate between different versions of a representation). +An object will only appear if its layer is one of the layers listed to be shown. An edge will +only appear of each of the objects that it connect are to be shown. While commands cannot be executed +while an animation is running, the global set of visible layers can be changed while an animation is running +
      +
    • objectID: The ID of the object to modify. The object must exists, or an exception will be +thrown
    • +
    • layer: The new layer for this object. Each object must live in one and only one layer +(though any combination of layers can be shown at any given time)
    • +
    +
+ +

Simple Stack Example

+ +Everything make sense so far? Time for a simple, complete example. A simple stack visualization can be found at: + + + +Looking at the complete SimpleStack.js file in its entirety: +

+All code released under a FreeBSD license +
+
+// 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
+
+ + + +Next up is the Initial setup. The first several lines of any visualization javascript will look like this, with +SimpleStack replaced by whatever function you are writing + +
+
+function SimpleStack(am, w, h)
+{
+	this.init(am, w, h);
+}
+
+SimpleStack.prototype = new Algorithm();
+SimpleStack.prototype.constructor = SimpleStack;
+SimpleStack.superclass = Algorithm.prototype;
+
+ + +The next items in the file are some constants. We placed them in the function's namespace +to avoid symbol clashes: + + +
+
+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"
+
+ + +Next up is the constructor. Technically, the constructor was first: + +
+function SimpleStack( ...
+
+ +However, all of the work of the constructor is done in the init function -- that +way constructors of subclass can effectively call the constructors of their superclasses. +For the init function in this case, we need to do very little work. In this simple example +we are not adding any elements to the canvas at load time. All we need to do is set up our own +internal data structures. We are keeping track of two arrays -- an array that stores the actual +stack (stackValues), and an array that stores the objectIDs of the elements of the stack (stackID) + +
+
+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;
+}
+
+ + +Next up is the method to add algorithm controls and callbacks. The tricky bit here is that we can't do something like: + +
+this.popButton.onclick = this.popCallback
+
+ +to add our callbacks. Why not? This would pass in the proper function, but not the +proper contex -- essentially, it would be passing a pointer to the code of the function, +without saving the "this" pointer. So we need to bind the "this" pointer to our function before +we store it. + +
+
+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);	
+}
+
+ + +As a side note, here's the code for the bind function, located in CustomEvents.js + +
+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);
+	}
+}
+
+ +Moving on ... Next up is the reset function. All visualizations must implement the reset method. The reset +method needs to restore all of our variables to the state that they were in right after the call to init. +In our case, we only have 2 variables of importance. We could have recreated the arrays stackID and stackValues, but +that is not necessary in this case, since we don't care about the current values in those arrays -- we will write over any +value before we read it, once the stack top is 0. + +
+
+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;
+}
+
+ + +Next up, the callbacks. Note that we don't do any action directly on a callback -- instead, we use the +implementAction method, which takes a bound function (using the bind method) and a parameter, and them +calls that function using that parameter. implementAction also saves a list of all actions that have been +performed, so that undo will work nicely. + +
+
+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), "");
+}
+
+ + +Finally, we get to the actual meat of our visualization -- the code that does the work. Note that we are mostly +just implementing the action, using some calls to cmd to document what we are doing. +
+
+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;
+}
+
+ + +Almost done! Some code to enable / disable our algorithm controls while the animation is running... + +
+
+// 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;
+	}
+}
+
+ + +Finally, some boilerplate to get everything started. You can pretty much cut and paste the following +into your own code, replacing SimpleStack with your function: + +
+
+////////////////////////////////////////////////////////////
+// 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);
+	
+}
+
+ + +And we're done. We just need to create the appriate HTML file to enbed this in, and +we're good to go. + + +

HTML Template

+This visualization system is a combination of HTML and javascript -- you need a webpage to +embed the javascript, and that webpage needs the following items: + +
    +
  • A bunch of <script> tags in the header to load oll of the necessary scripts. These files need to be +included in the correct order, based on dependancies. (It would be nice if +javascript had a standard #include-like mechanism to avoid manually inserting all of these files +in the HTM. While there are some ways around +it -- dynamically inserting the <script> tags using javascript calls -- +not all browsers seem to work with these somewhat hacky methods. A brute-force inclusion +of all the files, in the proper order, works everywhere)
  • + +
  • An empty table with the id "algoControlSection" where the algorithm specific controls are to be placed
  • +
  • A canvas element, where the animations will appear
  • +
  • An empty table with the id "GeneralAnimationControls" where general animation controls are to be placed
  • +
  • An onload = "init();" command in the body tag to kick everything off
  • +
+ +The eaiest solition is just to use the following template, changing the values +that are specific to your application + + + +The template file is reproduced below, with the changes you need to make highlighted in red + + +
+
+<!DOCTYPE html>
+<html>
+    <head>
+        
+        <title>
+           Place your title here
+        </title>
+        
+        <!-- css sheet for how the page is laid out -->
+        
+        <link rel="stylesheet" href="visualizationPageStyle.css">
+            
+            
+        <!-- jqueury stuff.  Only used for the animation speed slider. -->
+        <link rel="stylesheet" href="ThirdParty/jquery-ui-1.8.11.custom.css">
+                
+        <script src="ThirdParty/jquery-1.5.2.min.js"></script>
+        <script src="ThirdParty/jquery-ui-1.8.11.custom.min.js"></script>
+                
+        <!-- Javascript for the actual visualization code -->
+        <script type = "text/javascript" src = "AnimationLibrary/CustomEvents.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/UndoFunctions.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/AnimatedObject.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/AnimatedLabel.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/AnimatedCircle.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/AnimatedRectangle.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/AnimatedLinkedList.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/HighlightCircle.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/Line.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/ObjectManager.js"> </script>
+        <script type = "text/javascript" src = "AnimationLibrary/AnimationMain.js"> </script>
+        <script type = "text/javascript" src = "AlgorithmLibrary/Algorithm.js"> </script>
+        <script type = "text/javascript" src = "Place path to your javascript file here"> </script> 
+                
+            
+     </head> 
+    
+    <body onload="init();" class="VisualizationMainPage">
+        
+        <div id = "container">
+            
+            <div id="header">  
+                <h1>Place your Header here </h1>
+            </div>
+            
+            <div = id = "mainContent"> 
+                
+                <div id = "algoControlSection">
+                    <!-- Table for buttons to control specific animation (insert/find/etc) -->
+                    <!-- (filled in by javascript code specific to the animtion) -->
+                    <table id="AlgorithmSpecificControls"> </table> 
+                </div>
+                
+                    <!-- Drawing canvas where all animation is done.  Note:  can be resized in code -->
+                                    
+                <canvas id="canvas" width="1000" height="500"></canvas>
+                
+                <div id = "generalAnimationControlSection">
+                    <!-- Table for buttons to control general animation (play/pause/undo/etc) ->
+                    <!-- (filled in by javascript code, specifically AnimationMain.js)  -->
+
+                    <table id="GeneralAnimationControls">  </table>     
+                </div>
+                
+            </div> <!-- mainContent -->
+            
+            <div id="footer">  
+                <p><a href="Algorithms.html">首页</a></p>
+            </div>
+
+        </div><!-- container -->
+    </body>
+</html>
+
+
+ +

Quirks and Advanced Techniques

+ +

Object Display Order

+ +If two object overlap, which one is placed on top? The animation system uses the following rules to determine draw order: + +
    +
  1. All non-highlighted items are drawn before all highlighted items +(so highlighted items will appear on top of non-highlighted items)
  2. +
  3. All items with the same highlight state are drawn in order of their identifiers (so objects with larger identifiers +will be drawn in front of objects with small identifiers)
  4. +
+ +This system is not terribly sophisticated, but it works well enough. You just need to be sure that if you want object A +to appear in front of object B, then object A has to have a higher object ID. If a more sophisticated system is required, +this may be modified in a future release. + + +

Debugging

+ +Developing in javascript? Firebug is a very fine (and very free!) javascript debugger. +However, there can be a problem with breakpoints. The animations in this system rely heavily on the javascript +setTimeout command. If a timeout is set, and then firebug hits a breakpoint, the timeout will be lost. Thus, hitting +a breakpoint in the wrong piece of code (pretty much anything in AnimationMain.js), will cause the animation to +stop. I've managed the use of setTimeout calls so that hitting a breakpoint in code that uses the animation libraries +(as opposed to code in the libraries themselves) should not cause this problem. + +
+ + +
+ + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/template.html b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/template.html new file mode 100644 index 0000000..1d0c1db --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/template.html @@ -0,0 +1,72 @@ + + + + + Place your Header here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + +
+
+ + + + + +
+ + +
+
+ +
+ + + +
+ + \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_diagonals-thick_18_b81900_40x40.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000..954e22d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_diagonals-thick_20_666666_40x40.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000..64ece57 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_flat_10_000000_40x100.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000..abdc010 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_flat_10_000000_40x100.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_100_f6f6f6_1x400.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 0000000..9b383f4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_100_fdf5ce_1x400.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_100_fdf5ce_1x400.png new file mode 100644 index 0000000..a23baad Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_100_fdf5ce_1x400.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_65_ffffff_1x400.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000..42ccba2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_gloss-wave_35_f6a828_500x100.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100644 index 0000000..39d5824 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_gloss-wave_35_f6a828_500x100.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_highlight-soft_100_eeeeee_1x100.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000..f127367 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_highlight-soft_75_ffe45c_1x100.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_highlight-soft_75_ffe45c_1x100.png new file mode 100644 index 0000000..359397a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-bg_highlight-soft_75_ffe45c_1x100.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_222222_256x240.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_222222_256x240.png new file mode 100644 index 0000000..b273ff1 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_222222_256x240.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_228ef1_256x240.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_228ef1_256x240.png new file mode 100644 index 0000000..a641a37 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_228ef1_256x240.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ef8c08_256x240.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ef8c08_256x240.png new file mode 100644 index 0000000..85e63e9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ef8c08_256x240.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ffd27a_256x240.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000..e117eff Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ffd27a_256x240.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ffffff_256x240.png b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000..42f8f99 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/timages/ui-icons_ffffff_256x240.png differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/visualPages.css b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/visualPages.css new file mode 100644 index 0000000..04b2122 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/visualPages.css @@ -0,0 +1,182 @@ +/* controlling the look of the left-hand menu */ + +body { + /*font: 100% Verdana, Arial, Helvetica, sans-serif; */ + /*background: #666666; */ + margin: 0; /* it's good practice to zero the margin and padding of the body element to account for differing browser defaults */ + padding: 0; +/* text-align: center; /* this centers the container in IE 5* browsers. The text is then set to the left aligned default in the #container selector */ + color: #000000; +} + + +.about { +margin-left:30px; + text-align:center; +} + + +.code { + + background: #EEEEEE; +} + + +.menu { + float:left; +/* height: 88%; */ + line-height:110%; + margin-left:-30px; +/* border-right:1px solid #004D99; /* solid grey; */ + padding:1em; + width:178px; +/* font-family: Helvetica, sans-serif; + color: #66EEEE; */ +} + +.menu ul { + list-style-type: none; +} + +.menu a { + font-weight: bold; + text-decoration: none; + color:#006633; +} + + +.content h1 { + color:#006633; +} + + +.content h2 { + color:#006633; +} + +.content h3 { + color:#006633; +} + + + +.content a { + //font-weight: bold; + text-decoration: none; + color:#006633; +} + +.content a:hover { + color:#ffCC33; +} + + + +.menu a:hover { + color:#ffCC33; +} + +.menu a:visited { +/* color:grey; */ +} + + + +.about a { + font-weight: bold; + text-decoration: none; + color:#006633; +} + +.about a:hover { + color:#ffCC33; +} + +.about a:visited { +/* color:grey; */ +} + + +.text, .personal { + margin: 0px 100px 100px 200px; + position: absolute; + font-family: Helvetica, sans-serif; +} + +.personal a { + color:#ffCC33; + text-decoration: none; +} + +.personal a:hover { + color:#ffCC33; +} + +.personal a:visited { + color: #006633; +} + + +div.header h1 { + margin: 0; padding: 10px 0; +} + + +div.container +{ +width:100%; +/* height: 100%; */ +margin:0px; +/*border:1px solid #004D99; solid grey; */ +line-height:100%; +} +div.header,div.footer +{ + font: 100% Verdana, Arial, Helvetica, sans-serif; + + padding: 0 10px 0 20px; + color:#ffCC33; + + background: #006633; + +/* border:1px solid grey; */ +} + +.footer a +{ + color:#ffCC33; +} + +h1.header +{ +padding:0; +margin:0; +} +div.content +{ +margin-left:180px; +border-left:1px solid #006633; +padding:1em; +} + + +/*div.header, div.footer a { + color: white; +} + +.header, .footer a:hover { + color: blue; +} +.header, .footer a:visited { + color: white; +} +*/ + + + +.contact { + text-align: center; + margin: 25px 0px 0px 400px; + position: absolute; + font-family: Helvetica, sans-serif; +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/visualizationPageStyle.css b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/visualizationPageStyle.css new file mode 100644 index 0000000..0c30c2e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/Visualization/visualizationPageStyle.css @@ -0,0 +1,120 @@ +@charset "utf-8"; + + +body { + font: 100% Verdana, Arial, Helvetica, sans-serif; + /*background: #666666; */ + margin: 0; /* it's good practice to zero the margin and padding of the body element to account for differing browser defaults */ + padding: 0; + text-align: center; /* this centers the container in IE 5* browsers. The text is then set to the left aligned default in the #container selector */ + color: #000000; +} + + + + +.VisualizationMainPage #mainContent { + /*padding: 0 20px; /* remember that padding is the space inside the div box and margin is the space outside the div box */ + background: #FFFFFF; +} + + + +.VisualizationMainPage #container { + + + background: #FFFFFF; + /*margin: 0 auto; /* the auto margins (in conjunction with a width) center the page */ + text-align: left; /* this overrides the text-align: center on the body element. */ +} + + +.VisualizationMainPage #algoControlSection +{ + background: #DDEEDD; + color:#000000; + +} + + +.VisualizationMainPage #generalAnimationControlSection +{ + background: #DDEEDD; + color:#006600; + +} + +.VisualizationMainPage #header { + background: #006633; + color:#ffCC33; + padding: 0 10px 0 20px; + +} + +.VisualizationMainPage #header A:visited + { text-decoration:none; + color:#ffCC33; + } + + +.VisualizationMainPage #header h1 { + margin: 0; + padding: 10px 0; + } + +.VisualizationMainPage #header A:link { + text-decoration:none; + color:#ffCC33; + } + + +.VisualizationMainPage #container { + background: #FFFFFF; + margin: 0 auto; /* the auto margins (in conjunction with a width) center the page */ + text-align: left; /* this overrides the text-align: center on the body element. */ +} + + +.VisualizationMainPage #footer A:visited { text-decoration:none; + color:ffcc33; +} + +.VisualizationMainPage #footer A:link { + text-decoration:none; + color:#ffCC33; +} + + + + +.VisualizationMainPage #mainContent h1{ + padding: 0 20px; + background: #FFFFFF; + color:#006633 +} + +.VisualizationMainPage #mainContent h2{ + padding: 0 20px; + background: #FFFFFF; + color:#006633 +} + +.VisualizationMainPage #mainContent h3{ + padding: 0 20px; + background: #FFFFFF; + color:#006633 +} + +.VisualizationMainPage #footer { + padding: 0 10px; + background: #006633; + color:#ffcc33; +} + +.VisualizationMainPage #footer p { + margin: 0; padding: 10px 0; +} +.VisualizationMainPage #footer a { + color: white; +} + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.project new file mode 100644 index 0000000..6948d03 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.project @@ -0,0 +1,17 @@ + + + 00-leetcode + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/二叉树/TreeNode.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/二叉树/TreeNode.class new file mode 100644 index 0000000..3af55a5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/二叉树/TreeNode.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/二叉树/_226_翻转二叉树.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/二叉树/_226_翻转二叉树.class new file mode 100644 index 0000000..98eaff7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/二叉树/_226_翻转二叉树.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/栈/_20_有效的括号.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/栈/_20_有效的括号.class new file mode 100644 index 0000000..5e2cf06 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/栈/_20_有效的括号.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/栈/_232_用栈实现队列.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/栈/_232_用栈实现队列.class new file mode 100644 index 0000000..71fd43d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/栈/_232_用栈实现队列.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/ListNode.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/ListNode.class new file mode 100644 index 0000000..59f0556 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/ListNode.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_141_环形链表.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_141_环形链表.class new file mode 100644 index 0000000..1290135 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_141_环形链表.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_206_反转链表.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_206_反转链表.class new file mode 100644 index 0000000..46ab3ed Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_206_反转链表.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_237_删除链表中的节点.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_237_删除链表中的节点.class new file mode 100644 index 0000000..b89625f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/bin/链表/_237_删除链表中的节点.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/二叉树/TreeNode.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/二叉树/TreeNode.java new file mode 100644 index 0000000..71a660a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/二叉树/TreeNode.java @@ -0,0 +1,10 @@ +package 二叉树; + +public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { + val = x; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/二叉树/_226_翻转二叉树.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/二叉树/_226_翻转二叉树.java new file mode 100644 index 0000000..f107ab1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/二叉树/_226_翻转二叉树.java @@ -0,0 +1,74 @@ +package 二叉树; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * https://leetcode-cn.com/problems/invert-binary-tree/ + * @author MJ Lee + * + */ +public class _226_翻转二叉树 { + +// public TreeNode invertTree(TreeNode root) { +// if (root == null) return root; +// +// TreeNode tmp = root.left; +// root.left = root.right; +// root.right = tmp; +// +// invertTree(root.left); +// invertTree(root.right); +// +// return root; +// } + +// public TreeNode invertTree(TreeNode root) { +// if (root == null) return root; +// +// invertTree(root.left); +// invertTree(root.right); +// +// TreeNode tmp = root.left; +// root.left = root.right; +// root.right = tmp; +// +// return root; +// } + +// public TreeNode invertTree(TreeNode root) { +// if (root == null) return root; +// +// invertTree(root.left); +// +// TreeNode tmp = root.left; +// root.left = root.right; +// root.right = tmp; +// +// invertTree(root.left); +// +// return root; +// } + public TreeNode invertTree(TreeNode root) { + if (root == null) return root; + + Queue queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + TreeNode tmp = node.left; + node.left = node.right; + node.right = tmp; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + return root; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/栈/_20_有效的括号.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/栈/_20_有效的括号.java new file mode 100644 index 0000000..9ddacc7 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/栈/_20_有效的括号.java @@ -0,0 +1,63 @@ +package 栈; + +import java.util.HashMap; +import java.util.Stack; + +public class _20_有效的括号 { + private static HashMap map = new HashMap<>(); + static { + // key - value + map.put('(', ')'); + map.put('{', '}'); + map.put('[', ']'); + } + + public boolean isValid(String s) { + Stack stack = new Stack<>(); + + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (map.containsKey(c)) { // 左括号 + stack.push(c); + } else { // 右括号 + if (stack.isEmpty()) return false; + + if (c != map.get(stack.pop())) return false; + } + } + return stack.isEmpty(); + } + + public boolean isValid1(String s) { + Stack stack = new Stack<>(); + + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (c == '(' || c == '{' || c == '[') { // 左括号 + stack.push(c); + } else { // 右括号 + if (stack.isEmpty()) return false; + + char left = stack.pop(); + if (left == '(' && c != ')') return false; + if (left == '{' && c != '}') return false; + if (left == '[' && c != ']') return false; + } + } + return stack.isEmpty(); + } + + public boolean isValid2(String s) { + while (s.contains("{}") + || s.contains("[]") + || s.contains("()")) { + s = s.replace("{}", ""); + s = s.replace("()", ""); + s = s.replace("[]", ""); + } + return s.isEmpty(); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/栈/_232_用栈实现队列.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/栈/_232_用栈实现队列.java new file mode 100644 index 0000000..f6d884e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/栈/_232_用栈实现队列.java @@ -0,0 +1,44 @@ +package 栈; + +import java.util.Stack; + +public class _232_用栈实现队列 { + private Stack inStack; + private Stack outStack; + + /** Initialize your data structure here. */ + public _232_用栈实现队列() { + inStack = new Stack<>(); + outStack = new Stack<>(); + } + + /** 入队 */ + public void push(int x) { + inStack.push(x); + } + + /** 出队 */ + public int pop() { + checkOutStack(); + return outStack.pop(); + } + + /** 获取队头元素 */ + public int peek() { + checkOutStack(); + return outStack.peek(); + } + + /** 是否为空 */ + public boolean empty() { + return inStack.isEmpty() && outStack.isEmpty(); + } + + private void checkOutStack() { + if (outStack.isEmpty()) { + while (!inStack.isEmpty()) { + outStack.push(inStack.pop()); + } + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/ListNode.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/ListNode.java new file mode 100644 index 0000000..13c5f88 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/ListNode.java @@ -0,0 +1,9 @@ +package 链表; + +public class ListNode { + int val; + ListNode next; + ListNode(int x) { + val = x; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_141_环形链表.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_141_环形链表.java new file mode 100644 index 0000000..bef9d6e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_141_环形链表.java @@ -0,0 +1,20 @@ +package 链表; + +public class _141_环形链表 { + + public boolean hasCycle(ListNode head) { + if (head == null || head.next == null) return false; + + ListNode slow = head; + ListNode fast = head.next; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + + if (slow == fast) return true; + } + + return false; + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_206_反转链表.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_206_反转链表.java new file mode 100644 index 0000000..e8b432b --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_206_反转链表.java @@ -0,0 +1,29 @@ +package 链表; + +public class _206_反转链表 { + + public ListNode reverseList(ListNode head) { + if (head == null || head.next == null) return head; + + ListNode newHead = reverseList(head.next); + head.next.next = head; + head.next = null; + return newHead; + } + + + public ListNode reverseList2(ListNode head) { + if (head == null || head.next == null) return head; + + ListNode newHead = null; + while (head != null) { + ListNode tmp = head.next; + head.next = newHead; + newHead = head; + head = tmp; + } + + return newHead; + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_237_删除链表中的节点.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_237_删除链表中的节点.java new file mode 100644 index 0000000..9b5ebf8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/00-leetcode/src/链表/_237_删除链表中的节点.java @@ -0,0 +1,14 @@ +package 链表; + +/** + * https://leetcode-cn.com/problems/delete-node-in-a-linked-list/ + * @author MJ Lee + * + */ +public class _237_删除链表中的节点 { + + public void deleteNode(ListNode node) { + node.val = node.next.val; + node.next = node.next.next; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.project new file mode 100644 index 0000000..274d6fd --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.project @@ -0,0 +1,17 @@ + + + 01-复杂度 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Main.class new file mode 100644 index 0000000..ce76b12 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Times$Task.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Times$Task.class new file mode 100644 index 0000000..573edc2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Times$Task.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Times.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Times.class new file mode 100644 index 0000000..49d99e8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/bin/com/mj/Times.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/src/com/mj/Main.java new file mode 100644 index 0000000..f3414c8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/src/com/mj/Main.java @@ -0,0 +1,162 @@ +package com.mj; + +public class Main { + + /* 0 1 2 3 4 5 + * 0 1 1 2 3 5 8 13 .... + */ + + // O(2^n) + public static int fib1(int n) { + if (n <= 1) return n; + return fib1(n - 1) + fib1(n - 2); + } + + // O(n) + public static int fib2(int n) { + if (n <= 1) return n; + + int first = 0; + int second = 1; + for (int i = 0; i < n - 1; i++) { + int sum = first + second; + first = second; + second = sum; + } + return second; + } + + public static int fib3(int n) { + if (n <= 1) return n; + + int first = 0; + int second = 1; + while (n-- > 1) { + second += first; + first = second - first; + } + return second; + } + + + public static void main(String[] args) { + int n = 12; + + System.out.println(fib2(n)); + System.out.println(fib3(n)); + +// TimeTool.check("fib1", new Task() { +// public void execute() { +// System.out.println(fib1(n)); +// } +// }); +// +// TimeTool.check("fib2", new Task() { +// public void execute() { +// System.out.println(fib2(n)); +// } +// }); + } + + public static void test1(int n) { + // 汇编指令 + + // 1 + if (n > 10) { + System.out.println("n > 10"); + } else if (n > 5) { // 2 + System.out.println("n > 5"); + } else { + System.out.println("n <= 5"); + } + + // 1 + 4 + 4 + 4 + for (int i = 0; i < 4; i++) { + System.out.println("test"); + } + + // 140000 + // O(1) + // O(1) + } + + public static void test2(int n) { + // O(n) + // 1 + 3n + for (int i = 0; i < n; i++) { + System.out.println("test"); + } + } + + public static void test3(int n) { + // 1 + 2n + n * (1 + 3n) + // 1 + 2n + n + 3n^2 + // 3n^2 + 3n + 1 + // O(n^2) + + // O(n) + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + System.out.println("test"); + } + } + } + + public static void test4(int n) { + // 1 + 2n + n * (1 + 45) + // 1 + 2n + 46n + // 48n + 1 + // O(n) + for (int i = 0; i < n; i++) { + for (int j = 0; j < 15; j++) { + System.out.println("test"); + } + } + } + + public static void test5(int n) { + // 8 = 2^3 + // 16 = 2^4 + + // 3 = log2(8) + // 4 = log2(16) + + // 执行次数 = log2(n) + // O(logn) + while ((n = n / 2) > 0) { + System.out.println("test"); + } + } + + public static void test6(int n) { + // log5(n) + // O(logn) + while ((n = n / 5) > 0) { + System.out.println("test"); + } + } + + public static void test7(int n) { + // 1 + 2*log2(n) + log2(n) * (1 + 3n) + + // 1 + 3*log2(n) + 2 * nlog2(n) + // O(nlogn) + for (int i = 1; i < n; i = i * 2) { + // 1 + 3n + for (int j = 0; j < n; j++) { + System.out.println("test"); + } + } + } + + public static void test10(int n) { + // O(n) + int a = 10; + int b = 20; + int c = a + b; + int[] array = new int[n]; + for (int i = 0; i < array.length; i++) { + System.out.println(array[i] + c); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/src/com/mj/Times.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/src/com/mj/Times.java new file mode 100644 index 0000000..35c93a4 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/01-复杂度/src/com/mj/Times.java @@ -0,0 +1,26 @@ +package com.mj; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Times { + private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS"); + + public interface Task { + void execute(); + } + + public static void test(String title, Task task) { + if (task == null) return; + title = (title == null) ? "" : ("【" + title + "】"); + System.out.println(title); + System.out.println("开始:" + fmt.format(new Date())); + long begin = System.currentTimeMillis(); + task.execute(); + long end = System.currentTimeMillis(); + System.out.println("结束:" + fmt.format(new Date())); + double delta = (end - begin) / 1000.0; + System.out.println("耗时:" + delta + "秒"); + System.out.println("-------------------------------------"); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.project new file mode 100644 index 0000000..822cf8e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.project @@ -0,0 +1,17 @@ + + + 02-动态数组 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/ArrayList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/ArrayList.class new file mode 100644 index 0000000..b1293b2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/ArrayList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Asserts.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Asserts.class new file mode 100644 index 0000000..6540fd7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Asserts.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Car.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Car.class new file mode 100644 index 0000000..6dd90b5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Car.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Main.class new file mode 100644 index 0000000..6f9035d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Person.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Person.class new file mode 100644 index 0000000..171acdc Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/bin/com/mj/Person.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/ArrayList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/ArrayList.java new file mode 100644 index 0000000..19a9002 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/ArrayList.java @@ -0,0 +1,209 @@ +package com.mj; + +@SuppressWarnings("unchecked") +public class ArrayList { + /** + * 元素的数量 + */ + private int size; + /** + * 所有的元素 + */ + private E[] elements; + + private static final int DEFAULT_CAPACITY = 10; + private static final int ELEMENT_NOT_FOUND = -1; + + public ArrayList(int capaticy) { + capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy; + elements = (E[]) new Object[capaticy]; + } + + public ArrayList() { + this(DEFAULT_CAPACITY); + } + + /** + * 清除所有元素 + */ + public void clear() { + for (int i = 0; i < size; i++) { + elements[i] = null; + } + size = 0; + } + + /** + * 元素的数量 + * @return + */ + public int size() { + return size; + } + + /** + * 是否为空 + * @return + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * 是否包含某个元素 + * @param element + * @return + */ + public boolean contains(E element) { + return indexOf(element) != ELEMENT_NOT_FOUND; + } + + /** + * 添加元素到尾部 + * @param element + */ + public void add(E element) { + add(size, element); + } + + /** + * 获取index位置的元素 + * @param index + * @return + */ + public E get(int index) { + rangeCheck(index); + return elements[index]; + } + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + public E set(int index, E element) { + rangeCheck(index); + + E old = elements[index]; + elements[index] = element; + return old; + } + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + public void add(int index, E element) { + rangeCheckForAdd(index); + + ensureCapacity(size + 1); + + for (int i = size; i > index; i--) { + elements[i] = elements[i - 1]; + } + elements[index] = element; + size++; + } + + /** + * 删除index位置的元素 + * @param index + * @return + */ + public E remove(int index) { + rangeCheck(index); + + E old = elements[index]; + for (int i = index + 1; i < size; i++) { + elements[i - 1] = elements[i]; + } + elements[--size] = null; + return old; + } + + /** + * 查看元素的索引 + * @param element + * @return + */ + public int indexOf(E element) { + if (element == null) { // 1 + for (int i = 0; i < size; i++) { + if (elements[i] == null) return i; + } + } else { + for (int i = 0; i < size; i++) { + if (element.equals(elements[i])) return i; // n + } + } + return ELEMENT_NOT_FOUND; + } + +// public int indexOf2(E element) { +// for (int i = 0; i < size; i++) { +// if (valEquals(element, elements[i])) return i; // 2n +// } +// return ELEMENT_NOT_FOUND; +// } +// +// private boolean valEquals(Object v1, Object v2) { +// return v1 == null ? v2 == null : v1.equals(v2); +// } + + /** + * 保证要有capacity的容量 + * @param capacity + */ + private void ensureCapacity(int capacity) { + int oldCapacity = elements.length; + if (oldCapacity >= capacity) return; + + // 新容量为旧容量的1.5倍 + int newCapacity = oldCapacity + (oldCapacity >> 1); + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[i]; + } + elements = newElements; + + System.out.println(oldCapacity + "扩容为" + newCapacity); + } + + private void outOfBounds(int index) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); + } + + private void rangeCheck(int index) { + if (index < 0 || index >= size) { + outOfBounds(index); + } + } + + private void rangeCheckForAdd(int index) { + if (index < 0 || index > size) { + outOfBounds(index); + } + } + + @Override + public String toString() { + // size=3, [99, 88, 77] + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(elements[i]); + +// if (i != size - 1) { +// string.append(", "); +// } + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Asserts.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Asserts.java new file mode 100644 index 0000000..f9b30cd --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Asserts.java @@ -0,0 +1,11 @@ +package com.mj; + +public class Asserts { + public static void test(boolean value) { + try { + if (!value) throw new Exception("测试未通过"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Car.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Car.java new file mode 100644 index 0000000..4516cf8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Car.java @@ -0,0 +1,5 @@ +package com.mj; + +public class Car { + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Main.java new file mode 100644 index 0000000..6349c3a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Main.java @@ -0,0 +1,47 @@ +package com.mj; + + +public class Main { + + public static void main(String[] args) { + ArrayList list = new ArrayList<>(); + list.add(10); + list.add(new Person(10, "Jack")); + list.add(22); + + list.indexOf(new Person(10, "Jack")); + + +// ArrayList persons = new ArrayList<>(); +// persons.add(new Person(10, "Jack")); +// persons.add(null); +// persons.add(new Person(15, "Rose")); +// persons.add(null); +// persons.add(new Person(12, "James")); +// persons.add(null); +// +// System.out.println(persons.indexOf(null)); + } + + static void test() { + // int -> Integer + + // 所有的类,最终都继承java.lang.Object + + // new是向堆空间申请内存 + ArrayList persons = new ArrayList<>(); + persons.add(new Person(10, "Jack")); + persons.add(new Person(12, "James")); + persons.add(new Person(15, "Rose")); + persons.clear(); + persons.add(new Person(22, "abc")); + + System.out.println(persons); + ArrayList ints = new ArrayList<>(); + ints.add(10); + ints.add(10); + ints.add(22); + ints.add(33); + System.out.println(ints); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Person.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Person.java new file mode 100644 index 0000000..13343f2 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/02-动态数组/src/com/mj/Person.java @@ -0,0 +1,33 @@ +package com.mj; + +public class Person { + private int age; + private String name; + + public Person(int age, String name) { + this.age = age; + this.name = name; + } + + @Override + public String toString() { + return "Person [age=" + age + ", name=" + name + "]"; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + + System.out.println("Person - finalize"); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (obj instanceof Person) { + Person person = (Person) obj; + return this.age == person.age; + } + return false; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.project new file mode 100644 index 0000000..3d66b44 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.project @@ -0,0 +1,17 @@ + + + 03-链表 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/AbstractList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/AbstractList.class new file mode 100644 index 0000000..5a03fca Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/AbstractList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/ArrayList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/ArrayList.class new file mode 100644 index 0000000..ac63c56 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/ArrayList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/ArrayList2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/ArrayList2.class new file mode 100644 index 0000000..562911a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/ArrayList2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/Asserts.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/Asserts.class new file mode 100644 index 0000000..6540fd7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/Asserts.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/LinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/LinkedList$Node.class new file mode 100644 index 0000000..60dc976 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/LinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/LinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/LinkedList.class new file mode 100644 index 0000000..18420a5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/LinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/List.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/List.class new file mode 100644 index 0000000..0e87cea Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/List.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/Main.class new file mode 100644 index 0000000..72e7d27 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/CircleLinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/CircleLinkedList$Node.class new file mode 100644 index 0000000..ab859aa Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/CircleLinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/CircleLinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/CircleLinkedList.class new file mode 100644 index 0000000..aeaf28c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/CircleLinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/SingleCircleLinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/SingleCircleLinkedList$Node.class new file mode 100644 index 0000000..b7426a4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/SingleCircleLinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/SingleCircleLinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/SingleCircleLinkedList.class new file mode 100644 index 0000000..96ec507 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/circle/SingleCircleLinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList$Node.class new file mode 100644 index 0000000..ed4d3a7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList.class new file mode 100644 index 0000000..2e61ccc Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList2$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList2$Node.class new file mode 100644 index 0000000..8c7b4ef Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList2$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList2.class new file mode 100644 index 0000000..fe0be9f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/bin/com/mj/single/SingleLinkedList2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/AbstractList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/AbstractList.java new file mode 100644 index 0000000..bbe194f --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/AbstractList.java @@ -0,0 +1,56 @@ +package com.mj; + +public abstract class AbstractList implements List { + /** + * 元素的数量 + */ + protected int size; + /** + * 元素的数量 + * @return + */ + public int size() { + return size; + } + + /** + * 是否为空 + * @return + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * 是否包含某个元素 + * @param element + * @return + */ + public boolean contains(E element) { + return indexOf(element) != ELEMENT_NOT_FOUND; + } + + /** + * 添加元素到尾部 + * @param element + */ + public void add(E element) { + add(size, element); + } + + protected void outOfBounds(int index) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); + } + + protected void rangeCheck(int index) { + if (index < 0 || index >= size) { + outOfBounds(index); + } + } + + protected void rangeCheckForAdd(int index) { + if (index < 0 || index > size) { + outOfBounds(index); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/ArrayList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/ArrayList.java new file mode 100644 index 0000000..fe1ba69 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/ArrayList.java @@ -0,0 +1,154 @@ +package com.mj; + +@SuppressWarnings("unchecked") +public class ArrayList extends AbstractList { + /** + * 所有的元素 + */ + private E[] elements; + private static final int DEFAULT_CAPACITY = 10; + + public ArrayList(int capaticy) { + capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy; + elements = (E[]) new Object[capaticy]; + } + + public ArrayList() { + this(DEFAULT_CAPACITY); + } + + /** + * 清除所有元素 + */ + public void clear() { + for (int i = 0; i < size; i++) { + elements[i] = null; + } + size = 0; + } + + /** + * 获取index位置的元素 + * @param index + * @return + */ + public E get(int index) { // O(1) + rangeCheck(index); + + return elements[index]; + } + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + public E set(int index, E element) { // O(1) + rangeCheck(index); + + E old = elements[index]; + elements[index] = element; + return old; + } + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + public void add(int index, E element) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheckForAdd(index); + + ensureCapacity(size + 1); + + for (int i = size; i > index; i--) { + elements[i] = elements[i - 1]; + } + elements[index] = element; + size++; + } // size是数据规模 + + /** + * 删除index位置的元素 + * @param index + * @return + */ + public E remove(int index) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheck(index); + + E old = elements[index]; + for (int i = index + 1; i < size; i++) { + elements[i - 1] = elements[i]; + } + elements[--size] = null; + return old; + } + + /** + * 查看元素的索引 + * @param element + * @return + */ + public int indexOf(E element) { + if (element == null) { + for (int i = 0; i < size; i++) { + if (elements[i] == null) return i; + } + } else { + for (int i = 0; i < size; i++) { + if (element.equals(elements[i])) return i; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 保证要有capacity的容量 + * @param capacity + */ + private void ensureCapacity(int capacity) { + int oldCapacity = elements.length; + if (oldCapacity >= capacity) return; + + // 新容量为旧容量的1.5倍 + int newCapacity = oldCapacity + (oldCapacity >> 1); + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[i]; + } + elements = newElements; + + System.out.println(oldCapacity + "扩容为" + newCapacity); + } + + @Override + public String toString() { + // size=3, [99, 88, 77] + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(elements[i]); + +// if (i != size - 1) { +// string.append(", "); +// } + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/ArrayList2.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/ArrayList2.java new file mode 100644 index 0000000..fc28e6e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/ArrayList2.java @@ -0,0 +1,189 @@ +package com.mj; + +@SuppressWarnings("unchecked") + +/** + * 有动态缩容操作 + * @author MJ Lee + * + * @param + */ +public class ArrayList2 extends AbstractList { + /** + * 所有的元素 + */ + private E[] elements; + private static final int DEFAULT_CAPACITY = 10; + + public ArrayList2(int capaticy) { + capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy; + elements = (E[]) new Object[capaticy]; + } + + public ArrayList2() { + this(DEFAULT_CAPACITY); + } + + /** + * 清除所有元素 + */ + public void clear() { + for (int i = 0; i < size; i++) { + elements[i] = null; + } + size = 0; + + // 仅供参考 + if (elements != null && elements.length > DEFAULT_CAPACITY) { + elements = (E[]) new Object[DEFAULT_CAPACITY]; + } + } + + /** + * 获取index位置的元素 + * @param index + * @return + */ + public E get(int index) { // O(1) + rangeCheck(index); + + return elements[index]; + } + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + public E set(int index, E element) { // O(1) + rangeCheck(index); + + E old = elements[index]; + elements[index] = element; + return old; + } + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + public void add(int index, E element) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheckForAdd(index); + + ensureCapacity(size + 1); + + for (int i = size; i > index; i--) { + elements[i] = elements[i - 1]; + } + elements[index] = element; + size++; + } // size是数据规模 + + /** + * 删除index位置的元素 + * @param index + * @return + */ + public E remove(int index) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheck(index); + + E old = elements[index]; + for (int i = index + 1; i < size; i++) { + elements[i - 1] = elements[i]; + } + elements[--size] = null; + + trim(); + + return old; + } + + /** + * 查看元素的索引 + * @param element + * @return + */ + public int indexOf(E element) { + if (element == null) { + for (int i = 0; i < size; i++) { + if (elements[i] == null) return i; + } + } else { + for (int i = 0; i < size; i++) { + if (element.equals(elements[i])) return i; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 保证要有capacity的容量 + * @param capacity + */ + private void ensureCapacity(int capacity) { + int oldCapacity = elements.length; + if (oldCapacity >= capacity) return; + + // 新容量为旧容量的1.5倍 + int newCapacity = oldCapacity + (oldCapacity >> 1); + + // 新容量为旧容量的2倍 + // int newCapacity = oldCapacity << 1; + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[i]; + } + elements = newElements; + + System.out.println(oldCapacity + "扩容为" + newCapacity); + } + + private void trim() { + // 30 + int oldCapacity = elements.length; + // 15 + int newCapacity = oldCapacity >> 1; + if (size > (newCapacity) || oldCapacity <= DEFAULT_CAPACITY) return; + + // 剩余空间还很多 + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[i]; + } + elements = newElements; + + System.out.println(oldCapacity + "缩容为" + newCapacity); + } + + @Override + public String toString() { + // size=3, [99, 88, 77] + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(elements[i]); + +// if (i != size - 1) { +// string.append(", "); +// } + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/Asserts.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/Asserts.java new file mode 100644 index 0000000..f9b30cd --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/Asserts.java @@ -0,0 +1,11 @@ +package com.mj; + +public class Asserts { + public static void test(boolean value) { + try { + if (!value) throw new Exception("测试未通过"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/LinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/LinkedList.java new file mode 100644 index 0000000..3ab9094 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/LinkedList.java @@ -0,0 +1,175 @@ +package com.mj; + +import com.mj.AbstractList; + +public class LinkedList extends AbstractList { + private Node first; + private Node last; + + private static class Node { + E element; + Node prev; + Node next; + public Node(Node prev, E element, Node next) { + this.prev = prev; + this.element = element; + this.next = next; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (prev != null) { + sb.append(prev.element); + } else { + sb.append("null"); + } + + sb.append("_").append(element).append("_"); + + if (next != null) { + sb.append(next.element); + } else { + sb.append("null"); + } + + return sb.toString(); + } + } + + @Override + public void clear() { + size = 0; + first = null; + last = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + // size == 0 + // index == 0 + if (index == size) { // 往最后面添加元素 + Node oldLast = last; + last = new Node<>(oldLast, element, null); + if (oldLast == null) { // 这是链表添加的第一个元素 + first = last; + } else { + oldLast.next = last; + } + } else { + Node next = node(index); + Node prev = next.prev; + Node node = new Node<>(prev, element, next); + next.prev = node; + + if (prev == null) { // index == 0 + first = node; + } else { + prev.next = node; + } + } + + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + + Node node = node(index); + Node prev = node.prev; + Node next = node.next; + + if (prev == null) { // index == 0 + first = next; + } else { + prev.next = next; + } + + if (next == null) { // index == size - 1 + last = prev; + } else { + next.prev = prev; + } + + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + if (index < (size >> 1)) { + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } else { + Node node = last; + for (int i = size - 1; i > index; i--) { + node = node.prev; + } + return node; + } + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node); + + node = node.next; + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/List.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/List.java new file mode 100644 index 0000000..85e3638 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/List.java @@ -0,0 +1,70 @@ +package com.mj; + +public interface List { + static final int ELEMENT_NOT_FOUND = -1; + /** + * 清除所有元素 + */ + void clear(); + + /** + * 元素的数量 + * @return + */ + int size(); + + /** + * 是否为空 + * @return + */ + boolean isEmpty(); + + /** + * 是否包含某个元素 + * @param element + * @return + */ + boolean contains(E element); + + /** + * 添加元素到尾部 + * @param element + */ + void add(E element); + + /** + * 获取index位置的元素 + * @param index + * @return + */ + E get(int index); + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + E set(int index, E element); + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + void add(int index, E element); + + /** + * 删除index位置的元素 + * @param index + * @return + */ + E remove(int index); + + /** + * 查看元素的索引 + * @param element + * @return + */ + int indexOf(E element); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/Main.java new file mode 100644 index 0000000..ca05279 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/Main.java @@ -0,0 +1,64 @@ +package com.mj; + +import com.mj.circle.CircleLinkedList; + +public class Main { + + static void testList(List list) { + list.add(11); + list.add(22); + list.add(33); + list.add(44); + + list.add(0, 55); // [55, 11, 22, 33, 44] + list.add(2, 66); // [55, 11, 66, 22, 33, 44] + list.add(list.size(), 77); // [55, 11, 66, 22, 33, 44, 77] + + list.remove(0); // [11, 66, 22, 33, 44, 77] + list.remove(2); // [11, 66, 33, 44, 77] + list.remove(list.size() - 1); // [11, 66, 33, 44] + + Asserts.test(list.indexOf(44) == 3); + Asserts.test(list.indexOf(22) == List.ELEMENT_NOT_FOUND); + Asserts.test(list.contains(33)); + Asserts.test(list.get(0) == 11); + Asserts.test(list.get(1) == 66); + Asserts.test(list.get(list.size() - 1) == 44); + + System.out.println(list); + } + + static void josephus() { + CircleLinkedList list = new CircleLinkedList<>(); + for (int i = 1; i <= 8; i++) { + list.add(i); + } + + // 指向头结点(指向1) + list.reset(); + + while (!list.isEmpty()) { + list.next(); + list.next(); + System.out.println(list.remove()); + } + } + + public static void main(String[] args) { + josephus(); + +// testList(new ArrayList<>()); +// testList(new LinkedList<>()); + + + // testList(new SingleCircleLinkedList<>()); + + // testList(new CircleLinkedList<>()); + + /* + * gc root对象 + * 1> 被局部变量指向的对象 + */ + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/circle/CircleLinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/circle/CircleLinkedList.java new file mode 100644 index 0000000..a3f767f --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/circle/CircleLinkedList.java @@ -0,0 +1,208 @@ +package com.mj.circle; + +import com.mj.AbstractList; + +public class CircleLinkedList extends AbstractList { + private Node first; + private Node last; + private Node current; + + private static class Node { + E element; + Node prev; + Node next; + public Node(Node prev, E element, Node next) { + this.prev = prev; + this.element = element; + this.next = next; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (prev != null) { + sb.append(prev.element); + } else { + sb.append("null"); + } + + sb.append("_").append(element).append("_"); + + if (next != null) { + sb.append(next.element); + } else { + sb.append("null"); + } + + return sb.toString(); + } + } + + public void reset() { + current = first; + } + + public E next() { + if (current == null) return null; + + current = current.next; + return current.element; + } + + public E remove() { + if (current == null) return null; + + Node next = current.next; + E element = remove(current); + if (size == 0) { + current = null; + } else { + current = next; + } + + return element; + } + + @Override + public void clear() { + size = 0; + first = null; + last = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + // size == 0 + // index == 0 + if (index == size) { // 往最后面添加元素 + Node oldLast = last; + last = new Node<>(oldLast, element, first); + if (oldLast == null) { // 这是链表添加的第一个元素 + first = last; + first.next = first; + first.prev = first; + } else { + oldLast.next = last; + first.prev = last; + } + } else { + Node next = node(index); + Node prev = next.prev; + Node node = new Node<>(prev, element, next); + next.prev = node; + prev.next = node; + + if (next == first) { // index == 0 + first = node; + } + } + + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + return remove(node(index)); + } + + private E remove(Node node) { + if (size == 1) { + first = null; + last = null; + } else { + Node prev = node.prev; + Node next = node.next; + prev.next = next; + next.prev = prev; + + if (node == first) { // index == 0 + first = next; + } + + if (node == last) { // index == size - 1 + last = prev; + } + } + + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + if (index < (size >> 1)) { + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } else { + Node node = last; + for (int i = size - 1; i > index; i--) { + node = node.prev; + } + return node; + } + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node); + + node = node.next; + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/circle/SingleCircleLinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/circle/SingleCircleLinkedList.java new file mode 100644 index 0000000..c10e404 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/circle/SingleCircleLinkedList.java @@ -0,0 +1,135 @@ +package com.mj.circle; + +import com.mj.AbstractList; + +public class SingleCircleLinkedList extends AbstractList { + private Node first; + + private static class Node { + E element; + Node next; + public Node(E element, Node next) { + this.element = element; + this.next = next; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(element).append("_").append(next.element); + return sb.toString(); + } + } + + @Override + public void clear() { + size = 0; + first = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + if (index == 0) { + Node newFirst = new Node<>(element, first); + // 拿到最后一个节点 + Node last = (size == 0) ? newFirst : node(size - 1); + last.next = newFirst; + first = newFirst; + } else { + Node prev = node(index - 1); + prev.next = new Node<>(element, prev.next); + } + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + + Node node = first; + if (index == 0) { + if (size == 1) { + first = null; + } else { + Node last = node(size - 1); + first = first.next; + last.next = first; + } + } else { + Node prev = node(index - 1); + node = prev.next; + prev.next = node.next; + } + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + + return node; + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node); + + node = node.next; + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/single/SingleLinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/single/SingleLinkedList.java new file mode 100644 index 0000000..d0de9b3 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/single/SingleLinkedList.java @@ -0,0 +1,144 @@ +package com.mj.single; + +import com.mj.AbstractList; + +public class SingleLinkedList extends AbstractList { + private Node first; + + private static class Node { + E element; + Node next; + public Node(E element, Node next) { + this.element = element; + this.next = next; + } + } + + @Override + public void clear() { + size = 0; + first = null; + } + + @Override + public E get(int index) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + return node(index).element; + } + + @Override + public E set(int index, E element) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheckForAdd(index); + + if (index == 0) { + first = new Node<>(element, first); + } else { + Node prev = node(index - 1); + prev.next = new Node<>(element, prev.next); + } + size++; + } + + @Override + public E remove(int index) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheck(index); + + Node node = first; + if (index == 0) { + first = first.next; + } else { + Node prev = node(index - 1); + node = prev.next; + prev.next = node.next; + } + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node.element); + + node = node.next; + } + string.append("]"); + +// Node node1 = first; +// while (node1 != null) { +// +// +// node1 = node1.next; +// } + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/single/SingleLinkedList2.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/single/SingleLinkedList2.java new file mode 100644 index 0000000..26f767e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/03-链表/src/com/mj/single/SingleLinkedList2.java @@ -0,0 +1,127 @@ +package com.mj.single; + +import com.mj.AbstractList; + +/** + * 增加一个虚拟头结点 + * @author MJ Lee + * + * @param + */ +public class SingleLinkedList2 extends AbstractList { + private Node first; + + public SingleLinkedList2() { + first = new Node<>(null, null); + } + + private static class Node { + E element; + Node next; + public Node(E element, Node next) { + this.element = element; + this.next = next; + } + } + + @Override + public void clear() { + size = 0; + first = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + Node prev = index == 0 ? first : node(index - 1); + prev.next = new Node<>(element, prev.next); + + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + + Node prev = index == 0 ? first : node(index - 1); + Node node = prev.next; + prev.next = node.next; + + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + Node node = first.next; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first.next; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node.element); + + node = node.next; + } + string.append("]"); + +// Node node1 = first; +// while (node1 != null) { +// +// +// node1 = node1.next; +// } + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.project new file mode 100644 index 0000000..d6170a6 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.project @@ -0,0 +1,17 @@ + + + 04-栈 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/Main.class new file mode 100644 index 0000000..f29270b Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/Stack.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/Stack.class new file mode 100644 index 0000000..2697cef Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/Stack.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/AbstractList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/AbstractList.class new file mode 100644 index 0000000..efaf42f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/AbstractList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/ArrayList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/ArrayList.class new file mode 100644 index 0000000..5b00d7e Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/ArrayList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/LinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/LinkedList$Node.class new file mode 100644 index 0000000..e6bb90f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/LinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/LinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/LinkedList.class new file mode 100644 index 0000000..107ef02 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/LinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/List.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/List.class new file mode 100644 index 0000000..e5d4790 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/bin/com/mj/list/List.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/Main.java new file mode 100644 index 0000000..65fb898 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/Main.java @@ -0,0 +1,17 @@ +package com.mj; + +public class Main { + + public static void main(String[] args) { + Stack stack = new Stack<>(); + stack.push(11); + stack.push(22); + stack.push(33); + stack.push(44); + + while (!stack.isEmpty()) { + System.out.println(stack.pop()); + } + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/Stack.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/Stack.java new file mode 100644 index 0000000..e50dea0 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/Stack.java @@ -0,0 +1,34 @@ +package com.mj; + +import com.mj.list.ArrayList; +import com.mj.list.List; + +public class Stack { + private List list = new ArrayList<>(); + + public void clear() { + list.clear(); + } + + public int size() { + return list.size(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public void push(E element) { + list.add(element); + } + + + public E pop() { + return list.remove(list.size() - 1); + } + + + public E top() { + return list.get(list.size() - 1); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/AbstractList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/AbstractList.java new file mode 100644 index 0000000..455c858 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/AbstractList.java @@ -0,0 +1,56 @@ +package com.mj.list; + +public abstract class AbstractList implements List { + /** + * 元素的数量 + */ + protected int size; + /** + * 元素的数量 + * @return + */ + public int size() { + return size; + } + + /** + * 是否为空 + * @return + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * 是否包含某个元素 + * @param element + * @return + */ + public boolean contains(E element) { + return indexOf(element) != ELEMENT_NOT_FOUND; + } + + /** + * 添加元素到尾部 + * @param element + */ + public void add(E element) { + add(size, element); + } + + protected void outOfBounds(int index) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); + } + + protected void rangeCheck(int index) { + if (index < 0 || index >= size) { + outOfBounds(index); + } + } + + protected void rangeCheckForAdd(int index) { + if (index < 0 || index > size) { + outOfBounds(index); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/ArrayList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/ArrayList.java new file mode 100644 index 0000000..08b3b1e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/ArrayList.java @@ -0,0 +1,154 @@ +package com.mj.list; + +@SuppressWarnings("unchecked") +public class ArrayList extends AbstractList { + /** + * 所有的元素 + */ + private E[] elements; + private static final int DEFAULT_CAPACITY = 10; + + public ArrayList(int capaticy) { + capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy; + elements = (E[]) new Object[capaticy]; + } + + public ArrayList() { + this(DEFAULT_CAPACITY); + } + + /** + * 清除所有元素 + */ + public void clear() { + for (int i = 0; i < size; i++) { + elements[i] = null; + } + size = 0; + } + + /** + * 获取index位置的元素 + * @param index + * @return + */ + public E get(int index) { // O(1) + rangeCheck(index); + + return elements[index]; + } + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + public E set(int index, E element) { // O(1) + rangeCheck(index); + + E old = elements[index]; + elements[index] = element; + return old; + } + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + public void add(int index, E element) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheckForAdd(index); + + ensureCapacity(size + 1); + + for (int i = size; i > index; i--) { + elements[i] = elements[i - 1]; + } + elements[index] = element; + size++; + } // size是数据规模 + + /** + * 删除index位置的元素 + * @param index + * @return + */ + public E remove(int index) { + /* + * 最好:O(1) + * 最坏:O(n) + * 平均:O(n) + */ + rangeCheck(index); + + E old = elements[index]; + for (int i = index + 1; i < size; i++) { + elements[i - 1] = elements[i]; + } + elements[--size] = null; + return old; + } + + /** + * 查看元素的索引 + * @param element + * @return + */ + public int indexOf(E element) { + if (element == null) { + for (int i = 0; i < size; i++) { + if (elements[i] == null) return i; + } + } else { + for (int i = 0; i < size; i++) { + if (element.equals(elements[i])) return i; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 保证要有capacity的容量 + * @param capacity + */ + private void ensureCapacity(int capacity) { + int oldCapacity = elements.length; + if (oldCapacity >= capacity) return; + + // 新容量为旧容量的1.5倍 + int newCapacity = oldCapacity + (oldCapacity >> 1); + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[i]; + } + elements = newElements; + + System.out.println(oldCapacity + "扩容为" + newCapacity); + } + + @Override + public String toString() { + // size=3, [99, 88, 77] + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(elements[i]); + +// if (i != size - 1) { +// string.append(", "); +// } + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/LinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/LinkedList.java new file mode 100644 index 0000000..d954908 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/LinkedList.java @@ -0,0 +1,175 @@ +package com.mj.list; + +import com.mj.list.AbstractList; + +public class LinkedList extends AbstractList { + private Node first; + private Node last; + + private static class Node { + E element; + Node prev; + Node next; + public Node(Node prev, E element, Node next) { + this.prev = prev; + this.element = element; + this.next = next; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (prev != null) { + sb.append(prev.element); + } else { + sb.append("null"); + } + + sb.append("_").append(element).append("_"); + + if (next != null) { + sb.append(next.element); + } else { + sb.append("null"); + } + + return sb.toString(); + } + } + + @Override + public void clear() { + size = 0; + first = null; + last = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + // size == 0 + // index == 0 + if (index == size) { // 往最后面添加元素 + Node oldLast = last; + last = new Node<>(oldLast, element, null); + if (oldLast == null) { // 这是链表添加的第一个元素 + first = last; + } else { + oldLast.next = last; + } + } else { + Node next = node(index); + Node prev = next.prev; + Node node = new Node<>(prev, element, next); + next.prev = node; + + if (prev == null) { // index == 0 + first = node; + } else { + prev.next = node; + } + } + + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + + Node node = node(index); + Node prev = node.prev; + Node next = node.next; + + if (prev == null) { // index == 0 + first = next; + } else { + prev.next = next; + } + + if (next == null) { // index == size - 1 + last = prev; + } else { + next.prev = prev; + } + + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + if (index < (size >> 1)) { + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } else { + Node node = last; + for (int i = size - 1; i > index; i--) { + node = node.prev; + } + return node; + } + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node); + + node = node.next; + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/List.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/List.java new file mode 100644 index 0000000..d8b5af5 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/04-栈/src/com/mj/list/List.java @@ -0,0 +1,70 @@ +package com.mj.list; + +public interface List { + static final int ELEMENT_NOT_FOUND = -1; + /** + * 清除所有元素 + */ + void clear(); + + /** + * 元素的数量 + * @return + */ + int size(); + + /** + * 是否为空 + * @return + */ + boolean isEmpty(); + + /** + * 是否包含某个元素 + * @param element + * @return + */ + boolean contains(E element); + + /** + * 添加元素到尾部 + * @param element + */ + void add(E element); + + /** + * 获取index位置的元素 + * @param index + * @return + */ + E get(int index); + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + E set(int index, E element); + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + void add(int index, E element); + + /** + * 删除index位置的元素 + * @param index + * @return + */ + E remove(int index); + + /** + * 查看元素的索引 + * @param element + * @return + */ + int indexOf(E element); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.project new file mode 100644 index 0000000..99a5a98 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.project @@ -0,0 +1,17 @@ + + + 05-队列 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Deque.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Deque.class new file mode 100644 index 0000000..1fb80d0 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Deque.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Main.class new file mode 100644 index 0000000..13f23a0 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Queue.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Queue.class new file mode 100644 index 0000000..c8d93a9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/Queue.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/circle/CircleDeque.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/circle/CircleDeque.class new file mode 100644 index 0000000..5bf3081 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/circle/CircleDeque.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/circle/CircleQueue.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/circle/CircleQueue.class new file mode 100644 index 0000000..da02a3b Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/circle/CircleQueue.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/AbstractList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/AbstractList.class new file mode 100644 index 0000000..efaf42f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/AbstractList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/LinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/LinkedList$Node.class new file mode 100644 index 0000000..acd9e51 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/LinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/LinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/LinkedList.class new file mode 100644 index 0000000..ffd1e3a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/LinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/List.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/List.class new file mode 100644 index 0000000..e5d4790 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/bin/com/mj/list/List.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Deque.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Deque.java new file mode 100644 index 0000000..13625f4 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Deque.java @@ -0,0 +1,44 @@ +package com.mj; + +import com.mj.list.LinkedList; +import com.mj.list.List; + +public class Deque { + private List list = new LinkedList<>(); + + public int size() { + return list.size(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public void clear() { + list.clear(); + } + + public void enQueueRear(E element) { + list.add(element); + } + + public E deQueueFront() { + return list.remove(0); + } + + public void enQueueFront(E element) { + list.add(0, element); + } + + public E deQueueRear() { + return list.remove(list.size() - 1); + } + + public E front() { + return list.get(0); + } + + public E rear() { + return list.get(list.size() - 1); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Main.java new file mode 100644 index 0000000..c727292 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Main.java @@ -0,0 +1,96 @@ +package com.mj; + +import com.mj.circle.CircleDeque; +import com.mj.circle.CircleQueue; + +public class Main { + + static void test1() { + Queue queue = new Queue<>(); + queue.enQueue(11); + queue.enQueue(22); + queue.enQueue(33); + queue.enQueue(44); + + while (!queue.isEmpty()) { + System.out.println(queue.deQueue()); + } + +// Deque queue = new Deque<>(); +// queue.enQueueFront(11); +// queue.enQueueFront(22); +// queue.enQueueRear(33); +// queue.enQueueRear(44); +// +// /* 尾 44 33 11 22 头 */ +// +// while (!queue.isEmpty()) { +// System.out.println(queue.deQueueRear()); +// } + } + + static void test2() { + CircleQueue queue = new CircleQueue(); + // 0 1 2 3 4 5 6 7 8 9 + for (int i = 0; i < 10; i++) { + queue.enQueue(i); + } + // null null null null null 5 6 7 8 9 + for (int i = 0; i < 5; i++) { + queue.deQueue(); + } + // 15 16 17 18 19 5 6 7 8 9 + for (int i = 15; i < 20; i++) { + queue.enQueue(i); + } + while (!queue.isEmpty()) { + System.out.println(queue.deQueue()); + } + System.out.println(queue); + } + + static void test3() { + CircleDeque queue = new CircleDeque<>(); + // 头5 4 3 2 1 100 101 102 103 104 105 106 8 7 6 尾 + + // 头 8 7 6 5 4 3 2 1 100 101 102 103 104 105 106 107 108 109 null null 10 9 尾 + for (int i = 0; i < 10; i++) { + queue.enQueueFront(i + 1); + queue.enQueueRear(i + 100); + } + + // 头 null 7 6 5 4 3 2 1 100 101 102 103 104 105 106 null null null null null null null 尾 + for (int i = 0; i < 3; i++) { + queue.deQueueFront(); + queue.deQueueRear(); + } + + // 头 11 7 6 5 4 3 2 1 100 101 102 103 104 105 106 null null null null null null 12 尾 + queue.enQueueFront(11); + queue.enQueueFront(12); + System.out.println(queue); + while (!queue.isEmpty()) { + System.out.println(queue.deQueueFront()); + } + } + + public static void main(String[] args) { + test2(); + test3(); + +// int n = 13; +// int m = 7; +// +//// if (n >= m) { +//// System.out.println(n - m); +//// } else { +//// System.out.println(n); +//// } +// +// // m > 0, n >= 0, n < 2m +// System.out.println(n - (n >= m ? m : 0)); +// +// System.out.println(n % m); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Queue.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Queue.java new file mode 100644 index 0000000..376cb49 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/Queue.java @@ -0,0 +1,32 @@ +package com.mj; + +import com.mj.list.LinkedList; +import com.mj.list.List; + +public class Queue { + private List list = new LinkedList<>(); + + public int size() { + return list.size(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public void clear() { + list.clear(); + } + + public void enQueue(E element) { + list.add(element); + } + + public E deQueue() { + return list.remove(0); + } + + public E front() { + return list.get(0); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/circle/CircleDeque.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/circle/CircleDeque.java new file mode 100644 index 0000000..d21960f --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/circle/CircleDeque.java @@ -0,0 +1,130 @@ +package com.mj.circle; + +@SuppressWarnings("unchecked") +public class CircleDeque { + private int front; + private int size; + private E[] elements; + private static final int DEFAULT_CAPACITY = 10; + + public CircleDeque() { + elements = (E[]) new Object[DEFAULT_CAPACITY]; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + for (int i = 0; i < size; i++) { + elements[index(i)] = null; + } + front = 0; + size = 0; + } + + /** + * 从尾部入队 + * @param element + */ + public void enQueueRear(E element) { + ensureCapacity(size + 1); + + elements[index(size)] = element; + size++; + } + + /** + * 从头部出队 + * @param element + */ + public E deQueueFront() { + E frontElement = elements[front]; + elements[front] = null; + front = index(1); + size--; + return frontElement; + } + + /** + * 从头部入队 + * @param element + */ + public void enQueueFront(E element) { + ensureCapacity(size + 1); + + front = index(-1); + elements[front] = element; + size++; + } + + /** + * 从尾部出队 + * @param element + */ + public E deQueueRear() { + int rearIndex = index(size - 1); + E rear = elements[rearIndex]; + elements[rearIndex] = null; + size--; + return rear; + } + + public E front() { + return elements[front]; + } + + public E rear() { + return elements[index(size - 1)]; + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("capcacity=").append(elements.length) + .append(" size=").append(size) + .append(" front=").append(front) + .append(", ["); + for (int i = 0; i < elements.length; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(elements[i]); + } + string.append("]"); + return string.toString(); + } + + private int index(int index) { + index += front; + if (index < 0) { + return index + elements.length; + } + return index - (index >= elements.length ? elements.length : 0); + } + + /** + * 保证要有capacity的容量 + * @param capacity + */ + private void ensureCapacity(int capacity) { + int oldCapacity = elements.length; + if (oldCapacity >= capacity) return; + + // 新容量为旧容量的1.5倍 + int newCapacity = oldCapacity + (oldCapacity >> 1); + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[index(i)]; + } + elements = newElements; + + // 重置front + front = 0; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/circle/CircleQueue.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/circle/CircleQueue.java new file mode 100644 index 0000000..709dfaa --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/circle/CircleQueue.java @@ -0,0 +1,91 @@ +package com.mj.circle; + +@SuppressWarnings("unchecked") +public class CircleQueue { + private int front; + private int size; + private E[] elements; + private static final int DEFAULT_CAPACITY = 10; + + public CircleQueue() { + elements = (E[]) new Object[DEFAULT_CAPACITY]; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + for (int i = 0; i < size; i++) { + elements[index(i)] = null; + } + front = 0; + size = 0; + } + + public void enQueue(E element) { + ensureCapacity(size + 1); + + elements[index(size)] = element; + size++; + } + + public E deQueue() { + E frontElement = elements[front]; + elements[front] = null; + front = index(1); + size--; + return frontElement; + } + + public E front() { + return elements[front]; + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("capcacity=").append(elements.length) + .append(" size=").append(size) + .append(" front=").append(front) + .append(", ["); + for (int i = 0; i < elements.length; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(elements[i]); + } + string.append("]"); + return string.toString(); + } + + private int index(int index) { + index += front; + return index - (index >= elements.length ? elements.length : 0); + } + + /** + * 保证要有capacity的容量 + * @param capacity + */ + private void ensureCapacity(int capacity) { + int oldCapacity = elements.length; + if (oldCapacity >= capacity) return; + + // 新容量为旧容量的1.5倍 + int newCapacity = oldCapacity + (oldCapacity >> 1); + E[] newElements = (E[]) new Object[newCapacity]; + for (int i = 0; i < size; i++) { + newElements[i] = elements[index(i)]; + } + elements = newElements; + + // 重置front + front = 0; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/AbstractList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/AbstractList.java new file mode 100644 index 0000000..455c858 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/AbstractList.java @@ -0,0 +1,56 @@ +package com.mj.list; + +public abstract class AbstractList implements List { + /** + * 元素的数量 + */ + protected int size; + /** + * 元素的数量 + * @return + */ + public int size() { + return size; + } + + /** + * 是否为空 + * @return + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * 是否包含某个元素 + * @param element + * @return + */ + public boolean contains(E element) { + return indexOf(element) != ELEMENT_NOT_FOUND; + } + + /** + * 添加元素到尾部 + * @param element + */ + public void add(E element) { + add(size, element); + } + + protected void outOfBounds(int index) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); + } + + protected void rangeCheck(int index) { + if (index < 0 || index >= size) { + outOfBounds(index); + } + } + + protected void rangeCheckForAdd(int index) { + if (index < 0 || index > size) { + outOfBounds(index); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/LinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/LinkedList.java new file mode 100644 index 0000000..d74c2ef --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/LinkedList.java @@ -0,0 +1,173 @@ +package com.mj.list; + +public class LinkedList extends AbstractList { + private Node first; + private Node last; + + private static class Node { + E element; + Node prev; + Node next; + public Node(Node prev, E element, Node next) { + this.prev = prev; + this.element = element; + this.next = next; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (prev != null) { + sb.append(prev.element); + } else { + sb.append("null"); + } + + sb.append("_").append(element).append("_"); + + if (next != null) { + sb.append(next.element); + } else { + sb.append("null"); + } + + return sb.toString(); + } + } + + @Override + public void clear() { + size = 0; + first = null; + last = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + // size == 0 + // index == 0 + if (index == size) { // 往最后面添加元素 + Node oldLast = last; + last = new Node<>(oldLast, element, null); + if (oldLast == null) { // 这是链表添加的第一个元素 + first = last; + } else { + oldLast.next = last; + } + } else { + Node next = node(index); + Node prev = next.prev; + Node node = new Node<>(prev, element, next); + next.prev = node; + + if (prev == null) { // index == 0 + first = node; + } else { + prev.next = node; + } + } + + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + + Node node = node(index); + Node prev = node.prev; + Node next = node.next; + + if (prev == null) { // index == 0 + first = next; + } else { + prev.next = next; + } + + if (next == null) { // index == size - 1 + last = prev; + } else { + next.prev = prev; + } + + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + if (index < (size >> 1)) { + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } else { + Node node = last; + for (int i = size - 1; i > index; i--) { + node = node.prev; + } + return node; + } + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node); + + node = node.next; + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/List.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/List.java new file mode 100644 index 0000000..d8b5af5 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/05-队列/src/com/mj/list/List.java @@ -0,0 +1,70 @@ +package com.mj.list; + +public interface List { + static final int ELEMENT_NOT_FOUND = -1; + /** + * 清除所有元素 + */ + void clear(); + + /** + * 元素的数量 + * @return + */ + int size(); + + /** + * 是否为空 + * @return + */ + boolean isEmpty(); + + /** + * 是否包含某个元素 + * @param element + * @return + */ + boolean contains(E element); + + /** + * 添加元素到尾部 + * @param element + */ + void add(E element); + + /** + * 获取index位置的元素 + * @param index + * @return + */ + E get(int index); + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + E set(int index, E element); + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + void add(int index, E element); + + /** + * 删除index位置的元素 + * @param index + * @return + */ + E remove(int index); + + /** + * 查看元素的索引 + * @param element + * @return + */ + int indexOf(E element); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.project new file mode 100644 index 0000000..ea6f78f --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.project @@ -0,0 +1,17 @@ + + + 06-二叉搜索树 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree$Node.class new file mode 100644 index 0000000..dea0925 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree$Visitor.class new file mode 100644 index 0000000..9029be9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree.class new file mode 100644 index 0000000..e8e69d3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/BinarySearchTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Car.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Car.class new file mode 100644 index 0000000..6dd90b5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Car.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$1.class new file mode 100644 index 0000000..31ff001 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$2.class new file mode 100644 index 0000000..bda94f1 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$3.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$3.class new file mode 100644 index 0000000..9710ffa Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$3.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$4.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$4.class new file mode 100644 index 0000000..b8a3ce0 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$4.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$5.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$5.class new file mode 100644 index 0000000..cd510d3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$5.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$6.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$6.class new file mode 100644 index 0000000..e85995c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$6.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$PersonComparator.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$PersonComparator.class new file mode 100644 index 0000000..a0e1071 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$PersonComparator.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$PersonComparator2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$PersonComparator2.class new file mode 100644 index 0000000..113fb71 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main$PersonComparator2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main.class new file mode 100644 index 0000000..838283d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Person.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Person.class new file mode 100644 index 0000000..6ac5136 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/Person.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/file/Files.class new file mode 100644 index 0000000..c3dbe12 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTreeInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTreeInfo.class new file mode 100644 index 0000000..c84fa40 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTreeInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTrees$PrintStyle.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTrees$PrintStyle.class new file mode 100644 index 0000000..6d329fd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTrees$PrintStyle.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTrees.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTrees.class new file mode 100644 index 0000000..e00b4bb Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/BinaryTrees.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/InorderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/InorderPrinter.class new file mode 100644 index 0000000..a028890 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/InorderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class new file mode 100644 index 0000000..919f4b3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter$Node.class new file mode 100644 index 0000000..a580601 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter.class new file mode 100644 index 0000000..b6c1394 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/LevelOrderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/Printer.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/Printer.class new file mode 100644 index 0000000..24c28d4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/Printer.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/Strings.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/Strings.class new file mode 100644 index 0000000..dc3c14a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/bin/com/mj/printer/Strings.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/BinarySearchTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/BinarySearchTree.java new file mode 100644 index 0000000..088b787 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/BinarySearchTree.java @@ -0,0 +1,483 @@ +package com.mj; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.Queue; + +import com.mj.printer.BinaryTreeInfo; + +@SuppressWarnings("unchecked") +public class BinarySearchTree implements BinaryTreeInfo { + private int size; + private Node root; + private Comparator comparator; + + public BinarySearchTree() { + this(null); + } + + public BinarySearchTree(Comparator comparator) { + this.comparator = comparator; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + public void add(E element) { + elementNotNullCheck(element); + + // 添加第一个节点 + if (root == null) { + root = new Node<>(element, null); + size++; + return; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(element, node.element); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.element = element; + return; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = new Node<>(element, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + } + + public void remove(E element) { + remove(node(element)); + } + + public boolean contains(E element) { + return node(element) != null; + } + + private void remove(Node node) { + if (node == null) return; + + size--; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.element = s.element; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + } + } + + private Node node(E element) { + Node node = root; + while (node != null) { + int cmp = compare(element, node.element); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + +// /** +// * 前序遍历 +// */ +// public void preorderTraversal() { +// preorderTraversal(root); +// } +// +// private void preorderTraversal(Node node) { +// if (node == null) return; +// +// System.out.println(node.element); +// preorderTraversal(node.left); +// preorderTraversal(node.right); +// } +// +// /** +// * 中序遍历 +// */ +// public void inorderTraversal() { +// inorderTraversal(root); +// } +// +// private void inorderTraversal(Node node) { +// if (node == null) return; +// +// inorderTraversal(node.left); +// System.out.println(node.element); +// inorderTraversal(node.right); +// } +// +// /** +// * 后序遍历 +// */ +// public void postorderTraversal() { +// postorderTraversal(root); +// } +// +// private void postorderTraversal(Node node) { +// if (node == null) return; +// +// postorderTraversal(node.left); +// postorderTraversal(node.right); +// System.out.println(node.element); +// } +// +// /** +// * 层序遍历 +// */ +// public void levelOrderTraversal() { +// if (root == null) return; +// +// Queue> queue = new LinkedList<>(); +// queue.offer(root); +// +// while (!queue.isEmpty()) { +// Node node = queue.poll(); +// System.out.println(node.element); +// +// if (node.left != null) { +// queue.offer(node.left); +// } +// +// if (node.right != null) { +// queue.offer(node.right); +// } +// } +// } + + public void preorder(Visitor visitor) { + if (visitor == null) return; + preorder(root, visitor); + } + + private void preorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + visitor.stop = visitor.visit(node.element); + preorder(node.left, visitor); + preorder(node.right, visitor); + } + + public void inorder(Visitor visitor) { + if (visitor == null) return; + inorder(root, visitor); + } + + private void inorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + inorder(node.left, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + inorder(node.right, visitor); + } + + public void postorder(Visitor visitor) { + if (visitor == null) return; + postorder(root, visitor); + } + + private void postorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + postorder(node.left, visitor); + postorder(node.right, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + } + + public void levelOrder(Visitor visitor) { + if (root == null || visitor == null) return; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (visitor.visit(node.element)) return; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + } + + public boolean isComplete() { + if (root == null) return false; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + boolean leaf = false; + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (leaf && !node.isLeaf()) return false; + + if (node.left != null) { + queue.offer(node.left); + } else if (node.right != null) { // node.left == null && node.right != null + return false; + } + + if (node.right != null) { + queue.offer(node.right); + } else { // node.right == null + leaf = true; + } + } + + return true; + } + +// public boolean isComplete() { +// if (root == null) return false; +// +// Queue> queue = new LinkedList<>(); +// queue.offer(root); +// +// boolean leaf = false; +// while (!queue.isEmpty()) { +// Node node = queue.poll(); +// if (leaf && !node.isLeaf()) return false; +// +// if (node.left != null && node.right != null) { +// queue.offer(node.left); +// queue.offer(node.right); +// } else if (node.left == null && node.right != null) { +// return false; +// } else { // 后面遍历的节点都必须是叶子节点 +// leaf = true; +// if (node.left != null) { +// queue.offer(node.left); +// } +// } +// } +// +// return true; +// } + + public int height() { + if (root == null) return 0; + + // 树的高度 + int height = 0; + // 存储着每一层的元素数量 + int levelSize = 1; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + levelSize--; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + + if (levelSize == 0) { // 意味着即将要访问下一层 + levelSize = queue.size(); + height++; + } + } + + return height; + } + + public int height2() { + return height(root); + } + + private int height(Node node) { + if (node == null) return 0; + return 1 + Math.max(height(node.left), height(node.right)); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + toString(root, sb, ""); + return sb.toString(); + } + + private void toString(Node node, StringBuilder sb, String prefix) { + if (node == null) return; + + toString(node.left, sb, prefix + "L---"); + sb.append(prefix).append(node.element).append("\n"); + toString(node.right, sb, prefix + "R---"); + } + + /** + * @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2 + */ + private int compare(E e1, E e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void elementNotNullCheck(E element) { + if (element == null) { + throw new IllegalArgumentException("element must not be null"); + } + } + + @SuppressWarnings("unused") + private Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + private Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + public static abstract class Visitor { + boolean stop; + /** + * @return 如果返回true,就代表停止遍历 + */ + public abstract boolean visit(E element); + } + + private static class Node { + E element; + Node left; + Node right; + Node parent; + public Node(E element, Node parent) { + this.element = element; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + } + + @Override + public Object root() { + return root; + } + + @Override + public Object left(Object node) { + return ((Node)node).left; + } + + @Override + public Object right(Object node) { + return ((Node)node).right; + } + + @Override + public Object string(Object node) { + Node myNode = (Node)node; + String parentString = "null"; + if (myNode.parent != null) { + parentString = myNode.parent.element.toString(); + } + return myNode.element + "_p(" + parentString + ")"; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Car.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Car.java new file mode 100644 index 0000000..4516cf8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Car.java @@ -0,0 +1,5 @@ +package com.mj; + +public class Car { + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Main.java new file mode 100644 index 0000000..86deef5 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Main.java @@ -0,0 +1,258 @@ +package com.mj; + +import java.util.Comparator; + +import com.mj.BinarySearchTree.Visitor; +import com.mj.file.Files; +import com.mj.printer.BinaryTreeInfo; +import com.mj.printer.BinaryTrees; + +@SuppressWarnings("unused") +public class Main { + + private static class PersonComparator implements Comparator { + public int compare(Person e1, Person e2) { + return e1.getAge() - e2.getAge(); + } + } + + private static class PersonComparator2 implements Comparator { + public int compare(Person e1, Person e2) { + return e2.getAge() - e1.getAge(); + } + } + + static void test1() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 5, 8, 11, 3, 12, 1 + }; + + BinarySearchTree bst = new BinarySearchTree<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + + BinaryTrees.println(bst); + } + + static void test2() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 5, 8, 11, 3, 12, 1 + }; + + BinarySearchTree bst1 = new BinarySearchTree<>(); + for (int i = 0; i < data.length; i++) { + bst1.add(new Person(data[i])); + } + + BinaryTrees.println(bst1); + + BinarySearchTree bst2 = new BinarySearchTree<>(new Comparator() { + public int compare(Person o1, Person o2) { + return o2.getAge() - o1.getAge(); + } + }); + for (int i = 0; i < data.length; i++) { + bst2.add(new Person(data[i])); + } + BinaryTrees.println(bst2); + } + + static void test3() { + BinarySearchTree bst = new BinarySearchTree<>(); + for (int i = 0; i < 40; i++) { + bst.add((int)(Math.random() * 100)); + } + + String str = BinaryTrees.printString(bst); + str += "\n"; + Files.writeToFile("F:/1.txt", str, true); + + // BinaryTrees.println(bst); + } + + static void test4() { + BinaryTrees.println(new BinaryTreeInfo() { + + @Override + public Object string(Object node) { + return node.toString() + "_"; + } + + @Override + public Object root() { + return "A"; + } + + @Override + public Object right(Object node) { + if (node.equals("A")) return "C"; + if (node.equals("C")) return "E"; + return null; + } + + @Override + public Object left(Object node) { + if (node.equals("A")) return "B"; + if (node.equals("C")) return "D"; + return null; + } + }); + + // test3(); + + + /* + * Java的匿名类,类似于iOS中的Block、JS中的闭包(function) + */ + +// BinarySearchTree bst1 = new BinarySearchTree<>(new Comparator() { +// @Override +// public int compare(Person o1, Person o2) { +// return 0; +// } +// }); +// bst1.add(new Person(12)); +// bst1.add(new Person(15)); +// +// BinarySearchTree bst2 = new BinarySearchTree<>(new PersonComparator()); +// bst2.add(new Person(12)); +// bst2.add(new Person(15)); +// + + +// BinarySearchTree bst4 = new BinarySearchTree<>(new Car); +// +// +// java.util.Comparator iComparator; + } + + static void test5() { + BinarySearchTree bst = new BinarySearchTree<>(); + bst.add(new Person(10, "jack")); + bst.add(new Person(12, "rose")); + bst.add(new Person(6, "jim")); + + bst.add(new Person(10, "michael")); + + BinaryTrees.println(bst); + } + + static void test6() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 5 + }; + + BinarySearchTree bst = new BinarySearchTree<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + +// BinarySearchTree bst = new BinarySearchTree<>(); +// for (int i = 0; i < 10; i++) { +// bst.add((int)(Math.random() * 100)); +// } + BinaryTrees.println(bst); + System.out.println(bst.isComplete()); + + // bst.levelOrderTraversal(); + + /* + * 7 + * 4 9 + 2 5 + */ + +// bst.levelOrder(new Visitor() { +// public void visit(Integer element) { +// System.out.print("_" + element + "_ "); +// } +// }); + +// bst.inorder(new Visitor() { +// public void visit(Integer element) { +// System.out.print("_" + (element + 3) + "_ "); +// } +// }); + + // System.out.println(bst.height()); + } + + static void test7() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 5, 8, 11, 3, 12, 1 + }; + + BinarySearchTree bst = new BinarySearchTree<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + + BinaryTrees.println(bst); + + bst.remove(7); + + BinaryTrees.println(bst); + } + + static void test8() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 1 + }; + + BinarySearchTree bst = new BinarySearchTree<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + BinaryTrees.println(bst); + System.out.println(bst.isComplete()); + } + + static void test9() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 1 + }; + + BinarySearchTree bst = new BinarySearchTree<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + BinaryTrees.println(bst); + + bst.preorder(new Visitor() { + public boolean visit(Integer element) { + System.out.print(element + " "); + return element == 2 ? true : false; + } + }); + System.out.println(); + + bst.inorder(new Visitor() { + public boolean visit(Integer element) { + System.out.print(element + " "); + return element == 4 ? true : false; + } + }); + System.out.println(); + + bst.postorder(new Visitor() { + public boolean visit(Integer element) { + System.out.print(element + " "); + return element == 4 ? true : false; + } + }); + System.out.println(); + + bst.levelOrder(new Visitor() { + public boolean visit(Integer element) { + System.out.print(element + " "); + return element == 9 ? true : false; + } + }); + System.out.println(); + } + + public static void main(String[] args) { + test9(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Person.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Person.java new file mode 100644 index 0000000..7248d51 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/Person.java @@ -0,0 +1,37 @@ +package com.mj; + +public class Person implements Comparable { + private int age; + private String name; + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Person(int age) { + this.age = age; + } + + public Person(int age, String name) { + this.age = age; + this.name = name; + } + + @Override + public int compareTo(Person e) { +// if (age > e.age) return 1; +// if (age < e.age) return -1; +// return 0; + return age - e.age; + } + + @Override + public String toString() { + return age + "_" + name; + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/file/Files.java new file mode 100644 index 0000000..6817d28 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/file/Files.java @@ -0,0 +1,33 @@ +package com.mj.file; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +public class Files { + + public static void writeToFile(String filePath, Object data) { + writeToFile(filePath, data, false); + } + + public static void writeToFile(String filePath, Object data, boolean append) { + if (filePath == null || data == null) return; + + try { + File file = new File(filePath); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + + try (FileWriter writer = new FileWriter(file, append); + BufferedWriter out = new BufferedWriter(writer) ) { + out.write(data.toString()); + out.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/BinaryTreeInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/BinaryTreeInfo.java new file mode 100644 index 0000000..d7a6c4d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/BinaryTreeInfo.java @@ -0,0 +1,20 @@ +package com.mj.printer; + +public interface BinaryTreeInfo { + /** + * who is the root node + */ + Object root(); + /** + * how to get the left child of the node + */ + Object left(Object node); + /** + * how to get the right child of the node + */ + Object right(Object node); + /** + * how to print the node + */ + Object string(Object node); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/BinaryTrees.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/BinaryTrees.java new file mode 100644 index 0000000..d3b878a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/BinaryTrees.java @@ -0,0 +1,48 @@ +package com.mj.printer; + +/** + * + * @author MJ Lee + * + */ +public final class BinaryTrees { + + private BinaryTrees() { + } + + public static void print(BinaryTreeInfo tree) { + print(tree, null); + } + + public static void println(BinaryTreeInfo tree) { + println(tree, null); + } + + public static void print(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).print(); + } + + public static void println(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).println(); + } + + public static String printString(BinaryTreeInfo tree) { + return printString(tree, null); + } + + public static String printString(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return null; + return printer(tree, style).printString(); + } + + private static Printer printer(BinaryTreeInfo tree, PrintStyle style) { + if (style == PrintStyle.INORDER) return new InorderPrinter(tree); + return new LevelOrderPrinter(tree); + } + + public enum PrintStyle { + LEVEL_ORDER, INORDER + } +} \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/InorderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/InorderPrinter.java new file mode 100644 index 0000000..85b6211 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/InorderPrinter.java @@ -0,0 +1,89 @@ +package com.mj.printer; + +/** + + ┌──800 + ┌──760 + │ └──600 + ┌──540 + │ └──476 + │ └──445 + ┌──410 + │ └──394 +381 + │ ┌──190 + │ │ └──146 + │ ┌──40 + │ │ └──35 + └──12 + └──9 + + * @author MJ Lee + * + */ +public class InorderPrinter extends Printer { + private static String rightAppend; + private static String leftAppend; + private static String blankAppend; + private static String lineAppend; + static { + int length = 2; + rightAppend = "┌" + Strings.repeat("─", length); + leftAppend = "└" + Strings.repeat("─", length); + blankAppend = Strings.blank(length + 1); + lineAppend = "│" + Strings.blank(length); + } + + public InorderPrinter(BinaryTreeInfo tree) { + super(tree); + } + + @Override + public String printString() { + StringBuilder string = new StringBuilder( + printString(tree.root(), "", "", "")); + string.deleteCharAt(string.length() - 1); + return string.toString(); + } + + /** + * 生成node节点的字符串 + * @param nodePrefix node那一行的前缀字符串 + * @param leftPrefix node整棵左子树的前缀字符串 + * @param rightPrefix node整棵右子树的前缀字符串 + * @return + */ + private String printString( + Object node, + String nodePrefix, + String leftPrefix, + String rightPrefix) { + Object left = tree.left(node); + Object right = tree.right(node); + String string = tree.string(node).toString(); + + int length = string.length(); + if (length % 2 == 0) { + length--; + } + length >>= 1; + + String nodeString = ""; + if (right != null) { + rightPrefix += Strings.blank(length); + nodeString += printString(right, + rightPrefix + rightAppend, + rightPrefix + lineAppend, + rightPrefix + blankAppend); + } + nodeString += nodePrefix + string + "\n"; + if (left != null) { + leftPrefix += Strings.blank(length); + nodeString += printString(left, + leftPrefix + leftAppend, + leftPrefix + blankAppend, + leftPrefix + lineAppend); + } + return nodeString; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/LevelOrderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/LevelOrderPrinter.java new file mode 100644 index 0000000..c7c229c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/LevelOrderPrinter.java @@ -0,0 +1,528 @@ +package com.mj.printer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + + ┌───381────┐ + │ │ +┌─12─┐ ┌─410─┐ +│ │ │ │ +9 ┌─40─┐ 394 ┌─540─┐ + │ │ │ │ + 35 ┌─190 ┌─476 ┌─760─┐ + │ │ │ │ + 146 445 600 800 + + * @author MJ Lee + * + */ +public class LevelOrderPrinter extends Printer { + /** + * 节点之间允许的最小间距(最小只能填1) + */ + private static final int MIN_SPACE = 1; + private Node root; + private int minX; + private int maxWidth; + + public LevelOrderPrinter(BinaryTreeInfo tree) { + super(tree); + + root = new Node(tree.root(), tree); + maxWidth = root.width; + } + + @Override + public String printString() { + // nodes用来存放所有的节点 + List> nodes = new ArrayList<>(); + fillNodes(nodes); + cleanNodes(nodes); + compressNodes(nodes); + addLineNodes(nodes); + + int rowCount = nodes.size(); + + // 构建字符串 + StringBuilder string = new StringBuilder(); + for (int i = 0; i < rowCount; i++) { + if (i != 0) { + string.append("\n"); + } + + List rowNodes = nodes.get(i); + StringBuilder rowSb = new StringBuilder(); + for (Node node : rowNodes) { + int leftSpace = node.x - rowSb.length() - minX; + rowSb.append(Strings.blank(leftSpace)); + rowSb.append(node.string); + } + + string.append(rowSb); + } + + return string.toString(); + } + + /** + * 添加一个元素节点 + */ + private Node addNode(List nodes, Object btNode) { + Node node = null; + if (btNode != null) { + node = new Node(btNode, tree); + maxWidth = Math.max(maxWidth, node.width); + nodes.add(node); + } else { + nodes.add(null); + } + return node; + } + + /** + * 以满二叉树的形式填充节点 + */ + private void fillNodes(List> nodes) { + if (nodes == null) return; + // 第一行 + List firstRowNodes = new ArrayList<>(); + firstRowNodes.add(root); + nodes.add(firstRowNodes); + + // 其他行 + while (true) { + List preRowNodes = nodes.get(nodes.size() - 1); + List rowNodes = new ArrayList<>(); + + boolean notNull = false; + for (Node node : preRowNodes) { + if (node == null) { + rowNodes.add(null); + rowNodes.add(null); + } else { + Node left = addNode(rowNodes, tree.left(node.btNode)); + if (left != null) { + node.left = left; + left.parent = node; + notNull = true; + } + + Node right = addNode(rowNodes, tree.right(node.btNode)); + if (right != null) { + node.right = right; + right.parent = node; + notNull = true; + } + } + } + + // 全是null,就退出 + if (!notNull) break; + nodes.add(rowNodes); + } + } + + /** + * 删除全部null、更新节点的坐标 + */ + private void cleanNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + // 最后一行的节点数量 + int lastRowNodeCount = nodes.get(rowCount - 1).size(); + + // 每个节点之间的间距 + int nodeSpace = maxWidth + 2; + + // 最后一行的长度 + int lastRowLength = lastRowNodeCount * maxWidth + + nodeSpace * (lastRowNodeCount - 1); + + // 空集合 + Collection nullSet = Collections.singleton(null); + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + + int rowNodeCount = rowNodes.size(); + // 节点左右两边的间距 + int allSpace = lastRowLength - (rowNodeCount - 1) * nodeSpace; + int cornerSpace = allSpace / rowNodeCount - maxWidth; + cornerSpace >>= 1; + + int rowLength = 0; + for (int j = 0; j < rowNodeCount; j++) { + if (j != 0) { + // 每个节点之间的间距 + rowLength += nodeSpace; + } + rowLength += cornerSpace; + Node node = rowNodes.get(j); + if (node != null) { + // 居中(由于奇偶数的问题,可能有1个符号的误差) + int deltaX = (maxWidth - node.width) >> 1; + node.x = rowLength + deltaX; + node.y = i; + } + rowLength += maxWidth; + rowLength += cornerSpace; + } + // 删除所有的null + rowNodes.removeAll(nullSet); + } + } + + /** + * 压缩空格 + */ + private void compressNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + for (int i = rowCount - 2; i >= 0; i--) { + List rowNodes = nodes.get(i); + for (Node node : rowNodes) { + Node left = node.left; + Node right = node.right; + if (left == null && right == null) continue; + if (left != null && right != null) { + // 让左右节点对称 + node.balance(left, right); + + // left和right之间可以挪动的最小间距 + int leftEmpty = node.leftBoundEmptyLength(); + int rightEmpty = node.rightBoundEmptyLength(); + int empty = Math.min(leftEmpty, rightEmpty); + empty = Math.min(empty, (right.x - left.rightX()) >> 1); + + // left、right的子节点之间可以挪动的最小间距 + int space = left.minLevelSpaceToRight(right) - MIN_SPACE; + space = Math.min(space >> 1, empty); + + // left、right往中间挪动 + if (space > 0) { + left.translateX(space); + right.translateX(-space); + } + + // 继续挪动 + space = left.minLevelSpaceToRight(right) - MIN_SPACE; + if (space < 1) continue; + + // 可以继续挪动的间距 + leftEmpty = node.leftBoundEmptyLength(); + rightEmpty = node.rightBoundEmptyLength(); + if (leftEmpty < 1 && rightEmpty < 1) continue; + + if (leftEmpty > rightEmpty) { + left.translateX(Math.min(leftEmpty, space)); + } else { + right.translateX(-Math.min(rightEmpty, space)); + } + } else if (left != null) { + left.translateX(node.leftBoundEmptyLength()); + } else { // right != null + right.translateX(-node.rightBoundEmptyLength()); + } + } + } + } + + private void addXLineNode(List curRow, Node parent, int x) { + Node line = new Node("─"); + line.x = x; + line.y = parent.y; + curRow.add(line); + } + + private Node addLineNode(List curRow, List nextRow, Node parent, Node child) { + if (child == null) return null; + + Node top = null; + int topX = child.topLineX(); + if (child == parent.left) { + top = new Node("┌"); + curRow.add(top); + + for (int x = topX + 1; x < parent.x; x++) { + addXLineNode(curRow, parent, x); + } + } else { + for (int x = parent.rightX(); x < topX; x++) { + addXLineNode(curRow, parent, x); + } + + top = new Node("┐"); + curRow.add(top); + } + + // 坐标 + top.x = topX; + top.y = parent.y; + child.y = parent.y + 2; + minX = Math.min(minX, child.x); + + // 竖线 + Node bottom = new Node("│"); + bottom.x = topX; + bottom.y = parent.y + 1; + nextRow.add(bottom); + + return top; + } + + private void addLineNodes(List> nodes) { + List> newNodes = new ArrayList<>(); + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + minX = root.x; + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + if (i == rowCount - 1) { + newNodes.add(rowNodes); + continue; + } + + List newRowNodes = new ArrayList<>(); + newNodes.add(newRowNodes); + + List lineNodes = new ArrayList<>(); + newNodes.add(lineNodes); + for (Node node : rowNodes) { + addLineNode(newRowNodes, lineNodes, node, node.left); + newRowNodes.add(node); + addLineNode(newRowNodes, lineNodes, node, node.right); + } + } + + nodes.clear(); + nodes.addAll(newNodes); + } + + private static class Node { + /** + * 顶部符号距离父节点的最小距离(最小能填0) + */ + private static final int TOP_LINE_SPACE = 1; + + Object btNode; + Node left; + Node right; + Node parent; + /** + * 首字符的位置 + */ + int x; + int y; + int treeHeight; + String string; + int width; + + private void init(String string) { + string = (string == null) ? "null" : string; + string = string.isEmpty() ? " " : string; + + width = string.length(); + this.string = string; + } + + public Node(String string) { + init(string); + } + + public Node(Object btNode, BinaryTreeInfo opetaion) { + init(opetaion.string(btNode).toString()); + + this.btNode = btNode; + } + + /** + * 顶部方向字符的X(极其重要) + * + * @return + */ + private int topLineX() { + // 宽度的一半 + int delta = width; + if (delta % 2 == 0) { + delta--; + } + delta >>= 1; + + if (parent != null && this == parent.left) { + return rightX() - 1 - delta; + } else { + return x + delta; + } + } + + /** + * 右边界的位置(rightX 或者 右子节点topLineX的下一个位置)(极其重要) + */ + private int rightBound() { + if (right == null) return rightX(); + return right.topLineX() + 1; + } + + /** + * 左边界的位置(x 或者 左子节点topLineX)(极其重要) + */ + private int leftBound() { + if (left == null) return x; + return left.topLineX(); + } + + /** + * x ~ 左边界之间的长度(包括左边界字符) + * + * @return + */ + private int leftBoundLength() { + return x - leftBound(); + } + + /** + * rightX ~ 右边界之间的长度(包括右边界字符) + * + * @return + */ + private int rightBoundLength() { + return rightBound() - rightX(); + } + + /** + * 左边界可以清空的长度 + * + * @return + */ + private int leftBoundEmptyLength() { + return leftBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 右边界可以清空的长度 + * + * @return + */ + private int rightBoundEmptyLength() { + return rightBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 让left和right基于this对称 + */ + private void balance(Node left, Node right) { + if (left == null || right == null) + return; + // 【left的尾字符】与【this的首字符】之间的间距 + int deltaLeft = x - left.rightX(); + // 【this的尾字符】与【this的首字符】之间的间距 + int deltaRight = right.x - rightX(); + + int delta = Math.max(deltaLeft, deltaRight); + int newRightX = rightX() + delta; + right.translateX(newRightX - right.x); + + int newLeftX = x - delta - left.width; + left.translateX(newLeftX - left.x); + } + + private int treeHeight(Node node) { + if (node == null) return 0; + if (node.treeHeight != 0) return node.treeHeight; + node.treeHeight = 1 + Math.max( + treeHeight(node.left), treeHeight(node.right)); + return node.treeHeight; + } + + /** + * 和右节点之间的最小层级距离 + */ + private int minLevelSpaceToRight(Node right) { + int thisHeight = treeHeight(this); + int rightHeight = treeHeight(right); + int minSpace = Integer.MAX_VALUE; + for (int i = 0; i < thisHeight && i < rightHeight; i++) { + int space = right.levelInfo(i).leftX + - this.levelInfo(i).rightX; + minSpace = Math.min(minSpace, space); + } + return minSpace; + } + + private LevelInfo levelInfo(int level) { + if (level < 0) return null; + int levelY = y + level; + if (level >= treeHeight(this)) return null; + + List list = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(this); + + // 层序遍历找出第level行的所有节点 + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (levelY == node.y) { + list.add(node); + } else if (node.y > levelY) break; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + + Node left = list.get(0); + Node right = list.get(list.size() - 1); + return new LevelInfo(left, right); + } + + /** + * 尾字符的下一个位置 + */ + public int rightX() { + return x + width; + } + + public void translateX(int deltaX) { + if (deltaX == 0) return; + x += deltaX; + + // 如果是LineNode + if (btNode == null) return; + + if (left != null) { + left.translateX(deltaX); + } + if (right != null) { + right.translateX(deltaX); + } + } + } + + private static class LevelInfo { + int leftX; + int rightX; + + public LevelInfo(Node left, Node right) { + this.leftX = left.leftBound(); + this.rightX = right.rightBound(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/Printer.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/Printer.java new file mode 100644 index 0000000..a8845a1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/Printer.java @@ -0,0 +1,32 @@ +package com.mj.printer; + +public abstract class Printer { + /** + * 二叉树的基本信息 + */ + protected BinaryTreeInfo tree; + + public Printer(BinaryTreeInfo tree) { + this.tree = tree; + } + + /** + * 生成打印的字符串 + */ + public abstract String printString(); + + /** + * 打印后换行 + */ + public void println() { + print(); + System.out.println(); + } + + /** + * 打印 + */ + public void print() { + System.out.print(printString()); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/Strings.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/Strings.java new file mode 100644 index 0000000..83ea770 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树/src/com/mj/printer/Strings.java @@ -0,0 +1,19 @@ +package com.mj.printer; + +public class Strings { + public static String repeat(String string, int count) { + if (string == null) return null; + + StringBuilder builder = new StringBuilder(); + while (count-- > 0) { + builder.append(string); + } + return builder.toString(); + } + + public static String blank(int length) { + if (length < 0) return null; + if (length == 0) return ""; + return String.format("%" + length + "s", ""); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/.gitignore b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/compiler.xml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/compiler.xml new file mode 100644 index 0000000..a1757ae --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/compiler.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/encodings.xml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/encodings.xml new file mode 100644 index 0000000..4987eca --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/misc.xml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/misc.xml new file mode 100644 index 0000000..44ae3bd --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/modules.xml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/modules.xml new file mode 100644 index 0000000..82f1e61 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.project new file mode 100644 index 0000000..f5ad8d4 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.project @@ -0,0 +1,17 @@ + + + 06-二叉搜索树2 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/06-二叉搜索树2.iml b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/06-二叉搜索树2.iml new file mode 100644 index 0000000..c4f1bef --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/06-二叉搜索树2.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/Main.class new file mode 100644 index 0000000..f18c6e4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/file/Files.class new file mode 100644 index 0000000..c3dbe12 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTreeInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTreeInfo.class new file mode 100644 index 0000000..c84fa40 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTreeInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTrees$PrintStyle.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTrees$PrintStyle.class new file mode 100644 index 0000000..6d329fd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTrees$PrintStyle.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTrees.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTrees.class new file mode 100644 index 0000000..e00b4bb Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/BinaryTrees.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/InorderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/InorderPrinter.class new file mode 100644 index 0000000..a028890 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/InorderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class new file mode 100644 index 0000000..919f4b3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter$Node.class new file mode 100644 index 0000000..a580601 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter.class new file mode 100644 index 0000000..b6c1394 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/LevelOrderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/Printer.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/Printer.class new file mode 100644 index 0000000..24c28d4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/Printer.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/Strings.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/Strings.class new file mode 100644 index 0000000..dc3c14a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/printer/Strings.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BST.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BST.class new file mode 100644 index 0000000..60cbe28 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BST.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree$Node.class new file mode 100644 index 0000000..91a9396 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree$Visitor.class new file mode 100644 index 0000000..0ffb21f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree.class new file mode 100644 index 0000000..c68ddba Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/bin/com/mj/tree/BinaryTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/Main.java new file mode 100644 index 0000000..d93156b --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/Main.java @@ -0,0 +1,55 @@ +package com.mj; + +import java.util.Comparator; + +import com.mj.file.Files; +import com.mj.printer.BinaryTreeInfo; +import com.mj.printer.BinaryTrees; +import com.mj.tree.BST; +import com.mj.tree.BinaryTree; +import com.mj.tree.BinaryTree.Visitor; + +@SuppressWarnings("unused") +public class Main { + + static void test1() { + Integer data[] = new Integer[] { + 7, 4, 9, 2, 5, 8, 11, 3, 12, 1 + }; + + BST bst = new BST<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + + BinaryTrees.println(bst); + + bst.remove(7); + + BinaryTrees.println(bst); + } + + static void test2() { + Integer data[] = new Integer[] { + // 7, 4 + // 7, 4, 9 + // 7, 4, 9, 5 + // 7, 4, 9, 2 + // 7, 4, 9, 2, 8 + 7, 4, 9, 2, 1 + }; + + BST bst = new BST<>(); + for (int i = 0; i < data.length; i++) { + bst.add(data[i]); + } + + BinaryTrees.println(bst); + System.out.println("----------------------------------"); + System.out.println(bst.isComplete()); + } + + public static void main(String[] args) { + test2(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/file/Files.java new file mode 100644 index 0000000..6817d28 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/file/Files.java @@ -0,0 +1,33 @@ +package com.mj.file; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +public class Files { + + public static void writeToFile(String filePath, Object data) { + writeToFile(filePath, data, false); + } + + public static void writeToFile(String filePath, Object data, boolean append) { + if (filePath == null || data == null) return; + + try { + File file = new File(filePath); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + + try (FileWriter writer = new FileWriter(file, append); + BufferedWriter out = new BufferedWriter(writer) ) { + out.write(data.toString()); + out.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/BinaryTreeInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/BinaryTreeInfo.java new file mode 100644 index 0000000..d7a6c4d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/BinaryTreeInfo.java @@ -0,0 +1,20 @@ +package com.mj.printer; + +public interface BinaryTreeInfo { + /** + * who is the root node + */ + Object root(); + /** + * how to get the left child of the node + */ + Object left(Object node); + /** + * how to get the right child of the node + */ + Object right(Object node); + /** + * how to print the node + */ + Object string(Object node); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/BinaryTrees.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/BinaryTrees.java new file mode 100644 index 0000000..d3b878a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/BinaryTrees.java @@ -0,0 +1,48 @@ +package com.mj.printer; + +/** + * + * @author MJ Lee + * + */ +public final class BinaryTrees { + + private BinaryTrees() { + } + + public static void print(BinaryTreeInfo tree) { + print(tree, null); + } + + public static void println(BinaryTreeInfo tree) { + println(tree, null); + } + + public static void print(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).print(); + } + + public static void println(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).println(); + } + + public static String printString(BinaryTreeInfo tree) { + return printString(tree, null); + } + + public static String printString(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return null; + return printer(tree, style).printString(); + } + + private static Printer printer(BinaryTreeInfo tree, PrintStyle style) { + if (style == PrintStyle.INORDER) return new InorderPrinter(tree); + return new LevelOrderPrinter(tree); + } + + public enum PrintStyle { + LEVEL_ORDER, INORDER + } +} \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/InorderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/InorderPrinter.java new file mode 100644 index 0000000..85b6211 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/InorderPrinter.java @@ -0,0 +1,89 @@ +package com.mj.printer; + +/** + + ┌──800 + ┌──760 + │ └──600 + ┌──540 + │ └──476 + │ └──445 + ┌──410 + │ └──394 +381 + │ ┌──190 + │ │ └──146 + │ ┌──40 + │ │ └──35 + └──12 + └──9 + + * @author MJ Lee + * + */ +public class InorderPrinter extends Printer { + private static String rightAppend; + private static String leftAppend; + private static String blankAppend; + private static String lineAppend; + static { + int length = 2; + rightAppend = "┌" + Strings.repeat("─", length); + leftAppend = "└" + Strings.repeat("─", length); + blankAppend = Strings.blank(length + 1); + lineAppend = "│" + Strings.blank(length); + } + + public InorderPrinter(BinaryTreeInfo tree) { + super(tree); + } + + @Override + public String printString() { + StringBuilder string = new StringBuilder( + printString(tree.root(), "", "", "")); + string.deleteCharAt(string.length() - 1); + return string.toString(); + } + + /** + * 生成node节点的字符串 + * @param nodePrefix node那一行的前缀字符串 + * @param leftPrefix node整棵左子树的前缀字符串 + * @param rightPrefix node整棵右子树的前缀字符串 + * @return + */ + private String printString( + Object node, + String nodePrefix, + String leftPrefix, + String rightPrefix) { + Object left = tree.left(node); + Object right = tree.right(node); + String string = tree.string(node).toString(); + + int length = string.length(); + if (length % 2 == 0) { + length--; + } + length >>= 1; + + String nodeString = ""; + if (right != null) { + rightPrefix += Strings.blank(length); + nodeString += printString(right, + rightPrefix + rightAppend, + rightPrefix + lineAppend, + rightPrefix + blankAppend); + } + nodeString += nodePrefix + string + "\n"; + if (left != null) { + leftPrefix += Strings.blank(length); + nodeString += printString(left, + leftPrefix + leftAppend, + leftPrefix + blankAppend, + leftPrefix + lineAppend); + } + return nodeString; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/LevelOrderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/LevelOrderPrinter.java new file mode 100644 index 0000000..c7c229c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/LevelOrderPrinter.java @@ -0,0 +1,528 @@ +package com.mj.printer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + + ┌───381────┐ + │ │ +┌─12─┐ ┌─410─┐ +│ │ │ │ +9 ┌─40─┐ 394 ┌─540─┐ + │ │ │ │ + 35 ┌─190 ┌─476 ┌─760─┐ + │ │ │ │ + 146 445 600 800 + + * @author MJ Lee + * + */ +public class LevelOrderPrinter extends Printer { + /** + * 节点之间允许的最小间距(最小只能填1) + */ + private static final int MIN_SPACE = 1; + private Node root; + private int minX; + private int maxWidth; + + public LevelOrderPrinter(BinaryTreeInfo tree) { + super(tree); + + root = new Node(tree.root(), tree); + maxWidth = root.width; + } + + @Override + public String printString() { + // nodes用来存放所有的节点 + List> nodes = new ArrayList<>(); + fillNodes(nodes); + cleanNodes(nodes); + compressNodes(nodes); + addLineNodes(nodes); + + int rowCount = nodes.size(); + + // 构建字符串 + StringBuilder string = new StringBuilder(); + for (int i = 0; i < rowCount; i++) { + if (i != 0) { + string.append("\n"); + } + + List rowNodes = nodes.get(i); + StringBuilder rowSb = new StringBuilder(); + for (Node node : rowNodes) { + int leftSpace = node.x - rowSb.length() - minX; + rowSb.append(Strings.blank(leftSpace)); + rowSb.append(node.string); + } + + string.append(rowSb); + } + + return string.toString(); + } + + /** + * 添加一个元素节点 + */ + private Node addNode(List nodes, Object btNode) { + Node node = null; + if (btNode != null) { + node = new Node(btNode, tree); + maxWidth = Math.max(maxWidth, node.width); + nodes.add(node); + } else { + nodes.add(null); + } + return node; + } + + /** + * 以满二叉树的形式填充节点 + */ + private void fillNodes(List> nodes) { + if (nodes == null) return; + // 第一行 + List firstRowNodes = new ArrayList<>(); + firstRowNodes.add(root); + nodes.add(firstRowNodes); + + // 其他行 + while (true) { + List preRowNodes = nodes.get(nodes.size() - 1); + List rowNodes = new ArrayList<>(); + + boolean notNull = false; + for (Node node : preRowNodes) { + if (node == null) { + rowNodes.add(null); + rowNodes.add(null); + } else { + Node left = addNode(rowNodes, tree.left(node.btNode)); + if (left != null) { + node.left = left; + left.parent = node; + notNull = true; + } + + Node right = addNode(rowNodes, tree.right(node.btNode)); + if (right != null) { + node.right = right; + right.parent = node; + notNull = true; + } + } + } + + // 全是null,就退出 + if (!notNull) break; + nodes.add(rowNodes); + } + } + + /** + * 删除全部null、更新节点的坐标 + */ + private void cleanNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + // 最后一行的节点数量 + int lastRowNodeCount = nodes.get(rowCount - 1).size(); + + // 每个节点之间的间距 + int nodeSpace = maxWidth + 2; + + // 最后一行的长度 + int lastRowLength = lastRowNodeCount * maxWidth + + nodeSpace * (lastRowNodeCount - 1); + + // 空集合 + Collection nullSet = Collections.singleton(null); + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + + int rowNodeCount = rowNodes.size(); + // 节点左右两边的间距 + int allSpace = lastRowLength - (rowNodeCount - 1) * nodeSpace; + int cornerSpace = allSpace / rowNodeCount - maxWidth; + cornerSpace >>= 1; + + int rowLength = 0; + for (int j = 0; j < rowNodeCount; j++) { + if (j != 0) { + // 每个节点之间的间距 + rowLength += nodeSpace; + } + rowLength += cornerSpace; + Node node = rowNodes.get(j); + if (node != null) { + // 居中(由于奇偶数的问题,可能有1个符号的误差) + int deltaX = (maxWidth - node.width) >> 1; + node.x = rowLength + deltaX; + node.y = i; + } + rowLength += maxWidth; + rowLength += cornerSpace; + } + // 删除所有的null + rowNodes.removeAll(nullSet); + } + } + + /** + * 压缩空格 + */ + private void compressNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + for (int i = rowCount - 2; i >= 0; i--) { + List rowNodes = nodes.get(i); + for (Node node : rowNodes) { + Node left = node.left; + Node right = node.right; + if (left == null && right == null) continue; + if (left != null && right != null) { + // 让左右节点对称 + node.balance(left, right); + + // left和right之间可以挪动的最小间距 + int leftEmpty = node.leftBoundEmptyLength(); + int rightEmpty = node.rightBoundEmptyLength(); + int empty = Math.min(leftEmpty, rightEmpty); + empty = Math.min(empty, (right.x - left.rightX()) >> 1); + + // left、right的子节点之间可以挪动的最小间距 + int space = left.minLevelSpaceToRight(right) - MIN_SPACE; + space = Math.min(space >> 1, empty); + + // left、right往中间挪动 + if (space > 0) { + left.translateX(space); + right.translateX(-space); + } + + // 继续挪动 + space = left.minLevelSpaceToRight(right) - MIN_SPACE; + if (space < 1) continue; + + // 可以继续挪动的间距 + leftEmpty = node.leftBoundEmptyLength(); + rightEmpty = node.rightBoundEmptyLength(); + if (leftEmpty < 1 && rightEmpty < 1) continue; + + if (leftEmpty > rightEmpty) { + left.translateX(Math.min(leftEmpty, space)); + } else { + right.translateX(-Math.min(rightEmpty, space)); + } + } else if (left != null) { + left.translateX(node.leftBoundEmptyLength()); + } else { // right != null + right.translateX(-node.rightBoundEmptyLength()); + } + } + } + } + + private void addXLineNode(List curRow, Node parent, int x) { + Node line = new Node("─"); + line.x = x; + line.y = parent.y; + curRow.add(line); + } + + private Node addLineNode(List curRow, List nextRow, Node parent, Node child) { + if (child == null) return null; + + Node top = null; + int topX = child.topLineX(); + if (child == parent.left) { + top = new Node("┌"); + curRow.add(top); + + for (int x = topX + 1; x < parent.x; x++) { + addXLineNode(curRow, parent, x); + } + } else { + for (int x = parent.rightX(); x < topX; x++) { + addXLineNode(curRow, parent, x); + } + + top = new Node("┐"); + curRow.add(top); + } + + // 坐标 + top.x = topX; + top.y = parent.y; + child.y = parent.y + 2; + minX = Math.min(minX, child.x); + + // 竖线 + Node bottom = new Node("│"); + bottom.x = topX; + bottom.y = parent.y + 1; + nextRow.add(bottom); + + return top; + } + + private void addLineNodes(List> nodes) { + List> newNodes = new ArrayList<>(); + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + minX = root.x; + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + if (i == rowCount - 1) { + newNodes.add(rowNodes); + continue; + } + + List newRowNodes = new ArrayList<>(); + newNodes.add(newRowNodes); + + List lineNodes = new ArrayList<>(); + newNodes.add(lineNodes); + for (Node node : rowNodes) { + addLineNode(newRowNodes, lineNodes, node, node.left); + newRowNodes.add(node); + addLineNode(newRowNodes, lineNodes, node, node.right); + } + } + + nodes.clear(); + nodes.addAll(newNodes); + } + + private static class Node { + /** + * 顶部符号距离父节点的最小距离(最小能填0) + */ + private static final int TOP_LINE_SPACE = 1; + + Object btNode; + Node left; + Node right; + Node parent; + /** + * 首字符的位置 + */ + int x; + int y; + int treeHeight; + String string; + int width; + + private void init(String string) { + string = (string == null) ? "null" : string; + string = string.isEmpty() ? " " : string; + + width = string.length(); + this.string = string; + } + + public Node(String string) { + init(string); + } + + public Node(Object btNode, BinaryTreeInfo opetaion) { + init(opetaion.string(btNode).toString()); + + this.btNode = btNode; + } + + /** + * 顶部方向字符的X(极其重要) + * + * @return + */ + private int topLineX() { + // 宽度的一半 + int delta = width; + if (delta % 2 == 0) { + delta--; + } + delta >>= 1; + + if (parent != null && this == parent.left) { + return rightX() - 1 - delta; + } else { + return x + delta; + } + } + + /** + * 右边界的位置(rightX 或者 右子节点topLineX的下一个位置)(极其重要) + */ + private int rightBound() { + if (right == null) return rightX(); + return right.topLineX() + 1; + } + + /** + * 左边界的位置(x 或者 左子节点topLineX)(极其重要) + */ + private int leftBound() { + if (left == null) return x; + return left.topLineX(); + } + + /** + * x ~ 左边界之间的长度(包括左边界字符) + * + * @return + */ + private int leftBoundLength() { + return x - leftBound(); + } + + /** + * rightX ~ 右边界之间的长度(包括右边界字符) + * + * @return + */ + private int rightBoundLength() { + return rightBound() - rightX(); + } + + /** + * 左边界可以清空的长度 + * + * @return + */ + private int leftBoundEmptyLength() { + return leftBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 右边界可以清空的长度 + * + * @return + */ + private int rightBoundEmptyLength() { + return rightBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 让left和right基于this对称 + */ + private void balance(Node left, Node right) { + if (left == null || right == null) + return; + // 【left的尾字符】与【this的首字符】之间的间距 + int deltaLeft = x - left.rightX(); + // 【this的尾字符】与【this的首字符】之间的间距 + int deltaRight = right.x - rightX(); + + int delta = Math.max(deltaLeft, deltaRight); + int newRightX = rightX() + delta; + right.translateX(newRightX - right.x); + + int newLeftX = x - delta - left.width; + left.translateX(newLeftX - left.x); + } + + private int treeHeight(Node node) { + if (node == null) return 0; + if (node.treeHeight != 0) return node.treeHeight; + node.treeHeight = 1 + Math.max( + treeHeight(node.left), treeHeight(node.right)); + return node.treeHeight; + } + + /** + * 和右节点之间的最小层级距离 + */ + private int minLevelSpaceToRight(Node right) { + int thisHeight = treeHeight(this); + int rightHeight = treeHeight(right); + int minSpace = Integer.MAX_VALUE; + for (int i = 0; i < thisHeight && i < rightHeight; i++) { + int space = right.levelInfo(i).leftX + - this.levelInfo(i).rightX; + minSpace = Math.min(minSpace, space); + } + return minSpace; + } + + private LevelInfo levelInfo(int level) { + if (level < 0) return null; + int levelY = y + level; + if (level >= treeHeight(this)) return null; + + List list = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(this); + + // 层序遍历找出第level行的所有节点 + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (levelY == node.y) { + list.add(node); + } else if (node.y > levelY) break; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + + Node left = list.get(0); + Node right = list.get(list.size() - 1); + return new LevelInfo(left, right); + } + + /** + * 尾字符的下一个位置 + */ + public int rightX() { + return x + width; + } + + public void translateX(int deltaX) { + if (deltaX == 0) return; + x += deltaX; + + // 如果是LineNode + if (btNode == null) return; + + if (left != null) { + left.translateX(deltaX); + } + if (right != null) { + right.translateX(deltaX); + } + } + } + + private static class LevelInfo { + int leftX; + int rightX; + + public LevelInfo(Node left, Node right) { + this.leftX = left.leftBound(); + this.rightX = right.rightBound(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/Printer.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/Printer.java new file mode 100644 index 0000000..a8845a1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/Printer.java @@ -0,0 +1,32 @@ +package com.mj.printer; + +public abstract class Printer { + /** + * 二叉树的基本信息 + */ + protected BinaryTreeInfo tree; + + public Printer(BinaryTreeInfo tree) { + this.tree = tree; + } + + /** + * 生成打印的字符串 + */ + public abstract String printString(); + + /** + * 打印后换行 + */ + public void println() { + print(); + System.out.println(); + } + + /** + * 打印 + */ + public void print() { + System.out.print(printString()); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/Strings.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/Strings.java new file mode 100644 index 0000000..83ea770 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/printer/Strings.java @@ -0,0 +1,19 @@ +package com.mj.printer; + +public class Strings { + public static String repeat(String string, int count) { + if (string == null) return null; + + StringBuilder builder = new StringBuilder(); + while (count-- > 0) { + builder.append(string); + } + return builder.toString(); + } + + public static String blank(int length) { + if (length < 0) return null; + if (length == 0) return ""; + return String.format("%" + length + "s", ""); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/tree/BST.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/tree/BST.java new file mode 100644 index 0000000..bc9b7c7 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/tree/BST.java @@ -0,0 +1,131 @@ +package com.mj.tree; + +import java.util.Comparator; + +@SuppressWarnings("unchecked") +public class BST extends BinaryTree { + private Comparator comparator; + + public BST() { + this(null); + } + + public BST(Comparator comparator) { + this.comparator = comparator; + } + + public void add(E element) { + elementNotNullCheck(element); + + // 添加第一个节点 + if (root == null) { + root = new Node<>(element, null); + size++; + return; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(element, node.element); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.element = element; + return; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = new Node<>(element, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + } + + public void remove(E element) { + remove(node(element)); + } + + public boolean contains(E element) { + return node(element) != null; + } + + private void remove(Node node) { + if (node == null) return; + + size--; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.element = s.element; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + } + } + + private Node node(E element) { + Node node = root; + while (node != null) { + int cmp = compare(element, node.element); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + + /** + * @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2 + */ + private int compare(E e1, E e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void elementNotNullCheck(E element) { + if (element == null) { + throw new IllegalArgumentException("element must not be null"); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/tree/BinaryTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/tree/BinaryTree.java new file mode 100644 index 0000000..c251a9b --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/06-二叉搜索树2/src/com/mj/tree/BinaryTree.java @@ -0,0 +1,246 @@ +package com.mj.tree; + +import java.util.LinkedList; +import java.util.Queue; + +import com.mj.printer.BinaryTreeInfo; + +@SuppressWarnings("unchecked") +public class BinaryTree implements BinaryTreeInfo { + protected int size; + protected Node root; + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + public void preorder(Visitor visitor) { + if (visitor == null) return; + preorder(root, visitor); + } + + private void preorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + visitor.stop = visitor.visit(node.element); + preorder(node.left, visitor); + preorder(node.right, visitor); + } + + public void inorder(Visitor visitor) { + if (visitor == null) return; + inorder(root, visitor); + } + + private void inorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + inorder(node.left, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + inorder(node.right, visitor); + } + + public void postorder(Visitor visitor) { + if (visitor == null) return; + postorder(root, visitor); + } + + private void postorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + postorder(node.left, visitor); + postorder(node.right, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + } + + public void levelOrder(Visitor visitor) { + if (root == null || visitor == null) return; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (visitor.visit(node.element)) return; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + } + + public boolean isComplete() { + if (root == null) return false; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + boolean leaf = false; + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (leaf && !node.isLeaf()) return false; + + if (node.left != null) { + queue.offer(node.left); + } else if (node.right != null) { + return false; + } + + if (node.right != null) { + queue.offer(node.right); + } else { // 后面遍历的节点都必须是叶子节点 + leaf = true; + } + } + + return true; + } + + public int height() { + if (root == null) return 0; + + // 树的高度 + int height = 0; + // 存储着每一层的元素数量 + int levelSize = 1; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + levelSize--; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + + if (levelSize == 0) { // 意味着即将要访问下一层 + levelSize = queue.size(); + height++; + } + } + + return height; + } + + public int height2() { + return height(root); + } + + private int height(Node node) { + if (node == null) return 0; + return 1 + Math.max(height(node.left), height(node.right)); + } + + protected Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + protected Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + public static abstract class Visitor { + boolean stop; + /** + * @return 如果返回true,就代表停止遍历 + */ + abstract boolean visit(E element); + } + + protected static class Node { + E element; + Node left; + Node right; + Node parent; + public Node(E element, Node parent) { + this.element = element; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + } + + @Override + public Object root() { + return root; + } + + @Override + public Object left(Object node) { + return ((Node)node).left; + } + + @Override + public Object right(Object node) { + return ((Node)node).right; + } + + @Override + public Object string(Object node) { + Node myNode = (Node)node; + String parentString = "null"; + if (myNode.parent != null) { + parentString = myNode.parent.element.toString(); + } + return myNode.element + "_p(" + parentString + ")"; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.project new file mode 100644 index 0000000..4585c44 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.project @@ -0,0 +1,17 @@ + + + 07-AVL树 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/Main.class new file mode 100644 index 0000000..f577d80 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/file/Files.class new file mode 100644 index 0000000..c3dbe12 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTreeInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTreeInfo.class new file mode 100644 index 0000000..c84fa40 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTreeInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTrees$PrintStyle.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTrees$PrintStyle.class new file mode 100644 index 0000000..6d329fd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTrees$PrintStyle.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTrees.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTrees.class new file mode 100644 index 0000000..e00b4bb Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/BinaryTrees.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/InorderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/InorderPrinter.class new file mode 100644 index 0000000..a028890 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/InorderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class new file mode 100644 index 0000000..919f4b3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter$Node.class new file mode 100644 index 0000000..a580601 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter.class new file mode 100644 index 0000000..b6c1394 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/LevelOrderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/Printer.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/Printer.class new file mode 100644 index 0000000..24c28d4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/Printer.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/Strings.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/Strings.class new file mode 100644 index 0000000..dc3c14a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/printer/Strings.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/AVLTree$AVLNode.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/AVLTree$AVLNode.class new file mode 100644 index 0000000..f1f6cf7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/AVLTree$AVLNode.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/AVLTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/AVLTree.class new file mode 100644 index 0000000..3f6958c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/AVLTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BST.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BST.class new file mode 100644 index 0000000..500fda8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BST.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree$Node.class new file mode 100644 index 0000000..3ca04ef Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree$Visitor.class new file mode 100644 index 0000000..1423438 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree.class new file mode 100644 index 0000000..703b912 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/bin/com/mj/tree/BinaryTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/Main.java new file mode 100644 index 0000000..eb087cf --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/Main.java @@ -0,0 +1,75 @@ +package com.mj; + +import java.util.ArrayList; +import java.util.List; + +import com.mj.file.Files; +import com.mj.printer.BinaryTreeInfo; +import com.mj.printer.BinaryTrees; +import com.mj.tree.AVLTree; +import com.mj.tree.BST; +import com.mj.tree.BinaryTree; +import com.mj.tree.BinaryTree.Visitor; + +@SuppressWarnings("unused") +public class Main { + + static void test1() { + Integer data[] = new Integer[] { + 67, 52, 92, 96, 53, 95, 13, 63, 34, 82, 76, 54, 9, 68, 39 + }; + + AVLTree avl = new AVLTree<>(); + for (int i = 0; i < data.length; i++) { + avl.add(data[i]); +// System.out.println("【" + data[i] + "】"); +// BinaryTrees.println(avl); +// System.out.println("---------------------------------------"); + } + +// for (int i = 0; i < data.length; i++) { +// avl.remove(data[i]); +// System.out.println("【" + data[i] + "】"); +// BinaryTrees.println(avl); +// System.out.println("---------------------------------------"); +// } + + + BinaryTrees.println(avl); + } + + static void test2() { + List data = new ArrayList<>(); + for (int i = 0; i < 100_0000; i++) { + data.add((int)(Math.random() * 100_0000)); + } + + BST bst = new BST<>(); + for (int i = 0; i < data.size(); i++) { + bst.add(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + bst.contains(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + bst.remove(data.get(i)); + } + + AVLTree avl = new AVLTree<>(); + for (int i = 0; i < data.size(); i++) { + avl.add(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + avl.contains(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + avl.remove(data.get(i)); + } + } + + public static void main(String[] args) { + test1(); + + + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/file/Files.java new file mode 100644 index 0000000..6817d28 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/file/Files.java @@ -0,0 +1,33 @@ +package com.mj.file; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +public class Files { + + public static void writeToFile(String filePath, Object data) { + writeToFile(filePath, data, false); + } + + public static void writeToFile(String filePath, Object data, boolean append) { + if (filePath == null || data == null) return; + + try { + File file = new File(filePath); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + + try (FileWriter writer = new FileWriter(file, append); + BufferedWriter out = new BufferedWriter(writer) ) { + out.write(data.toString()); + out.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/BinaryTreeInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/BinaryTreeInfo.java new file mode 100644 index 0000000..d7a6c4d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/BinaryTreeInfo.java @@ -0,0 +1,20 @@ +package com.mj.printer; + +public interface BinaryTreeInfo { + /** + * who is the root node + */ + Object root(); + /** + * how to get the left child of the node + */ + Object left(Object node); + /** + * how to get the right child of the node + */ + Object right(Object node); + /** + * how to print the node + */ + Object string(Object node); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/BinaryTrees.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/BinaryTrees.java new file mode 100644 index 0000000..d3b878a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/BinaryTrees.java @@ -0,0 +1,48 @@ +package com.mj.printer; + +/** + * + * @author MJ Lee + * + */ +public final class BinaryTrees { + + private BinaryTrees() { + } + + public static void print(BinaryTreeInfo tree) { + print(tree, null); + } + + public static void println(BinaryTreeInfo tree) { + println(tree, null); + } + + public static void print(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).print(); + } + + public static void println(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).println(); + } + + public static String printString(BinaryTreeInfo tree) { + return printString(tree, null); + } + + public static String printString(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return null; + return printer(tree, style).printString(); + } + + private static Printer printer(BinaryTreeInfo tree, PrintStyle style) { + if (style == PrintStyle.INORDER) return new InorderPrinter(tree); + return new LevelOrderPrinter(tree); + } + + public enum PrintStyle { + LEVEL_ORDER, INORDER + } +} \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/InorderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/InorderPrinter.java new file mode 100644 index 0000000..85b6211 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/InorderPrinter.java @@ -0,0 +1,89 @@ +package com.mj.printer; + +/** + + ┌──800 + ┌──760 + │ └──600 + ┌──540 + │ └──476 + │ └──445 + ┌──410 + │ └──394 +381 + │ ┌──190 + │ │ └──146 + │ ┌──40 + │ │ └──35 + └──12 + └──9 + + * @author MJ Lee + * + */ +public class InorderPrinter extends Printer { + private static String rightAppend; + private static String leftAppend; + private static String blankAppend; + private static String lineAppend; + static { + int length = 2; + rightAppend = "┌" + Strings.repeat("─", length); + leftAppend = "└" + Strings.repeat("─", length); + blankAppend = Strings.blank(length + 1); + lineAppend = "│" + Strings.blank(length); + } + + public InorderPrinter(BinaryTreeInfo tree) { + super(tree); + } + + @Override + public String printString() { + StringBuilder string = new StringBuilder( + printString(tree.root(), "", "", "")); + string.deleteCharAt(string.length() - 1); + return string.toString(); + } + + /** + * 生成node节点的字符串 + * @param nodePrefix node那一行的前缀字符串 + * @param leftPrefix node整棵左子树的前缀字符串 + * @param rightPrefix node整棵右子树的前缀字符串 + * @return + */ + private String printString( + Object node, + String nodePrefix, + String leftPrefix, + String rightPrefix) { + Object left = tree.left(node); + Object right = tree.right(node); + String string = tree.string(node).toString(); + + int length = string.length(); + if (length % 2 == 0) { + length--; + } + length >>= 1; + + String nodeString = ""; + if (right != null) { + rightPrefix += Strings.blank(length); + nodeString += printString(right, + rightPrefix + rightAppend, + rightPrefix + lineAppend, + rightPrefix + blankAppend); + } + nodeString += nodePrefix + string + "\n"; + if (left != null) { + leftPrefix += Strings.blank(length); + nodeString += printString(left, + leftPrefix + leftAppend, + leftPrefix + blankAppend, + leftPrefix + lineAppend); + } + return nodeString; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/LevelOrderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/LevelOrderPrinter.java new file mode 100644 index 0000000..c7c229c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/LevelOrderPrinter.java @@ -0,0 +1,528 @@ +package com.mj.printer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + + ┌───381────┐ + │ │ +┌─12─┐ ┌─410─┐ +│ │ │ │ +9 ┌─40─┐ 394 ┌─540─┐ + │ │ │ │ + 35 ┌─190 ┌─476 ┌─760─┐ + │ │ │ │ + 146 445 600 800 + + * @author MJ Lee + * + */ +public class LevelOrderPrinter extends Printer { + /** + * 节点之间允许的最小间距(最小只能填1) + */ + private static final int MIN_SPACE = 1; + private Node root; + private int minX; + private int maxWidth; + + public LevelOrderPrinter(BinaryTreeInfo tree) { + super(tree); + + root = new Node(tree.root(), tree); + maxWidth = root.width; + } + + @Override + public String printString() { + // nodes用来存放所有的节点 + List> nodes = new ArrayList<>(); + fillNodes(nodes); + cleanNodes(nodes); + compressNodes(nodes); + addLineNodes(nodes); + + int rowCount = nodes.size(); + + // 构建字符串 + StringBuilder string = new StringBuilder(); + for (int i = 0; i < rowCount; i++) { + if (i != 0) { + string.append("\n"); + } + + List rowNodes = nodes.get(i); + StringBuilder rowSb = new StringBuilder(); + for (Node node : rowNodes) { + int leftSpace = node.x - rowSb.length() - minX; + rowSb.append(Strings.blank(leftSpace)); + rowSb.append(node.string); + } + + string.append(rowSb); + } + + return string.toString(); + } + + /** + * 添加一个元素节点 + */ + private Node addNode(List nodes, Object btNode) { + Node node = null; + if (btNode != null) { + node = new Node(btNode, tree); + maxWidth = Math.max(maxWidth, node.width); + nodes.add(node); + } else { + nodes.add(null); + } + return node; + } + + /** + * 以满二叉树的形式填充节点 + */ + private void fillNodes(List> nodes) { + if (nodes == null) return; + // 第一行 + List firstRowNodes = new ArrayList<>(); + firstRowNodes.add(root); + nodes.add(firstRowNodes); + + // 其他行 + while (true) { + List preRowNodes = nodes.get(nodes.size() - 1); + List rowNodes = new ArrayList<>(); + + boolean notNull = false; + for (Node node : preRowNodes) { + if (node == null) { + rowNodes.add(null); + rowNodes.add(null); + } else { + Node left = addNode(rowNodes, tree.left(node.btNode)); + if (left != null) { + node.left = left; + left.parent = node; + notNull = true; + } + + Node right = addNode(rowNodes, tree.right(node.btNode)); + if (right != null) { + node.right = right; + right.parent = node; + notNull = true; + } + } + } + + // 全是null,就退出 + if (!notNull) break; + nodes.add(rowNodes); + } + } + + /** + * 删除全部null、更新节点的坐标 + */ + private void cleanNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + // 最后一行的节点数量 + int lastRowNodeCount = nodes.get(rowCount - 1).size(); + + // 每个节点之间的间距 + int nodeSpace = maxWidth + 2; + + // 最后一行的长度 + int lastRowLength = lastRowNodeCount * maxWidth + + nodeSpace * (lastRowNodeCount - 1); + + // 空集合 + Collection nullSet = Collections.singleton(null); + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + + int rowNodeCount = rowNodes.size(); + // 节点左右两边的间距 + int allSpace = lastRowLength - (rowNodeCount - 1) * nodeSpace; + int cornerSpace = allSpace / rowNodeCount - maxWidth; + cornerSpace >>= 1; + + int rowLength = 0; + for (int j = 0; j < rowNodeCount; j++) { + if (j != 0) { + // 每个节点之间的间距 + rowLength += nodeSpace; + } + rowLength += cornerSpace; + Node node = rowNodes.get(j); + if (node != null) { + // 居中(由于奇偶数的问题,可能有1个符号的误差) + int deltaX = (maxWidth - node.width) >> 1; + node.x = rowLength + deltaX; + node.y = i; + } + rowLength += maxWidth; + rowLength += cornerSpace; + } + // 删除所有的null + rowNodes.removeAll(nullSet); + } + } + + /** + * 压缩空格 + */ + private void compressNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + for (int i = rowCount - 2; i >= 0; i--) { + List rowNodes = nodes.get(i); + for (Node node : rowNodes) { + Node left = node.left; + Node right = node.right; + if (left == null && right == null) continue; + if (left != null && right != null) { + // 让左右节点对称 + node.balance(left, right); + + // left和right之间可以挪动的最小间距 + int leftEmpty = node.leftBoundEmptyLength(); + int rightEmpty = node.rightBoundEmptyLength(); + int empty = Math.min(leftEmpty, rightEmpty); + empty = Math.min(empty, (right.x - left.rightX()) >> 1); + + // left、right的子节点之间可以挪动的最小间距 + int space = left.minLevelSpaceToRight(right) - MIN_SPACE; + space = Math.min(space >> 1, empty); + + // left、right往中间挪动 + if (space > 0) { + left.translateX(space); + right.translateX(-space); + } + + // 继续挪动 + space = left.minLevelSpaceToRight(right) - MIN_SPACE; + if (space < 1) continue; + + // 可以继续挪动的间距 + leftEmpty = node.leftBoundEmptyLength(); + rightEmpty = node.rightBoundEmptyLength(); + if (leftEmpty < 1 && rightEmpty < 1) continue; + + if (leftEmpty > rightEmpty) { + left.translateX(Math.min(leftEmpty, space)); + } else { + right.translateX(-Math.min(rightEmpty, space)); + } + } else if (left != null) { + left.translateX(node.leftBoundEmptyLength()); + } else { // right != null + right.translateX(-node.rightBoundEmptyLength()); + } + } + } + } + + private void addXLineNode(List curRow, Node parent, int x) { + Node line = new Node("─"); + line.x = x; + line.y = parent.y; + curRow.add(line); + } + + private Node addLineNode(List curRow, List nextRow, Node parent, Node child) { + if (child == null) return null; + + Node top = null; + int topX = child.topLineX(); + if (child == parent.left) { + top = new Node("┌"); + curRow.add(top); + + for (int x = topX + 1; x < parent.x; x++) { + addXLineNode(curRow, parent, x); + } + } else { + for (int x = parent.rightX(); x < topX; x++) { + addXLineNode(curRow, parent, x); + } + + top = new Node("┐"); + curRow.add(top); + } + + // 坐标 + top.x = topX; + top.y = parent.y; + child.y = parent.y + 2; + minX = Math.min(minX, child.x); + + // 竖线 + Node bottom = new Node("│"); + bottom.x = topX; + bottom.y = parent.y + 1; + nextRow.add(bottom); + + return top; + } + + private void addLineNodes(List> nodes) { + List> newNodes = new ArrayList<>(); + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + minX = root.x; + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + if (i == rowCount - 1) { + newNodes.add(rowNodes); + continue; + } + + List newRowNodes = new ArrayList<>(); + newNodes.add(newRowNodes); + + List lineNodes = new ArrayList<>(); + newNodes.add(lineNodes); + for (Node node : rowNodes) { + addLineNode(newRowNodes, lineNodes, node, node.left); + newRowNodes.add(node); + addLineNode(newRowNodes, lineNodes, node, node.right); + } + } + + nodes.clear(); + nodes.addAll(newNodes); + } + + private static class Node { + /** + * 顶部符号距离父节点的最小距离(最小能填0) + */ + private static final int TOP_LINE_SPACE = 1; + + Object btNode; + Node left; + Node right; + Node parent; + /** + * 首字符的位置 + */ + int x; + int y; + int treeHeight; + String string; + int width; + + private void init(String string) { + string = (string == null) ? "null" : string; + string = string.isEmpty() ? " " : string; + + width = string.length(); + this.string = string; + } + + public Node(String string) { + init(string); + } + + public Node(Object btNode, BinaryTreeInfo opetaion) { + init(opetaion.string(btNode).toString()); + + this.btNode = btNode; + } + + /** + * 顶部方向字符的X(极其重要) + * + * @return + */ + private int topLineX() { + // 宽度的一半 + int delta = width; + if (delta % 2 == 0) { + delta--; + } + delta >>= 1; + + if (parent != null && this == parent.left) { + return rightX() - 1 - delta; + } else { + return x + delta; + } + } + + /** + * 右边界的位置(rightX 或者 右子节点topLineX的下一个位置)(极其重要) + */ + private int rightBound() { + if (right == null) return rightX(); + return right.topLineX() + 1; + } + + /** + * 左边界的位置(x 或者 左子节点topLineX)(极其重要) + */ + private int leftBound() { + if (left == null) return x; + return left.topLineX(); + } + + /** + * x ~ 左边界之间的长度(包括左边界字符) + * + * @return + */ + private int leftBoundLength() { + return x - leftBound(); + } + + /** + * rightX ~ 右边界之间的长度(包括右边界字符) + * + * @return + */ + private int rightBoundLength() { + return rightBound() - rightX(); + } + + /** + * 左边界可以清空的长度 + * + * @return + */ + private int leftBoundEmptyLength() { + return leftBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 右边界可以清空的长度 + * + * @return + */ + private int rightBoundEmptyLength() { + return rightBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 让left和right基于this对称 + */ + private void balance(Node left, Node right) { + if (left == null || right == null) + return; + // 【left的尾字符】与【this的首字符】之间的间距 + int deltaLeft = x - left.rightX(); + // 【this的尾字符】与【this的首字符】之间的间距 + int deltaRight = right.x - rightX(); + + int delta = Math.max(deltaLeft, deltaRight); + int newRightX = rightX() + delta; + right.translateX(newRightX - right.x); + + int newLeftX = x - delta - left.width; + left.translateX(newLeftX - left.x); + } + + private int treeHeight(Node node) { + if (node == null) return 0; + if (node.treeHeight != 0) return node.treeHeight; + node.treeHeight = 1 + Math.max( + treeHeight(node.left), treeHeight(node.right)); + return node.treeHeight; + } + + /** + * 和右节点之间的最小层级距离 + */ + private int minLevelSpaceToRight(Node right) { + int thisHeight = treeHeight(this); + int rightHeight = treeHeight(right); + int minSpace = Integer.MAX_VALUE; + for (int i = 0; i < thisHeight && i < rightHeight; i++) { + int space = right.levelInfo(i).leftX + - this.levelInfo(i).rightX; + minSpace = Math.min(minSpace, space); + } + return minSpace; + } + + private LevelInfo levelInfo(int level) { + if (level < 0) return null; + int levelY = y + level; + if (level >= treeHeight(this)) return null; + + List list = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(this); + + // 层序遍历找出第level行的所有节点 + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (levelY == node.y) { + list.add(node); + } else if (node.y > levelY) break; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + + Node left = list.get(0); + Node right = list.get(list.size() - 1); + return new LevelInfo(left, right); + } + + /** + * 尾字符的下一个位置 + */ + public int rightX() { + return x + width; + } + + public void translateX(int deltaX) { + if (deltaX == 0) return; + x += deltaX; + + // 如果是LineNode + if (btNode == null) return; + + if (left != null) { + left.translateX(deltaX); + } + if (right != null) { + right.translateX(deltaX); + } + } + } + + private static class LevelInfo { + int leftX; + int rightX; + + public LevelInfo(Node left, Node right) { + this.leftX = left.leftBound(); + this.rightX = right.rightBound(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/Printer.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/Printer.java new file mode 100644 index 0000000..a8845a1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/Printer.java @@ -0,0 +1,32 @@ +package com.mj.printer; + +public abstract class Printer { + /** + * 二叉树的基本信息 + */ + protected BinaryTreeInfo tree; + + public Printer(BinaryTreeInfo tree) { + this.tree = tree; + } + + /** + * 生成打印的字符串 + */ + public abstract String printString(); + + /** + * 打印后换行 + */ + public void println() { + print(); + System.out.println(); + } + + /** + * 打印 + */ + public void print() { + System.out.print(printString()); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/Strings.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/Strings.java new file mode 100644 index 0000000..83ea770 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/printer/Strings.java @@ -0,0 +1,19 @@ +package com.mj.printer; + +public class Strings { + public static String repeat(String string, int count) { + if (string == null) return null; + + StringBuilder builder = new StringBuilder(); + while (count-- > 0) { + builder.append(string); + } + return builder.toString(); + } + + public static String blank(int length) { + if (length < 0) return null; + if (length == 0) return ""; + return String.format("%" + length + "s", ""); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/AVLTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/AVLTree.java new file mode 100644 index 0000000..5ccd7a8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/AVLTree.java @@ -0,0 +1,214 @@ +package com.mj.tree; + +import java.util.Comparator; + +public class AVLTree extends BST { + public AVLTree() { + this(null); + } + + public AVLTree(Comparator comparator) { + super(comparator); + } + + @Override + protected void afterAdd(Node node) { + while ((node = node.parent) != null) { + if (isBalanced(node)) { + // 更新高度 + updateHeight(node); + } else { + // 恢复平衡 + rebalance(node); + // 整棵树恢复平衡 + break; + } + } + } + + @Override + protected void afterRemove(Node node) { + while ((node = node.parent) != null) { + if (isBalanced(node)) { + // 更新高度 + updateHeight(node); + } else { + // 恢复平衡 + rebalance(node); + } + } + } + + @Override + protected Node createNode(E element, Node parent) { + return new AVLNode<>(element, parent); + } + + /** + * 恢复平衡 + * @param grand 高度最低的那个不平衡节点 + */ + @SuppressWarnings("unused") + private void rebalance2(Node grand) { + Node parent = ((AVLNode)grand).tallerChild(); + Node node = ((AVLNode)parent).tallerChild(); + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + rotateRight(grand); + } else { // LR + rotateLeft(parent); + rotateRight(grand); + } + } else { // R + if (node.isLeftChild()) { // RL + rotateRight(parent); + rotateLeft(grand); + } else { // RR + rotateLeft(grand); + } + } + } + /** + * 恢复平衡 + * @param grand 高度最低的那个不平衡节点 + */ + private void rebalance(Node grand) { + Node parent = ((AVLNode)grand).tallerChild(); + Node node = ((AVLNode)parent).tallerChild(); + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + rotate(grand, node, node.right, parent, parent.right, grand); + } else { // LR + rotate(grand, parent, node.left, node, node.right, grand); + } + } else { // R + if (node.isLeftChild()) { // RL + rotate(grand, grand, node.left, node, node.right, parent); + } else { // RR + rotate(grand, grand, parent.left, parent, node.left, node); + } + } + } + + private void rotate( + Node r, // 子树的根节点 + Node b, Node c, + Node d, + Node e, Node f) { + // 让d成为这棵子树的根节点 + d.parent = r.parent; + if (r.isLeftChild()) { + r.parent.left = d; + } else if (r.isRightChild()) { + r.parent.right = d; + } else { + root = d; + } + + //b-c + b.right = c; + if (c != null) { + c.parent = b; + } + updateHeight(b); + + // e-f + f.left = e; + if (e != null) { + e.parent = f; + } + updateHeight(f); + + // b-d-f + d.left = b; + d.right = f; + b.parent = d; + f.parent = d; + updateHeight(d); + } + + private void rotateLeft(Node grand) { + Node parent = grand.right; + Node child = parent.left; + grand.right = child; + parent.left = grand; + afterRotate(grand, parent, child); + } + + private void rotateRight(Node grand) { + Node parent = grand.left; + Node child = parent.right; + grand.left = child; + parent.right = grand; + afterRotate(grand, parent, child); + } + + private void afterRotate(Node grand, Node parent, Node child) { + // 让parent称为子树的根节点 + parent.parent = grand.parent; + if (grand.isLeftChild()) { + grand.parent.left = parent; + } else if (grand.isRightChild()) { + grand.parent.right = parent; + } else { // grand是root节点 + root = parent; + } + + // 更新child的parent + if (child != null) { + child.parent = grand; + } + + // 更新grand的parent + grand.parent = parent; + + // 更新高度 + updateHeight(grand); + updateHeight(parent); + } + + private boolean isBalanced(Node node) { + return Math.abs(((AVLNode)node).balanceFactor()) <= 1; + } + + private void updateHeight(Node node) { + ((AVLNode)node).updateHeight(); + } + + private static class AVLNode extends Node { + int height = 1; + + public AVLNode(E element, Node parent) { + super(element, parent); + } + + public int balanceFactor() { + int leftHeight = left == null ? 0 : ((AVLNode)left).height; + int rightHeight = right == null ? 0 : ((AVLNode)right).height; + return leftHeight - rightHeight; + } + + public void updateHeight() { + int leftHeight = left == null ? 0 : ((AVLNode)left).height; + int rightHeight = right == null ? 0 : ((AVLNode)right).height; + height = 1 + Math.max(leftHeight, rightHeight); + } + + public Node tallerChild() { + int leftHeight = left == null ? 0 : ((AVLNode)left).height; + int rightHeight = right == null ? 0 : ((AVLNode)right).height; + if (leftHeight > rightHeight) return left; + if (leftHeight < rightHeight) return right; + return isLeftChild() ? left : right; + } + + @Override + public String toString() { + String parentString = "null"; + if (parent != null) { + parentString = parent.element.toString(); + } + return element + "_p(" + parentString + ")_h(" + height + ")"; + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/BST.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/BST.java new file mode 100644 index 0000000..8b90656 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/BST.java @@ -0,0 +1,158 @@ +package com.mj.tree; + +import java.util.Comparator; + +@SuppressWarnings("unchecked") +public class BST extends BinaryTree { + private Comparator comparator; + + public BST() { + this(null); + } + + public BST(Comparator comparator) { + this.comparator = comparator; + } + + public void add(E element) { + elementNotNullCheck(element); + + // 添加第一个节点 + if (root == null) { + root = createNode(element, null); + size++; + + // 新添加节点之后的处理 + afterAdd(root); + return; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(element, node.element); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.element = element; + return; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = createNode(element, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + + // 新添加节点之后的处理 + afterAdd(newNode); + } + + /** + * 添加node之后的调整 + * @param node 新添加的节点 + */ + protected void afterAdd(Node node) { } + + /** + * 删除node之后的调整 + * @param node 被删除的节点 + */ + protected void afterRemove(Node node) { } + + public void remove(E element) { + remove(node(element)); + } + + public boolean contains(E element) { + return node(element) != null; + } + + private void remove(Node node) { + if (node == null) return; + + size--; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.element = s.element; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + + // 删除节点之后的处理 + afterRemove(node); + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + + // 删除节点之后的处理 + afterRemove(node); + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + + // 删除节点之后的处理 + afterRemove(node); + } + } + + private Node node(E element) { + Node node = root; + while (node != null) { + int cmp = compare(element, node.element); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + + /** + * @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2 + */ + private int compare(E e1, E e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void elementNotNullCheck(E element) { + if (element == null) { + throw new IllegalArgumentException("element must not be null"); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/BinaryTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/BinaryTree.java new file mode 100644 index 0000000..5a82a70 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/src/com/mj/tree/BinaryTree.java @@ -0,0 +1,265 @@ +package com.mj.tree; + +import java.util.LinkedList; +import java.util.Queue; + +import com.mj.printer.BinaryTreeInfo; + +@SuppressWarnings("unchecked") +public class BinaryTree implements BinaryTreeInfo { + protected int size; + protected Node root; + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + public void preorder(Visitor visitor) { + if (visitor == null) return; + preorder(root, visitor); + } + + private void preorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + visitor.stop = visitor.visit(node.element); + preorder(node.left, visitor); + preorder(node.right, visitor); + } + + public void inorder(Visitor visitor) { + if (visitor == null) return; + inorder(root, visitor); + } + + private void inorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + inorder(node.left, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + inorder(node.right, visitor); + } + + public void postorder(Visitor visitor) { + if (visitor == null) return; + postorder(root, visitor); + } + + private void postorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + postorder(node.left, visitor); + postorder(node.right, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + } + + public void levelOrder(Visitor visitor) { + if (root == null || visitor == null) return; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (visitor.visit(node.element)) return; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + } + + public boolean isComplete() { + if (root == null) return false; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + boolean leaf = false; + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (leaf && !node.isLeaf()) return false; + + if (node.left != null) { + queue.offer(node.left); + } else if (node.right != null) { + return false; + } + + if (node.right != null) { + queue.offer(node.right); + } else { // 后面遍历的节点都必须是叶子节点 + leaf = true; + } + } + + return true; + } + + public int height() { + if (root == null) return 0; + + // 树的高度 + int height = 0; + // 存储着每一层的元素数量 + int levelSize = 1; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + levelSize--; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + + if (levelSize == 0) { // 意味着即将要访问下一层 + levelSize = queue.size(); + height++; + } + } + + return height; + } + + public int height2() { + return height(root); + } + + private int height(Node node) { + if (node == null) return 0; + return 1 + Math.max(height(node.left), height(node.right)); + } + + protected Node createNode(E element, Node parent) { + return new Node<>(element, parent); + } + + protected Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + protected Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + public static abstract class Visitor { + boolean stop; + /** + * @return 如果返回true,就代表停止遍历 + */ + abstract boolean visit(E element); + } + + protected static class Node { + E element; + Node left; + Node right; + Node parent; + public Node(E element, Node parent) { + this.element = element; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + + public boolean isLeftChild() { + return parent != null && this == parent.left; + } + + public boolean isRightChild() { + return parent != null && this == parent.right; + } + + public Node sibling() { + if (isLeftChild()) { + return parent.right; + } + + if (isRightChild()) { + return parent.left; + } + + return null; + } + } + + @Override + public Object root() { + return root; + } + + @Override + public Object left(Object node) { + return ((Node)node).left; + } + + @Override + public Object right(Object node) { + return ((Node)node).right; + } + + @Override + public Object string(Object node) { + return node; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.project new file mode 100644 index 0000000..852b823 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.project @@ -0,0 +1,17 @@ + + + 08-红黑树 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/Main.class new file mode 100644 index 0000000..1b415f0 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/file/Files.class new file mode 100644 index 0000000..c3dbe12 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTreeInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTreeInfo.class new file mode 100644 index 0000000..c84fa40 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTreeInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTrees$PrintStyle.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTrees$PrintStyle.class new file mode 100644 index 0000000..6d329fd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTrees$PrintStyle.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTrees.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTrees.class new file mode 100644 index 0000000..e00b4bb Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/BinaryTrees.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/InorderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/InorderPrinter.class new file mode 100644 index 0000000..a028890 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/InorderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class new file mode 100644 index 0000000..919f4b3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter$Node.class new file mode 100644 index 0000000..a580601 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter.class new file mode 100644 index 0000000..b6c1394 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/LevelOrderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/Printer.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/Printer.class new file mode 100644 index 0000000..24c28d4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/Printer.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/Strings.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/Strings.class new file mode 100644 index 0000000..dc3c14a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/printer/Strings.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/AVLTree$AVLNode.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/AVLTree$AVLNode.class new file mode 100644 index 0000000..d50d585 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/AVLTree$AVLNode.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/AVLTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/AVLTree.class new file mode 100644 index 0000000..7fdfa77 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/AVLTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BBST.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BBST.class new file mode 100644 index 0000000..dc17fc6 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BBST.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BST.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BST.class new file mode 100644 index 0000000..069769d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BST.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree$Node.class new file mode 100644 index 0000000..3ca04ef Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree$Visitor.class new file mode 100644 index 0000000..1423438 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree.class new file mode 100644 index 0000000..703b912 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/BinaryTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/RBTree$RBNode.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/RBTree$RBNode.class new file mode 100644 index 0000000..29cf929 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/RBTree$RBNode.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/RBTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/RBTree.class new file mode 100644 index 0000000..20c5def Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/bin/com/mj/tree/RBTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/Main.java new file mode 100644 index 0000000..458be9c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/Main.java @@ -0,0 +1,108 @@ +package com.mj; + +import java.util.ArrayList; +import java.util.List; + +import com.mj.file.Files; +import com.mj.printer.BinaryTreeInfo; +import com.mj.printer.BinaryTrees; +import com.mj.tree.AVLTree; +import com.mj.tree.BST; +import com.mj.tree.BinaryTree; +import com.mj.tree.RBTree; +import com.mj.tree.BinaryTree.Visitor; + +@SuppressWarnings("unused") +public class Main { + + static void test1() { + Integer data[] = new Integer[] { + 67, 52, 92, 96, 53, 95, 13, 63, 34, 82, 76, 54, 9, 68, 39 + }; + + AVLTree avl = new AVLTree<>(); + for (int i = 0; i < data.length; i++) { + avl.add(data[i]); +// System.out.println("【" + data[i] + "】"); +// BinaryTrees.println(avl); +// System.out.println("---------------------------------------"); + } + +// for (int i = 0; i < data.length; i++) { +// avl.remove(data[i]); +// System.out.println("【" + data[i] + "】"); +// BinaryTrees.println(avl); +// System.out.println("---------------------------------------"); +// } + + + BinaryTrees.println(avl); + } + + static void test2() { + List data = new ArrayList<>(); + for (int i = 0; i < 100_0000; i++) { + data.add((int)(Math.random() * 100_0000)); + } + + BST bst = new BST<>(); + for (int i = 0; i < data.size(); i++) { + bst.add(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + bst.contains(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + bst.remove(data.get(i)); + } + + AVLTree avl = new AVLTree<>(); + for (int i = 0; i < data.size(); i++) { + avl.add(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + avl.contains(data.get(i)); + } + for (int i = 0; i < data.size(); i++) { + avl.remove(data.get(i)); + } + } + + static void test3() { + Integer data[] = new Integer[] { + 55, 87, 56, 74, 96, 22, 62, 20, 70, 68, 90, 50 + }; + + RBTree rb = new RBTree<>(); + for (int i = 0; i < data.length; i++) { + rb.add(data[i]); + System.out.println("【" + data[i] + "】"); + BinaryTrees.println(rb); + System.out.println("---------------------------------------"); + } + } + + static void test4() { + Integer data[] = new Integer[] { + 55, 87, 56, 74, 96, 22, 62, 20, 70, 68, 90, 50 + }; + + RBTree rb = new RBTree<>(); + for (int i = 0; i < data.length; i++) { + rb.add(data[i]); + } + + BinaryTrees.println(rb); + + for (int i = 0; i < data.length; i++) { + rb.remove(data[i]); + System.out.println("---------------------------------------"); + System.out.println("【" + data[i] + "】"); + BinaryTrees.println(rb); + } + } + + public static void main(String[] args) { + test4(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/file/Files.java new file mode 100644 index 0000000..6817d28 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/file/Files.java @@ -0,0 +1,33 @@ +package com.mj.file; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +public class Files { + + public static void writeToFile(String filePath, Object data) { + writeToFile(filePath, data, false); + } + + public static void writeToFile(String filePath, Object data, boolean append) { + if (filePath == null || data == null) return; + + try { + File file = new File(filePath); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + + try (FileWriter writer = new FileWriter(file, append); + BufferedWriter out = new BufferedWriter(writer) ) { + out.write(data.toString()); + out.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/BinaryTreeInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/BinaryTreeInfo.java new file mode 100644 index 0000000..d7a6c4d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/BinaryTreeInfo.java @@ -0,0 +1,20 @@ +package com.mj.printer; + +public interface BinaryTreeInfo { + /** + * who is the root node + */ + Object root(); + /** + * how to get the left child of the node + */ + Object left(Object node); + /** + * how to get the right child of the node + */ + Object right(Object node); + /** + * how to print the node + */ + Object string(Object node); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/BinaryTrees.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/BinaryTrees.java new file mode 100644 index 0000000..d3b878a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/BinaryTrees.java @@ -0,0 +1,48 @@ +package com.mj.printer; + +/** + * + * @author MJ Lee + * + */ +public final class BinaryTrees { + + private BinaryTrees() { + } + + public static void print(BinaryTreeInfo tree) { + print(tree, null); + } + + public static void println(BinaryTreeInfo tree) { + println(tree, null); + } + + public static void print(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).print(); + } + + public static void println(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).println(); + } + + public static String printString(BinaryTreeInfo tree) { + return printString(tree, null); + } + + public static String printString(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return null; + return printer(tree, style).printString(); + } + + private static Printer printer(BinaryTreeInfo tree, PrintStyle style) { + if (style == PrintStyle.INORDER) return new InorderPrinter(tree); + return new LevelOrderPrinter(tree); + } + + public enum PrintStyle { + LEVEL_ORDER, INORDER + } +} \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/InorderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/InorderPrinter.java new file mode 100644 index 0000000..85b6211 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/InorderPrinter.java @@ -0,0 +1,89 @@ +package com.mj.printer; + +/** + + ┌──800 + ┌──760 + │ └──600 + ┌──540 + │ └──476 + │ └──445 + ┌──410 + │ └──394 +381 + │ ┌──190 + │ │ └──146 + │ ┌──40 + │ │ └──35 + └──12 + └──9 + + * @author MJ Lee + * + */ +public class InorderPrinter extends Printer { + private static String rightAppend; + private static String leftAppend; + private static String blankAppend; + private static String lineAppend; + static { + int length = 2; + rightAppend = "┌" + Strings.repeat("─", length); + leftAppend = "└" + Strings.repeat("─", length); + blankAppend = Strings.blank(length + 1); + lineAppend = "│" + Strings.blank(length); + } + + public InorderPrinter(BinaryTreeInfo tree) { + super(tree); + } + + @Override + public String printString() { + StringBuilder string = new StringBuilder( + printString(tree.root(), "", "", "")); + string.deleteCharAt(string.length() - 1); + return string.toString(); + } + + /** + * 生成node节点的字符串 + * @param nodePrefix node那一行的前缀字符串 + * @param leftPrefix node整棵左子树的前缀字符串 + * @param rightPrefix node整棵右子树的前缀字符串 + * @return + */ + private String printString( + Object node, + String nodePrefix, + String leftPrefix, + String rightPrefix) { + Object left = tree.left(node); + Object right = tree.right(node); + String string = tree.string(node).toString(); + + int length = string.length(); + if (length % 2 == 0) { + length--; + } + length >>= 1; + + String nodeString = ""; + if (right != null) { + rightPrefix += Strings.blank(length); + nodeString += printString(right, + rightPrefix + rightAppend, + rightPrefix + lineAppend, + rightPrefix + blankAppend); + } + nodeString += nodePrefix + string + "\n"; + if (left != null) { + leftPrefix += Strings.blank(length); + nodeString += printString(left, + leftPrefix + leftAppend, + leftPrefix + blankAppend, + leftPrefix + lineAppend); + } + return nodeString; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/LevelOrderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/LevelOrderPrinter.java new file mode 100644 index 0000000..c7c229c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/LevelOrderPrinter.java @@ -0,0 +1,528 @@ +package com.mj.printer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + + ┌───381────┐ + │ │ +┌─12─┐ ┌─410─┐ +│ │ │ │ +9 ┌─40─┐ 394 ┌─540─┐ + │ │ │ │ + 35 ┌─190 ┌─476 ┌─760─┐ + │ │ │ │ + 146 445 600 800 + + * @author MJ Lee + * + */ +public class LevelOrderPrinter extends Printer { + /** + * 节点之间允许的最小间距(最小只能填1) + */ + private static final int MIN_SPACE = 1; + private Node root; + private int minX; + private int maxWidth; + + public LevelOrderPrinter(BinaryTreeInfo tree) { + super(tree); + + root = new Node(tree.root(), tree); + maxWidth = root.width; + } + + @Override + public String printString() { + // nodes用来存放所有的节点 + List> nodes = new ArrayList<>(); + fillNodes(nodes); + cleanNodes(nodes); + compressNodes(nodes); + addLineNodes(nodes); + + int rowCount = nodes.size(); + + // 构建字符串 + StringBuilder string = new StringBuilder(); + for (int i = 0; i < rowCount; i++) { + if (i != 0) { + string.append("\n"); + } + + List rowNodes = nodes.get(i); + StringBuilder rowSb = new StringBuilder(); + for (Node node : rowNodes) { + int leftSpace = node.x - rowSb.length() - minX; + rowSb.append(Strings.blank(leftSpace)); + rowSb.append(node.string); + } + + string.append(rowSb); + } + + return string.toString(); + } + + /** + * 添加一个元素节点 + */ + private Node addNode(List nodes, Object btNode) { + Node node = null; + if (btNode != null) { + node = new Node(btNode, tree); + maxWidth = Math.max(maxWidth, node.width); + nodes.add(node); + } else { + nodes.add(null); + } + return node; + } + + /** + * 以满二叉树的形式填充节点 + */ + private void fillNodes(List> nodes) { + if (nodes == null) return; + // 第一行 + List firstRowNodes = new ArrayList<>(); + firstRowNodes.add(root); + nodes.add(firstRowNodes); + + // 其他行 + while (true) { + List preRowNodes = nodes.get(nodes.size() - 1); + List rowNodes = new ArrayList<>(); + + boolean notNull = false; + for (Node node : preRowNodes) { + if (node == null) { + rowNodes.add(null); + rowNodes.add(null); + } else { + Node left = addNode(rowNodes, tree.left(node.btNode)); + if (left != null) { + node.left = left; + left.parent = node; + notNull = true; + } + + Node right = addNode(rowNodes, tree.right(node.btNode)); + if (right != null) { + node.right = right; + right.parent = node; + notNull = true; + } + } + } + + // 全是null,就退出 + if (!notNull) break; + nodes.add(rowNodes); + } + } + + /** + * 删除全部null、更新节点的坐标 + */ + private void cleanNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + // 最后一行的节点数量 + int lastRowNodeCount = nodes.get(rowCount - 1).size(); + + // 每个节点之间的间距 + int nodeSpace = maxWidth + 2; + + // 最后一行的长度 + int lastRowLength = lastRowNodeCount * maxWidth + + nodeSpace * (lastRowNodeCount - 1); + + // 空集合 + Collection nullSet = Collections.singleton(null); + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + + int rowNodeCount = rowNodes.size(); + // 节点左右两边的间距 + int allSpace = lastRowLength - (rowNodeCount - 1) * nodeSpace; + int cornerSpace = allSpace / rowNodeCount - maxWidth; + cornerSpace >>= 1; + + int rowLength = 0; + for (int j = 0; j < rowNodeCount; j++) { + if (j != 0) { + // 每个节点之间的间距 + rowLength += nodeSpace; + } + rowLength += cornerSpace; + Node node = rowNodes.get(j); + if (node != null) { + // 居中(由于奇偶数的问题,可能有1个符号的误差) + int deltaX = (maxWidth - node.width) >> 1; + node.x = rowLength + deltaX; + node.y = i; + } + rowLength += maxWidth; + rowLength += cornerSpace; + } + // 删除所有的null + rowNodes.removeAll(nullSet); + } + } + + /** + * 压缩空格 + */ + private void compressNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + for (int i = rowCount - 2; i >= 0; i--) { + List rowNodes = nodes.get(i); + for (Node node : rowNodes) { + Node left = node.left; + Node right = node.right; + if (left == null && right == null) continue; + if (left != null && right != null) { + // 让左右节点对称 + node.balance(left, right); + + // left和right之间可以挪动的最小间距 + int leftEmpty = node.leftBoundEmptyLength(); + int rightEmpty = node.rightBoundEmptyLength(); + int empty = Math.min(leftEmpty, rightEmpty); + empty = Math.min(empty, (right.x - left.rightX()) >> 1); + + // left、right的子节点之间可以挪动的最小间距 + int space = left.minLevelSpaceToRight(right) - MIN_SPACE; + space = Math.min(space >> 1, empty); + + // left、right往中间挪动 + if (space > 0) { + left.translateX(space); + right.translateX(-space); + } + + // 继续挪动 + space = left.minLevelSpaceToRight(right) - MIN_SPACE; + if (space < 1) continue; + + // 可以继续挪动的间距 + leftEmpty = node.leftBoundEmptyLength(); + rightEmpty = node.rightBoundEmptyLength(); + if (leftEmpty < 1 && rightEmpty < 1) continue; + + if (leftEmpty > rightEmpty) { + left.translateX(Math.min(leftEmpty, space)); + } else { + right.translateX(-Math.min(rightEmpty, space)); + } + } else if (left != null) { + left.translateX(node.leftBoundEmptyLength()); + } else { // right != null + right.translateX(-node.rightBoundEmptyLength()); + } + } + } + } + + private void addXLineNode(List curRow, Node parent, int x) { + Node line = new Node("─"); + line.x = x; + line.y = parent.y; + curRow.add(line); + } + + private Node addLineNode(List curRow, List nextRow, Node parent, Node child) { + if (child == null) return null; + + Node top = null; + int topX = child.topLineX(); + if (child == parent.left) { + top = new Node("┌"); + curRow.add(top); + + for (int x = topX + 1; x < parent.x; x++) { + addXLineNode(curRow, parent, x); + } + } else { + for (int x = parent.rightX(); x < topX; x++) { + addXLineNode(curRow, parent, x); + } + + top = new Node("┐"); + curRow.add(top); + } + + // 坐标 + top.x = topX; + top.y = parent.y; + child.y = parent.y + 2; + minX = Math.min(minX, child.x); + + // 竖线 + Node bottom = new Node("│"); + bottom.x = topX; + bottom.y = parent.y + 1; + nextRow.add(bottom); + + return top; + } + + private void addLineNodes(List> nodes) { + List> newNodes = new ArrayList<>(); + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + minX = root.x; + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + if (i == rowCount - 1) { + newNodes.add(rowNodes); + continue; + } + + List newRowNodes = new ArrayList<>(); + newNodes.add(newRowNodes); + + List lineNodes = new ArrayList<>(); + newNodes.add(lineNodes); + for (Node node : rowNodes) { + addLineNode(newRowNodes, lineNodes, node, node.left); + newRowNodes.add(node); + addLineNode(newRowNodes, lineNodes, node, node.right); + } + } + + nodes.clear(); + nodes.addAll(newNodes); + } + + private static class Node { + /** + * 顶部符号距离父节点的最小距离(最小能填0) + */ + private static final int TOP_LINE_SPACE = 1; + + Object btNode; + Node left; + Node right; + Node parent; + /** + * 首字符的位置 + */ + int x; + int y; + int treeHeight; + String string; + int width; + + private void init(String string) { + string = (string == null) ? "null" : string; + string = string.isEmpty() ? " " : string; + + width = string.length(); + this.string = string; + } + + public Node(String string) { + init(string); + } + + public Node(Object btNode, BinaryTreeInfo opetaion) { + init(opetaion.string(btNode).toString()); + + this.btNode = btNode; + } + + /** + * 顶部方向字符的X(极其重要) + * + * @return + */ + private int topLineX() { + // 宽度的一半 + int delta = width; + if (delta % 2 == 0) { + delta--; + } + delta >>= 1; + + if (parent != null && this == parent.left) { + return rightX() - 1 - delta; + } else { + return x + delta; + } + } + + /** + * 右边界的位置(rightX 或者 右子节点topLineX的下一个位置)(极其重要) + */ + private int rightBound() { + if (right == null) return rightX(); + return right.topLineX() + 1; + } + + /** + * 左边界的位置(x 或者 左子节点topLineX)(极其重要) + */ + private int leftBound() { + if (left == null) return x; + return left.topLineX(); + } + + /** + * x ~ 左边界之间的长度(包括左边界字符) + * + * @return + */ + private int leftBoundLength() { + return x - leftBound(); + } + + /** + * rightX ~ 右边界之间的长度(包括右边界字符) + * + * @return + */ + private int rightBoundLength() { + return rightBound() - rightX(); + } + + /** + * 左边界可以清空的长度 + * + * @return + */ + private int leftBoundEmptyLength() { + return leftBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 右边界可以清空的长度 + * + * @return + */ + private int rightBoundEmptyLength() { + return rightBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 让left和right基于this对称 + */ + private void balance(Node left, Node right) { + if (left == null || right == null) + return; + // 【left的尾字符】与【this的首字符】之间的间距 + int deltaLeft = x - left.rightX(); + // 【this的尾字符】与【this的首字符】之间的间距 + int deltaRight = right.x - rightX(); + + int delta = Math.max(deltaLeft, deltaRight); + int newRightX = rightX() + delta; + right.translateX(newRightX - right.x); + + int newLeftX = x - delta - left.width; + left.translateX(newLeftX - left.x); + } + + private int treeHeight(Node node) { + if (node == null) return 0; + if (node.treeHeight != 0) return node.treeHeight; + node.treeHeight = 1 + Math.max( + treeHeight(node.left), treeHeight(node.right)); + return node.treeHeight; + } + + /** + * 和右节点之间的最小层级距离 + */ + private int minLevelSpaceToRight(Node right) { + int thisHeight = treeHeight(this); + int rightHeight = treeHeight(right); + int minSpace = Integer.MAX_VALUE; + for (int i = 0; i < thisHeight && i < rightHeight; i++) { + int space = right.levelInfo(i).leftX + - this.levelInfo(i).rightX; + minSpace = Math.min(minSpace, space); + } + return minSpace; + } + + private LevelInfo levelInfo(int level) { + if (level < 0) return null; + int levelY = y + level; + if (level >= treeHeight(this)) return null; + + List list = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(this); + + // 层序遍历找出第level行的所有节点 + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (levelY == node.y) { + list.add(node); + } else if (node.y > levelY) break; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + + Node left = list.get(0); + Node right = list.get(list.size() - 1); + return new LevelInfo(left, right); + } + + /** + * 尾字符的下一个位置 + */ + public int rightX() { + return x + width; + } + + public void translateX(int deltaX) { + if (deltaX == 0) return; + x += deltaX; + + // 如果是LineNode + if (btNode == null) return; + + if (left != null) { + left.translateX(deltaX); + } + if (right != null) { + right.translateX(deltaX); + } + } + } + + private static class LevelInfo { + int leftX; + int rightX; + + public LevelInfo(Node left, Node right) { + this.leftX = left.leftBound(); + this.rightX = right.rightBound(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/Printer.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/Printer.java new file mode 100644 index 0000000..a8845a1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/Printer.java @@ -0,0 +1,32 @@ +package com.mj.printer; + +public abstract class Printer { + /** + * 二叉树的基本信息 + */ + protected BinaryTreeInfo tree; + + public Printer(BinaryTreeInfo tree) { + this.tree = tree; + } + + /** + * 生成打印的字符串 + */ + public abstract String printString(); + + /** + * 打印后换行 + */ + public void println() { + print(); + System.out.println(); + } + + /** + * 打印 + */ + public void print() { + System.out.print(printString()); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/Strings.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/Strings.java new file mode 100644 index 0000000..83ea770 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/printer/Strings.java @@ -0,0 +1,19 @@ +package com.mj.printer; + +public class Strings { + public static String repeat(String string, int count) { + if (string == null) return null; + + StringBuilder builder = new StringBuilder(); + while (count-- > 0) { + builder.append(string); + } + return builder.toString(); + } + + public static String blank(int length) { + if (length < 0) return null; + if (length == 0) return ""; + return String.format("%" + length + "s", ""); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/AVLTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/AVLTree.java new file mode 100644 index 0000000..685594d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/AVLTree.java @@ -0,0 +1,157 @@ +package com.mj.tree; + +import java.util.Comparator; + +public class AVLTree extends BBST { + public AVLTree() { + this(null); + } + + public AVLTree(Comparator comparator) { + super(comparator); + } + + @Override + protected void afterAdd(Node node) { + while ((node = node.parent) != null) { + if (isBalanced(node)) { + // 更新高度 + updateHeight(node); + } else { + // 恢复平衡 + rebalance(node); + // 整棵树恢复平衡 + break; + } + } + } + + @Override + protected void afterRemove(Node node) { + while ((node = node.parent) != null) { + if (isBalanced(node)) { + // 更新高度 + updateHeight(node); + } else { + // 恢复平衡 + rebalance(node); + } + } + } + + @Override + protected Node createNode(E element, Node parent) { + return new AVLNode<>(element, parent); + } + + /** + * 恢复平衡 + * @param grand 高度最低的那个不平衡节点 + */ + @SuppressWarnings("unused") + private void rebalance2(Node grand) { + Node parent = ((AVLNode)grand).tallerChild(); + Node node = ((AVLNode)parent).tallerChild(); + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + rotateRight(grand); + } else { // LR + rotateLeft(parent); + rotateRight(grand); + } + } else { // R + if (node.isLeftChild()) { // RL + rotateRight(parent); + rotateLeft(grand); + } else { // RR + rotateLeft(grand); + } + } + } + + @Override + protected void afterRotate(Node grand, Node parent, Node child) { + super.afterRotate(grand, parent, child); + + // 更新高度 + updateHeight(grand); + updateHeight(parent); + } + + @Override + protected void rotate(Node r, Node b, Node c, Node d, Node e, Node f) { + super.rotate(r, b, c, d, e, f); + + // 更新高度 + updateHeight(b); + updateHeight(f); + updateHeight(d); + } + + /** + * 恢复平衡 + * @param grand 高度最低的那个不平衡节点 + */ + private void rebalance(Node grand) { + Node parent = ((AVLNode)grand).tallerChild(); + Node node = ((AVLNode)parent).tallerChild(); + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + rotate(grand, node, node.right, parent, parent.right, grand); + } else { // LR + rotate(grand, parent, node.left, node, node.right, grand); + } + } else { // R + if (node.isLeftChild()) { // RL + rotate(grand, grand, node.left, node, node.right, parent); + } else { // RR + rotate(grand, grand, parent.left, parent, node.left, node); + } + } + } + + private boolean isBalanced(Node node) { + return Math.abs(((AVLNode)node).balanceFactor()) <= 1; + } + + private void updateHeight(Node node) { + ((AVLNode)node).updateHeight(); + } + + private static class AVLNode extends Node { + int height = 1; + + public AVLNode(E element, Node parent) { + super(element, parent); + } + + public int balanceFactor() { + int leftHeight = left == null ? 0 : ((AVLNode)left).height; + int rightHeight = right == null ? 0 : ((AVLNode)right).height; + return leftHeight - rightHeight; + } + + public void updateHeight() { + int leftHeight = left == null ? 0 : ((AVLNode)left).height; + int rightHeight = right == null ? 0 : ((AVLNode)right).height; + height = 1 + Math.max(leftHeight, rightHeight); + } + + public Node tallerChild() { + int leftHeight = left == null ? 0 : ((AVLNode)left).height; + int rightHeight = right == null ? 0 : ((AVLNode)right).height; + if (leftHeight > rightHeight) return left; + if (leftHeight < rightHeight) return right; + return isLeftChild() ? left : right; + } + + @Override + public String toString() { + String parentString = "null"; + if (parent != null) { + parentString = parent.element.toString(); + } + return element + "_p(" + parentString + ")_h(" + height + ")"; + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BBST.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BBST.java new file mode 100644 index 0000000..143c60e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BBST.java @@ -0,0 +1,83 @@ +package com.mj.tree; + +import java.util.Comparator; + +public class BBST extends BST { + public BBST() { + this(null); + } + + public BBST(Comparator comparator) { + super(comparator); + } + + protected void rotateLeft(Node grand) { + Node parent = grand.right; + Node child = parent.left; + grand.right = child; + parent.left = grand; + afterRotate(grand, parent, child); + } + + protected void rotateRight(Node grand) { + Node parent = grand.left; + Node child = parent.right; + grand.left = child; + parent.right = grand; + afterRotate(grand, parent, child); + } + + protected void afterRotate(Node grand, Node parent, Node child) { + // 让parent称为子树的根节点 + parent.parent = grand.parent; + if (grand.isLeftChild()) { + grand.parent.left = parent; + } else if (grand.isRightChild()) { + grand.parent.right = parent; + } else { // grand是root节点 + root = parent; + } + + // 更新child的parent + if (child != null) { + child.parent = grand; + } + + // 更新grand的parent + grand.parent = parent; + } + + protected void rotate( + Node r, // 子树的根节点 + Node b, Node c, + Node d, + Node e, Node f) { + // 让d成为这棵子树的根节点 + d.parent = r.parent; + if (r.isLeftChild()) { + r.parent.left = d; + } else if (r.isRightChild()) { + r.parent.right = d; + } else { + root = d; + } + + //b-c + b.right = c; + if (c != null) { + c.parent = b; + } + + // e-f + f.left = e; + if (e != null) { + e.parent = f; + } + + // b-d-f + d.left = b; + d.right = f; + b.parent = d; + f.parent = d; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BST.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BST.java new file mode 100644 index 0000000..611a6d8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BST.java @@ -0,0 +1,158 @@ +package com.mj.tree; + +import java.util.Comparator; + +@SuppressWarnings("unchecked") +public class BST extends BinaryTree { + private Comparator comparator; + + public BST() { + this(null); + } + + public BST(Comparator comparator) { + this.comparator = comparator; + } + + public void add(E element) { + elementNotNullCheck(element); + + // 添加第一个节点 + if (root == null) { + root = createNode(element, null); + size++; + + // 新添加节点之后的处理 + afterAdd(root); + return; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(element, node.element); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.element = element; + return; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = createNode(element, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + + // 新添加节点之后的处理 + afterAdd(newNode); + } + + /** + * 添加node之后的调整 + * @param node 新添加的节点 + */ + protected void afterAdd(Node node) { } + + /** + * 删除node之后的调整 + * @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1) + */ + protected void afterRemove(Node node) { } + + public void remove(E element) { + remove(node(element)); + } + + public boolean contains(E element) { + return node(element) != null; + } + + private void remove(Node node) { + if (node == null) return; + + size--; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.element = s.element; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + + // 删除节点之后的处理 + afterRemove(replacement); + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + + // 删除节点之后的处理 + afterRemove(node); + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + + // 删除节点之后的处理 + afterRemove(node); + } + } + + private Node node(E element) { + Node node = root; + while (node != null) { + int cmp = compare(element, node.element); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + + /** + * @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2 + */ + private int compare(E e1, E e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void elementNotNullCheck(E element) { + if (element == null) { + throw new IllegalArgumentException("element must not be null"); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BinaryTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BinaryTree.java new file mode 100644 index 0000000..5a82a70 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/BinaryTree.java @@ -0,0 +1,265 @@ +package com.mj.tree; + +import java.util.LinkedList; +import java.util.Queue; + +import com.mj.printer.BinaryTreeInfo; + +@SuppressWarnings("unchecked") +public class BinaryTree implements BinaryTreeInfo { + protected int size; + protected Node root; + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + public void preorder(Visitor visitor) { + if (visitor == null) return; + preorder(root, visitor); + } + + private void preorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + visitor.stop = visitor.visit(node.element); + preorder(node.left, visitor); + preorder(node.right, visitor); + } + + public void inorder(Visitor visitor) { + if (visitor == null) return; + inorder(root, visitor); + } + + private void inorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + inorder(node.left, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + inorder(node.right, visitor); + } + + public void postorder(Visitor visitor) { + if (visitor == null) return; + postorder(root, visitor); + } + + private void postorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + postorder(node.left, visitor); + postorder(node.right, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + } + + public void levelOrder(Visitor visitor) { + if (root == null || visitor == null) return; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (visitor.visit(node.element)) return; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + } + + public boolean isComplete() { + if (root == null) return false; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + boolean leaf = false; + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (leaf && !node.isLeaf()) return false; + + if (node.left != null) { + queue.offer(node.left); + } else if (node.right != null) { + return false; + } + + if (node.right != null) { + queue.offer(node.right); + } else { // 后面遍历的节点都必须是叶子节点 + leaf = true; + } + } + + return true; + } + + public int height() { + if (root == null) return 0; + + // 树的高度 + int height = 0; + // 存储着每一层的元素数量 + int levelSize = 1; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + levelSize--; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + + if (levelSize == 0) { // 意味着即将要访问下一层 + levelSize = queue.size(); + height++; + } + } + + return height; + } + + public int height2() { + return height(root); + } + + private int height(Node node) { + if (node == null) return 0; + return 1 + Math.max(height(node.left), height(node.right)); + } + + protected Node createNode(E element, Node parent) { + return new Node<>(element, parent); + } + + protected Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + protected Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + public static abstract class Visitor { + boolean stop; + /** + * @return 如果返回true,就代表停止遍历 + */ + abstract boolean visit(E element); + } + + protected static class Node { + E element; + Node left; + Node right; + Node parent; + public Node(E element, Node parent) { + this.element = element; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + + public boolean isLeftChild() { + return parent != null && this == parent.left; + } + + public boolean isRightChild() { + return parent != null && this == parent.right; + } + + public Node sibling() { + if (isLeftChild()) { + return parent.right; + } + + if (isRightChild()) { + return parent.left; + } + + return null; + } + } + + @Override + public Object root() { + return root; + } + + @Override + public Object left(Object node) { + return ((Node)node).left; + } + + @Override + public Object right(Object node) { + return ((Node)node).right; + } + + @Override + public Object string(Object node) { + return node; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/RBTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/RBTree.java new file mode 100644 index 0000000..c52ff59 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/08-红黑树/src/com/mj/tree/RBTree.java @@ -0,0 +1,268 @@ +package com.mj.tree; + +import java.util.Comparator; + +public class RBTree extends BBST { + private static final boolean RED = false; + private static final boolean BLACK = true; + + public RBTree() { + this(null); + } + + public RBTree(Comparator comparator) { + super(comparator); + } + + @Override + protected void afterAdd(Node node) { + Node parent = node.parent; + + // 添加的是根节点 或者 上溢到达了根节点 + if (parent == null) { + black(node); + return; + } + + // 如果父节点是黑色,直接返回 + if (isBlack(parent)) return; + + // 叔父节点 + Node uncle = parent.sibling(); + // 祖父节点 + Node grand = red(parent.parent); + if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】 + black(parent); + black(uncle); + // 把祖父节点当做是新添加的节点 + afterAdd(grand); + return; + } + + // 叔父节点不是红色 + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + black(parent); + } else { // LR + black(node); + rotateLeft(parent); + } + rotateRight(grand); + } else { // R + if (node.isLeftChild()) { // RL + black(node); + rotateRight(parent); + } else { // RR + black(parent); + } + rotateLeft(grand); + } + } + + @Override + protected void afterRemove(Node node) { + // 如果删除的节点是红色 + // 或者 用以取代删除节点的子节点是红色 + if (isRed(node)) { + black(node); + return; + } + + Node parent = node.parent; + // 删除的是根节点 + if (parent == null) return; + + // 删除的是黑色叶子节点【下溢】 + // 判断被删除的node是左还是右 + boolean left = parent.left == null || node.isLeftChild(); + Node sibling = left ? parent.right : parent.left; + if (left) { // 被删除的节点在左边,兄弟节点在右边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateLeft(parent); + // 更换兄弟 + sibling = parent.right; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.right)) { + rotateRight(sibling); + sibling = parent.right; + } + + color(sibling, colorOf(parent)); + black(sibling.right); + black(parent); + rotateLeft(parent); + } + } else { // 被删除的节点在右边,兄弟节点在左边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateRight(parent); + // 更换兄弟 + sibling = parent.left; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.left)) { + rotateLeft(sibling); + sibling = parent.left; + } + + color(sibling, colorOf(parent)); + black(sibling.left); + black(parent); + rotateRight(parent); + } + } + } +// protected void afterRemove(Node node, Node replacement) { +// // 如果删除的节点是红色 +// if (isRed(node)) return; +// +// // 用以取代node的子节点是红色 +// if (isRed(replacement)) { +// black(replacement); +// return; +// } +// +// Node parent = node.parent; +// // 删除的是根节点 +// if (parent == null) return; +// +// // 删除的是黑色叶子节点【下溢】 +// // 判断被删除的node是左还是右 +// boolean left = parent.left == null || node.isLeftChild(); +// Node sibling = left ? parent.right : parent.left; +// if (left) { // 被删除的节点在左边,兄弟节点在右边 +// if (isRed(sibling)) { // 兄弟节点是红色 +// black(sibling); +// red(parent); +// rotateLeft(parent); +// // 更换兄弟 +// sibling = parent.right; +// } +// +// // 兄弟节点必然是黑色 +// if (isBlack(sibling.left) && isBlack(sibling.right)) { +// // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 +// boolean parentBlack = isBlack(parent); +// black(parent); +// red(sibling); +// if (parentBlack) { +// afterRemove(parent, null); +// } +// } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 +// // 兄弟节点的左边是黑色,兄弟要先旋转 +// if (isBlack(sibling.right)) { +// rotateRight(sibling); +// sibling = parent.right; +// } +// +// color(sibling, colorOf(parent)); +// black(sibling.right); +// black(parent); +// rotateLeft(parent); +// } +// } else { // 被删除的节点在右边,兄弟节点在左边 +// if (isRed(sibling)) { // 兄弟节点是红色 +// black(sibling); +// red(parent); +// rotateRight(parent); +// // 更换兄弟 +// sibling = parent.left; +// } +// +// // 兄弟节点必然是黑色 +// if (isBlack(sibling.left) && isBlack(sibling.right)) { +// // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 +// boolean parentBlack = isBlack(parent); +// black(parent); +// red(sibling); +// if (parentBlack) { +// afterRemove(parent, null); +// } +// } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 +// // 兄弟节点的左边是黑色,兄弟要先旋转 +// if (isBlack(sibling.left)) { +// rotateLeft(sibling); +// sibling = parent.left; +// } +// +// color(sibling, colorOf(parent)); +// black(sibling.left); +// black(parent); +// rotateRight(parent); +// } +// } +// } + + private Node color(Node node, boolean color) { + if (node == null) return node; + ((RBNode)node).color = color; + return node; + } + + private Node red(Node node) { + return color(node, RED); + } + + private Node black(Node node) { + return color(node, BLACK); + } + + private boolean colorOf(Node node) { + return node == null ? BLACK : ((RBNode)node).color; + } + + private boolean isBlack(Node node) { + return colorOf(node) == BLACK; + } + + private boolean isRed(Node node) { + return colorOf(node) == RED; + } + + @Override + protected Node createNode(E element, Node parent) { + return new RBNode<>(element, parent); + } + + private static class RBNode extends Node { + boolean color = RED; + public RBNode(E element, Node parent) { + super(element, parent); + } + + @Override + public String toString() { + String str = ""; + if (color == RED) { + str = "R_"; + } + return str + element.toString(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.project new file mode 100644 index 0000000..e2d1d7d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.project @@ -0,0 +1,17 @@ + + + 09-集合 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main$1.class new file mode 100644 index 0000000..a557c51 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main$2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main$2.class new file mode 100644 index 0000000..99c4f12 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main$2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main.class new file mode 100644 index 0000000..ce6b547 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Times$Task.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Times$Task.class new file mode 100644 index 0000000..573edc2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Times$Task.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Times.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Times.class new file mode 100644 index 0000000..49d99e8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/Times.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/FileInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/FileInfo.class new file mode 100644 index 0000000..3d5f61c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/FileInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/Files$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/Files$1.class new file mode 100644 index 0000000..01b769c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/Files$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/Files.class new file mode 100644 index 0000000..2983be9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/AbstractList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/AbstractList.class new file mode 100644 index 0000000..efaf42f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/AbstractList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/LinkedList$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/LinkedList$Node.class new file mode 100644 index 0000000..acd9e51 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/LinkedList$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/LinkedList.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/LinkedList.class new file mode 100644 index 0000000..ffd1e3a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/LinkedList.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/List.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/List.class new file mode 100644 index 0000000..e5d4790 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/list/List.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/ListSet.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/ListSet.class new file mode 100644 index 0000000..3927b04 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/ListSet.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/Set$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/Set$Visitor.class new file mode 100644 index 0000000..5bd00a2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/Set$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/Set.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/Set.class new file mode 100644 index 0000000..deb255c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/Set.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/TreeSet$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/TreeSet$1.class new file mode 100644 index 0000000..2d85cc8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/TreeSet$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/TreeSet.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/TreeSet.class new file mode 100644 index 0000000..1518768 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/set/TreeSet.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BBST.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BBST.class new file mode 100644 index 0000000..dc17fc6 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BBST.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BST.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BST.class new file mode 100644 index 0000000..069769d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BST.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree$Node.class new file mode 100644 index 0000000..406e4b7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree$Visitor.class new file mode 100644 index 0000000..d813b5b Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree.class new file mode 100644 index 0000000..90f5474 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/BinaryTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/RBTree$RBNode.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/RBTree$RBNode.class new file mode 100644 index 0000000..29cf929 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/RBTree$RBNode.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/RBTree.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/RBTree.class new file mode 100644 index 0000000..20c5def Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/bin/com/mj/tree/RBTree.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/Main.java new file mode 100644 index 0000000..5833053 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/Main.java @@ -0,0 +1,79 @@ +package com.mj; + +import com.mj.Times.Task; +import com.mj.file.FileInfo; +import com.mj.file.Files; +import com.mj.set.ListSet; +import com.mj.set.Set; +import com.mj.set.Set.Visitor; +import com.mj.set.TreeSet; + +public class Main { + + static void test1() { + + Set listSet = new ListSet<>(); + listSet.add(10); + listSet.add(11); + listSet.add(11); + listSet.add(12); + listSet.add(10); + + Set treeSet = new TreeSet<>(); + treeSet.add(12); + treeSet.add(10); + treeSet.add(7); + treeSet.add(11); + treeSet.add(10); + treeSet.add(11); + treeSet.add(9); + + treeSet.traversal(new Visitor() { + @Override + public boolean visit(Integer element) { + System.out.println(element); + return false; + } + }); + } + + + static void testSet(Set set, String[] words) { + for (int i = 0; i < words.length; i++) { + set.add(words[i]); + } + for (int i = 0; i < words.length; i++) { + set.contains(words[i]); + } + for (int i = 0; i < words.length; i++) { + set.remove(words[i]); + } + } + + static void test2() { + FileInfo fileInfo = Files.read("C:\\Users\\MJ Lee\\Desktop\\src\\java\\util", + new String[]{"java"}); + + System.out.println("文件数量:" + fileInfo.getFiles()); + System.out.println("代码行数:" + fileInfo.getLines()); + String[] words = fileInfo.words(); + System.out.println("单词数量:" + words.length); + +// Times.test("ListSet", new Task() { +// public void execute() { +// testSet(new ListSet<>(), words); +// } +// }); + + Times.test("TreeSet", new Task() { + public void execute() { + testSet(new TreeSet<>(), words); + } + }); + } + + public static void main(String[] args) { + test2(); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/Times.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/Times.java new file mode 100644 index 0000000..35c93a4 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/Times.java @@ -0,0 +1,26 @@ +package com.mj; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Times { + private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS"); + + public interface Task { + void execute(); + } + + public static void test(String title, Task task) { + if (task == null) return; + title = (title == null) ? "" : ("【" + title + "】"); + System.out.println(title); + System.out.println("开始:" + fmt.format(new Date())); + long begin = System.currentTimeMillis(); + task.execute(); + long end = System.currentTimeMillis(); + System.out.println("结束:" + fmt.format(new Date())); + double delta = (end - begin) / 1000.0; + System.out.println("耗时:" + delta + "秒"); + System.out.println("-------------------------------------"); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/file/FileInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/file/FileInfo.java new file mode 100644 index 0000000..676fc6e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/file/FileInfo.java @@ -0,0 +1,47 @@ +package com.mj.file; + +public class FileInfo { + private int lines; + private int files; + private String content = ""; + + public String[] words() { + return content.split("[^a-zA-Z]+"); + } + + public int getFiles() { + return files; + } + + public void setFiles(int files) { + this.files = files; + } + + public int getLines() { + return lines; + } + + public void setLines(int lines) { + this.lines = lines; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public FileInfo append(FileInfo info) { + if (info != null && info.lines > 0) { + this.files += info.files; + this.lines += info.lines; + this.content = new StringBuilder(this.content) + .append("\n") + .append(info.content) + .toString(); + } + return this; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/file/Files.java new file mode 100644 index 0000000..1214723 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/file/Files.java @@ -0,0 +1,72 @@ +package com.mj.file; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.IOException; + +public class Files { + + /** + * 读取文件内容 + * @param file + * @return + */ + public static FileInfo read(String file) { + if (file == null) return null; + FileInfo info = new FileInfo(); + StringBuilder sb = new StringBuilder(); + try (FileReader reader = new FileReader(file); + BufferedReader br = new BufferedReader(reader)) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append("\n"); + info.setLines(info.getLines() + 1); + } + int len = sb.length(); + if (len > 0) { + sb.deleteCharAt(len - 1); + } + } catch (IOException e) { + e.printStackTrace(); + } + info.setFiles(info.getFiles() + 1); + info.setContent(sb.toString()); + return info; + } + + /** + * 读取文件夹下面的文件内容 + * @param dir + * @param extensions + * @return + */ + public static FileInfo read(String dir, String[] extensions) { + if (dir == null) return null; + + File dirFile = new File(dir); + if (!dirFile.exists()) return null; + + FileInfo info = new FileInfo(); + dirFile.listFiles(new FileFilter() { + public boolean accept(File subFile) { + String subFilepath = subFile.getAbsolutePath(); + if (subFile.isDirectory()) { + info.append(read(subFilepath, extensions)); + } else if (extensions != null && extensions.length > 0) { + for (String extension : extensions) { + if (subFilepath.endsWith("." + extension)) { + info.append(read(subFilepath)); + break; + } + } + } else { + info.append(read(subFilepath)); + } + return false; + } + }); + return info; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/AbstractList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/AbstractList.java new file mode 100644 index 0000000..455c858 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/AbstractList.java @@ -0,0 +1,56 @@ +package com.mj.list; + +public abstract class AbstractList implements List { + /** + * 元素的数量 + */ + protected int size; + /** + * 元素的数量 + * @return + */ + public int size() { + return size; + } + + /** + * 是否为空 + * @return + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * 是否包含某个元素 + * @param element + * @return + */ + public boolean contains(E element) { + return indexOf(element) != ELEMENT_NOT_FOUND; + } + + /** + * 添加元素到尾部 + * @param element + */ + public void add(E element) { + add(size, element); + } + + protected void outOfBounds(int index) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); + } + + protected void rangeCheck(int index) { + if (index < 0 || index >= size) { + outOfBounds(index); + } + } + + protected void rangeCheckForAdd(int index) { + if (index < 0 || index > size) { + outOfBounds(index); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/LinkedList.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/LinkedList.java new file mode 100644 index 0000000..d74c2ef --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/LinkedList.java @@ -0,0 +1,173 @@ +package com.mj.list; + +public class LinkedList extends AbstractList { + private Node first; + private Node last; + + private static class Node { + E element; + Node prev; + Node next; + public Node(Node prev, E element, Node next) { + this.prev = prev; + this.element = element; + this.next = next; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (prev != null) { + sb.append(prev.element); + } else { + sb.append("null"); + } + + sb.append("_").append(element).append("_"); + + if (next != null) { + sb.append(next.element); + } else { + sb.append("null"); + } + + return sb.toString(); + } + } + + @Override + public void clear() { + size = 0; + first = null; + last = null; + } + + @Override + public E get(int index) { + return node(index).element; + } + + @Override + public E set(int index, E element) { + Node node = node(index); + E old = node.element; + node.element = element; + return old; + } + + @Override + public void add(int index, E element) { + rangeCheckForAdd(index); + + // size == 0 + // index == 0 + if (index == size) { // 往最后面添加元素 + Node oldLast = last; + last = new Node<>(oldLast, element, null); + if (oldLast == null) { // 这是链表添加的第一个元素 + first = last; + } else { + oldLast.next = last; + } + } else { + Node next = node(index); + Node prev = next.prev; + Node node = new Node<>(prev, element, next); + next.prev = node; + + if (prev == null) { // index == 0 + first = node; + } else { + prev.next = node; + } + } + + size++; + } + + @Override + public E remove(int index) { + rangeCheck(index); + + Node node = node(index); + Node prev = node.prev; + Node next = node.next; + + if (prev == null) { // index == 0 + first = next; + } else { + prev.next = next; + } + + if (next == null) { // index == size - 1 + last = prev; + } else { + next.prev = prev; + } + + size--; + return node.element; + } + + @Override + public int indexOf(E element) { + if (element == null) { + Node node = first; + for (int i = 0; i < size; i++) { + if (node.element == null) return i; + + node = node.next; + } + } else { + Node node = first; + for (int i = 0; i < size; i++) { + if (element.equals(node.element)) return i; + + node = node.next; + } + } + return ELEMENT_NOT_FOUND; + } + + /** + * 获取index位置对应的节点对象 + * @param index + * @return + */ + private Node node(int index) { + rangeCheck(index); + + if (index < (size >> 1)) { + Node node = first; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } else { + Node node = last; + for (int i = size - 1; i > index; i--) { + node = node.prev; + } + return node; + } + } + + @Override + public String toString() { + StringBuilder string = new StringBuilder(); + string.append("size=").append(size).append(", ["); + Node node = first; + for (int i = 0; i < size; i++) { + if (i != 0) { + string.append(", "); + } + + string.append(node); + + node = node.next; + } + string.append("]"); + return string.toString(); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/List.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/List.java new file mode 100644 index 0000000..d8b5af5 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/list/List.java @@ -0,0 +1,70 @@ +package com.mj.list; + +public interface List { + static final int ELEMENT_NOT_FOUND = -1; + /** + * 清除所有元素 + */ + void clear(); + + /** + * 元素的数量 + * @return + */ + int size(); + + /** + * 是否为空 + * @return + */ + boolean isEmpty(); + + /** + * 是否包含某个元素 + * @param element + * @return + */ + boolean contains(E element); + + /** + * 添加元素到尾部 + * @param element + */ + void add(E element); + + /** + * 获取index位置的元素 + * @param index + * @return + */ + E get(int index); + + /** + * 设置index位置的元素 + * @param index + * @param element + * @return 原来的元素ֵ + */ + E set(int index, E element); + + /** + * 在index位置插入一个元素 + * @param index + * @param element + */ + void add(int index, E element); + + /** + * 删除index位置的元素 + * @param index + * @return + */ + E remove(int index); + + /** + * 查看元素的索引 + * @param element + * @return + */ + int indexOf(E element); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/ListSet.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/ListSet.java new file mode 100644 index 0000000..6e1e74c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/ListSet.java @@ -0,0 +1,57 @@ +package com.mj.set; + +import com.mj.list.LinkedList; +import com.mj.list.List; + +public class ListSet implements Set { + private List list = new LinkedList<>(); + + @Override + public int size() { + return list.size(); + } + + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + + @Override + public void clear() { + list.clear(); + } + + @Override + public boolean contains(E element) { + return list.contains(element); + } + + @Override + public void add(E element) { + int index = list.indexOf(element); + if (index != List.ELEMENT_NOT_FOUND) { // 存在就覆盖 + list.set(index, element); + } else { // 不存在就添加 + list.add(element); + } + } + + @Override + public void remove(E element) { + int index = list.indexOf(element); + if (index != List.ELEMENT_NOT_FOUND) { + list.remove(index); + } + } + + @Override + public void traversal(Visitor visitor) { + if (visitor == null) return; + + int size = list.size(); + for (int i = 0; i < size; i++) { + if (visitor.visit(list.get(i))) return; + } + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/Set.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/Set.java new file mode 100644 index 0000000..cfb49e1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/Set.java @@ -0,0 +1,16 @@ +package com.mj.set; + +public interface Set { + int size(); + boolean isEmpty(); + void clear(); + boolean contains(E element); + void add(E element); + void remove(E element); + void traversal(Visitor visitor); + + public static abstract class Visitor { + boolean stop; + public abstract boolean visit(E element); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/TreeSet.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/TreeSet.java new file mode 100644 index 0000000..da25606 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/set/TreeSet.java @@ -0,0 +1,59 @@ +package com.mj.set; + +import java.util.Comparator; + +import com.mj.tree.BinaryTree; +import com.mj.tree.RBTree; + +public class TreeSet implements Set { + private RBTree tree; + + public TreeSet() { + this(null); + } + + public TreeSet(Comparator comparator) { + tree = new RBTree<>(comparator); + } + + @Override + public int size() { + return tree.size(); + } + + @Override + public boolean isEmpty() { + return tree.isEmpty(); + } + + @Override + public void clear() { + tree.clear(); + } + + @Override + public boolean contains(E element) { + return tree.contains(element); + } + + @Override + public void add(E element) { + tree.add(element); + } + + @Override + public void remove(E element) { + tree.remove(element); + } + + @Override + public void traversal(Visitor visitor) { + tree.inorder(new BinaryTree.Visitor() { + @Override + public boolean visit(E element) { + return visitor.visit(element); + } + }); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BBST.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BBST.java new file mode 100644 index 0000000..143c60e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BBST.java @@ -0,0 +1,83 @@ +package com.mj.tree; + +import java.util.Comparator; + +public class BBST extends BST { + public BBST() { + this(null); + } + + public BBST(Comparator comparator) { + super(comparator); + } + + protected void rotateLeft(Node grand) { + Node parent = grand.right; + Node child = parent.left; + grand.right = child; + parent.left = grand; + afterRotate(grand, parent, child); + } + + protected void rotateRight(Node grand) { + Node parent = grand.left; + Node child = parent.right; + grand.left = child; + parent.right = grand; + afterRotate(grand, parent, child); + } + + protected void afterRotate(Node grand, Node parent, Node child) { + // 让parent称为子树的根节点 + parent.parent = grand.parent; + if (grand.isLeftChild()) { + grand.parent.left = parent; + } else if (grand.isRightChild()) { + grand.parent.right = parent; + } else { // grand是root节点 + root = parent; + } + + // 更新child的parent + if (child != null) { + child.parent = grand; + } + + // 更新grand的parent + grand.parent = parent; + } + + protected void rotate( + Node r, // 子树的根节点 + Node b, Node c, + Node d, + Node e, Node f) { + // 让d成为这棵子树的根节点 + d.parent = r.parent; + if (r.isLeftChild()) { + r.parent.left = d; + } else if (r.isRightChild()) { + r.parent.right = d; + } else { + root = d; + } + + //b-c + b.right = c; + if (c != null) { + c.parent = b; + } + + // e-f + f.left = e; + if (e != null) { + e.parent = f; + } + + // b-d-f + d.left = b; + d.right = f; + b.parent = d; + f.parent = d; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BST.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BST.java new file mode 100644 index 0000000..611a6d8 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BST.java @@ -0,0 +1,158 @@ +package com.mj.tree; + +import java.util.Comparator; + +@SuppressWarnings("unchecked") +public class BST extends BinaryTree { + private Comparator comparator; + + public BST() { + this(null); + } + + public BST(Comparator comparator) { + this.comparator = comparator; + } + + public void add(E element) { + elementNotNullCheck(element); + + // 添加第一个节点 + if (root == null) { + root = createNode(element, null); + size++; + + // 新添加节点之后的处理 + afterAdd(root); + return; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(element, node.element); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.element = element; + return; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = createNode(element, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + + // 新添加节点之后的处理 + afterAdd(newNode); + } + + /** + * 添加node之后的调整 + * @param node 新添加的节点 + */ + protected void afterAdd(Node node) { } + + /** + * 删除node之后的调整 + * @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1) + */ + protected void afterRemove(Node node) { } + + public void remove(E element) { + remove(node(element)); + } + + public boolean contains(E element) { + return node(element) != null; + } + + private void remove(Node node) { + if (node == null) return; + + size--; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.element = s.element; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + + // 删除节点之后的处理 + afterRemove(replacement); + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + + // 删除节点之后的处理 + afterRemove(node); + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + + // 删除节点之后的处理 + afterRemove(node); + } + } + + private Node node(E element) { + Node node = root; + while (node != null) { + int cmp = compare(element, node.element); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + + /** + * @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2 + */ + private int compare(E e1, E e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void elementNotNullCheck(E element) { + if (element == null) { + throw new IllegalArgumentException("element must not be null"); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BinaryTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BinaryTree.java new file mode 100644 index 0000000..d1fdf7b --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/BinaryTree.java @@ -0,0 +1,242 @@ +package com.mj.tree; + +import java.util.LinkedList; +import java.util.Queue; + +public class BinaryTree { + protected int size; + protected Node root; + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + public void preorder(Visitor visitor) { + if (visitor == null) return; + preorder(root, visitor); + } + + private void preorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + visitor.stop = visitor.visit(node.element); + preorder(node.left, visitor); + preorder(node.right, visitor); + } + + public void inorder(Visitor visitor) { + if (visitor == null) return; + inorder(root, visitor); + } + + private void inorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + inorder(node.left, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + inorder(node.right, visitor); + } + + public void postorder(Visitor visitor) { + if (visitor == null) return; + postorder(root, visitor); + } + + private void postorder(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + postorder(node.left, visitor); + postorder(node.right, visitor); + if (visitor.stop) return; + visitor.stop = visitor.visit(node.element); + } + + public void levelOrder(Visitor visitor) { + if (root == null || visitor == null) return; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (visitor.visit(node.element)) return; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + } + + public boolean isComplete() { + if (root == null) return false; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + boolean leaf = false; + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (leaf && !node.isLeaf()) return false; + + if (node.left != null) { + queue.offer(node.left); + } else if (node.right != null) { + return false; + } + + if (node.right != null) { + queue.offer(node.right); + } else { // 后面遍历的节点都必须是叶子节点 + leaf = true; + } + } + + return true; + } + + public int height() { + if (root == null) return 0; + + // 树的高度 + int height = 0; + // 存储着每一层的元素数量 + int levelSize = 1; + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + levelSize--; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + + if (levelSize == 0) { // 意味着即将要访问下一层 + levelSize = queue.size(); + height++; + } + } + + return height; + } + + public int height2() { + return height(root); + } + + private int height(Node node) { + if (node == null) return 0; + return 1 + Math.max(height(node.left), height(node.right)); + } + + protected Node createNode(E element, Node parent) { + return new Node<>(element, parent); + } + + protected Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + protected Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + public static abstract class Visitor { + boolean stop; + /** + * @return 如果返回true,就代表停止遍历 + */ + public abstract boolean visit(E element); + } + + protected static class Node { + E element; + Node left; + Node right; + Node parent; + public Node(E element, Node parent) { + this.element = element; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + + public boolean isLeftChild() { + return parent != null && this == parent.left; + } + + public boolean isRightChild() { + return parent != null && this == parent.right; + } + + public Node sibling() { + if (isLeftChild()) { + return parent.right; + } + + if (isRightChild()) { + return parent.left; + } + + return null; + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/RBTree.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/RBTree.java new file mode 100644 index 0000000..c52ff59 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/09-集合/src/com/mj/tree/RBTree.java @@ -0,0 +1,268 @@ +package com.mj.tree; + +import java.util.Comparator; + +public class RBTree extends BBST { + private static final boolean RED = false; + private static final boolean BLACK = true; + + public RBTree() { + this(null); + } + + public RBTree(Comparator comparator) { + super(comparator); + } + + @Override + protected void afterAdd(Node node) { + Node parent = node.parent; + + // 添加的是根节点 或者 上溢到达了根节点 + if (parent == null) { + black(node); + return; + } + + // 如果父节点是黑色,直接返回 + if (isBlack(parent)) return; + + // 叔父节点 + Node uncle = parent.sibling(); + // 祖父节点 + Node grand = red(parent.parent); + if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】 + black(parent); + black(uncle); + // 把祖父节点当做是新添加的节点 + afterAdd(grand); + return; + } + + // 叔父节点不是红色 + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + black(parent); + } else { // LR + black(node); + rotateLeft(parent); + } + rotateRight(grand); + } else { // R + if (node.isLeftChild()) { // RL + black(node); + rotateRight(parent); + } else { // RR + black(parent); + } + rotateLeft(grand); + } + } + + @Override + protected void afterRemove(Node node) { + // 如果删除的节点是红色 + // 或者 用以取代删除节点的子节点是红色 + if (isRed(node)) { + black(node); + return; + } + + Node parent = node.parent; + // 删除的是根节点 + if (parent == null) return; + + // 删除的是黑色叶子节点【下溢】 + // 判断被删除的node是左还是右 + boolean left = parent.left == null || node.isLeftChild(); + Node sibling = left ? parent.right : parent.left; + if (left) { // 被删除的节点在左边,兄弟节点在右边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateLeft(parent); + // 更换兄弟 + sibling = parent.right; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.right)) { + rotateRight(sibling); + sibling = parent.right; + } + + color(sibling, colorOf(parent)); + black(sibling.right); + black(parent); + rotateLeft(parent); + } + } else { // 被删除的节点在右边,兄弟节点在左边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateRight(parent); + // 更换兄弟 + sibling = parent.left; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.left)) { + rotateLeft(sibling); + sibling = parent.left; + } + + color(sibling, colorOf(parent)); + black(sibling.left); + black(parent); + rotateRight(parent); + } + } + } +// protected void afterRemove(Node node, Node replacement) { +// // 如果删除的节点是红色 +// if (isRed(node)) return; +// +// // 用以取代node的子节点是红色 +// if (isRed(replacement)) { +// black(replacement); +// return; +// } +// +// Node parent = node.parent; +// // 删除的是根节点 +// if (parent == null) return; +// +// // 删除的是黑色叶子节点【下溢】 +// // 判断被删除的node是左还是右 +// boolean left = parent.left == null || node.isLeftChild(); +// Node sibling = left ? parent.right : parent.left; +// if (left) { // 被删除的节点在左边,兄弟节点在右边 +// if (isRed(sibling)) { // 兄弟节点是红色 +// black(sibling); +// red(parent); +// rotateLeft(parent); +// // 更换兄弟 +// sibling = parent.right; +// } +// +// // 兄弟节点必然是黑色 +// if (isBlack(sibling.left) && isBlack(sibling.right)) { +// // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 +// boolean parentBlack = isBlack(parent); +// black(parent); +// red(sibling); +// if (parentBlack) { +// afterRemove(parent, null); +// } +// } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 +// // 兄弟节点的左边是黑色,兄弟要先旋转 +// if (isBlack(sibling.right)) { +// rotateRight(sibling); +// sibling = parent.right; +// } +// +// color(sibling, colorOf(parent)); +// black(sibling.right); +// black(parent); +// rotateLeft(parent); +// } +// } else { // 被删除的节点在右边,兄弟节点在左边 +// if (isRed(sibling)) { // 兄弟节点是红色 +// black(sibling); +// red(parent); +// rotateRight(parent); +// // 更换兄弟 +// sibling = parent.left; +// } +// +// // 兄弟节点必然是黑色 +// if (isBlack(sibling.left) && isBlack(sibling.right)) { +// // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 +// boolean parentBlack = isBlack(parent); +// black(parent); +// red(sibling); +// if (parentBlack) { +// afterRemove(parent, null); +// } +// } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 +// // 兄弟节点的左边是黑色,兄弟要先旋转 +// if (isBlack(sibling.left)) { +// rotateLeft(sibling); +// sibling = parent.left; +// } +// +// color(sibling, colorOf(parent)); +// black(sibling.left); +// black(parent); +// rotateRight(parent); +// } +// } +// } + + private Node color(Node node, boolean color) { + if (node == null) return node; + ((RBNode)node).color = color; + return node; + } + + private Node red(Node node) { + return color(node, RED); + } + + private Node black(Node node) { + return color(node, BLACK); + } + + private boolean colorOf(Node node) { + return node == null ? BLACK : ((RBNode)node).color; + } + + private boolean isBlack(Node node) { + return colorOf(node) == BLACK; + } + + private boolean isRed(Node node) { + return colorOf(node) == RED; + } + + @Override + protected Node createNode(E element, Node parent) { + return new RBNode<>(element, parent); + } + + private static class RBNode extends Node { + boolean color = RED; + public RBNode(E element, Node parent) { + super(element, parent); + } + + @Override + public String toString() { + String str = ""; + if (color == RED) { + str = "R_"; + } + return str + element.toString(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.project new file mode 100644 index 0000000..c265430 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.project @@ -0,0 +1,17 @@ + + + 10-映射 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$1.class new file mode 100644 index 0000000..3ff3bfa Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$2.class new file mode 100644 index 0000000..754d0ee Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$3.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$3.class new file mode 100644 index 0000000..367d6a6 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main$3.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main.class new file mode 100644 index 0000000..4260a71 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Times$Task.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Times$Task.class new file mode 100644 index 0000000..573edc2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Times$Task.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Times.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Times.class new file mode 100644 index 0000000..49d99e8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/Times.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/FileInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/FileInfo.class new file mode 100644 index 0000000..3d5f61c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/FileInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/Files$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/Files$1.class new file mode 100644 index 0000000..01b769c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/Files$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/Files.class new file mode 100644 index 0000000..2983be9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/Map$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/Map$Visitor.class new file mode 100644 index 0000000..feabbc5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/Map$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/Map.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/Map.class new file mode 100644 index 0000000..ca0f544 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/Map.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/TreeMap$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/TreeMap$Node.class new file mode 100644 index 0000000..77fd587 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/TreeMap$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/TreeMap.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/TreeMap.class new file mode 100644 index 0000000..d6083ac Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/map/TreeMap.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/Set$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/Set$Visitor.class new file mode 100644 index 0000000..5bd00a2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/Set$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/Set.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/Set.class new file mode 100644 index 0000000..deb255c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/Set.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/TreeSet$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/TreeSet$1.class new file mode 100644 index 0000000..32228d0 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/TreeSet$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/TreeSet.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/TreeSet.class new file mode 100644 index 0000000..5d72fee Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/bin/com/mj/set/TreeSet.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/Main.java new file mode 100644 index 0000000..4cb234e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/Main.java @@ -0,0 +1,72 @@ +package com.mj; + +import com.mj.file.FileInfo; +import com.mj.file.Files; +import com.mj.map.Map; +import com.mj.map.Map.Visitor; +import com.mj.map.TreeMap; +import com.mj.set.Set; +import com.mj.set.TreeSet; + +public class Main { + + static void test1() { + Map map = new TreeMap<>(); + map.put("c", 2); + map.put("a", 5); + map.put("b", 6); + map.put("a", 8); + + map.traversal(new Visitor() { + public boolean visit(String key, Integer value) { + System.out.println(key + "_" + value); + return false; + } + }); + } + + static void test2() { + FileInfo fileInfo = Files.read("F:\\CoderMJLee\\DSA_Course\\课堂代码\\09-集合\\src", + new String[]{"java"}); + + System.out.println("文件数量:" + fileInfo.getFiles()); + System.out.println("代码行数:" + fileInfo.getLines()); + String[] words = fileInfo.words(); + System.out.println("单词数量:" + words.length); + + Map map = new TreeMap<>(); + for (int i = 0; i < words.length; i++) { + Integer count = map.get(words[i]); + count = (count == null) ? 1 : (count + 1); + map.put(words[i], count); + } + + map.traversal(new Visitor() { + public boolean visit(String key, Integer value) { + System.out.println(key + "_" + value); + return false; + } + }); + } + + static void test3() { + Set set = new TreeSet<>(); + set.add("c"); + set.add("b"); + set.add("c"); + set.add("c"); + set.add("a"); + + set.traversal(new Set.Visitor() { + public boolean visit(String element) { + System.out.println(element); + return false; + } + }); + } + + public static void main(String[] args) { + test3(); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/Times.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/Times.java new file mode 100644 index 0000000..35c93a4 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/Times.java @@ -0,0 +1,26 @@ +package com.mj; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Times { + private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS"); + + public interface Task { + void execute(); + } + + public static void test(String title, Task task) { + if (task == null) return; + title = (title == null) ? "" : ("【" + title + "】"); + System.out.println(title); + System.out.println("开始:" + fmt.format(new Date())); + long begin = System.currentTimeMillis(); + task.execute(); + long end = System.currentTimeMillis(); + System.out.println("结束:" + fmt.format(new Date())); + double delta = (end - begin) / 1000.0; + System.out.println("耗时:" + delta + "秒"); + System.out.println("-------------------------------------"); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/file/FileInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/file/FileInfo.java new file mode 100644 index 0000000..676fc6e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/file/FileInfo.java @@ -0,0 +1,47 @@ +package com.mj.file; + +public class FileInfo { + private int lines; + private int files; + private String content = ""; + + public String[] words() { + return content.split("[^a-zA-Z]+"); + } + + public int getFiles() { + return files; + } + + public void setFiles(int files) { + this.files = files; + } + + public int getLines() { + return lines; + } + + public void setLines(int lines) { + this.lines = lines; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public FileInfo append(FileInfo info) { + if (info != null && info.lines > 0) { + this.files += info.files; + this.lines += info.lines; + this.content = new StringBuilder(this.content) + .append("\n") + .append(info.content) + .toString(); + } + return this; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/file/Files.java new file mode 100644 index 0000000..1214723 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/file/Files.java @@ -0,0 +1,72 @@ +package com.mj.file; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.IOException; + +public class Files { + + /** + * 读取文件内容 + * @param file + * @return + */ + public static FileInfo read(String file) { + if (file == null) return null; + FileInfo info = new FileInfo(); + StringBuilder sb = new StringBuilder(); + try (FileReader reader = new FileReader(file); + BufferedReader br = new BufferedReader(reader)) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append("\n"); + info.setLines(info.getLines() + 1); + } + int len = sb.length(); + if (len > 0) { + sb.deleteCharAt(len - 1); + } + } catch (IOException e) { + e.printStackTrace(); + } + info.setFiles(info.getFiles() + 1); + info.setContent(sb.toString()); + return info; + } + + /** + * 读取文件夹下面的文件内容 + * @param dir + * @param extensions + * @return + */ + public static FileInfo read(String dir, String[] extensions) { + if (dir == null) return null; + + File dirFile = new File(dir); + if (!dirFile.exists()) return null; + + FileInfo info = new FileInfo(); + dirFile.listFiles(new FileFilter() { + public boolean accept(File subFile) { + String subFilepath = subFile.getAbsolutePath(); + if (subFile.isDirectory()) { + info.append(read(subFilepath, extensions)); + } else if (extensions != null && extensions.length > 0) { + for (String extension : extensions) { + if (subFilepath.endsWith("." + extension)) { + info.append(read(subFilepath)); + break; + } + } + } else { + info.append(read(subFilepath)); + } + return false; + } + }); + return info; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/map/Map.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/map/Map.java new file mode 100644 index 0000000..88a91ff --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/map/Map.java @@ -0,0 +1,18 @@ +package com.mj.map; + +public interface Map { + int size(); + boolean isEmpty(); + void clear(); + V put(K key, V value); + V get(K key); + V remove(K key); + boolean containsKey(K key); + boolean containsValue(V value); + void traversal(Visitor visitor); + + public static abstract class Visitor { + boolean stop; + public abstract boolean visit(K key, V value); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/map/TreeMap.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/map/TreeMap.java new file mode 100644 index 0000000..e3d4433 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/map/TreeMap.java @@ -0,0 +1,486 @@ +package com.mj.map; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.Queue; + +@SuppressWarnings({"unchecked", "unused"}) +public class TreeMap implements Map { + private static final boolean RED = false; + private static final boolean BLACK = true; + private int size; + private Node root; + private Comparator comparator; + + public TreeMap() { + this(null); + } + + public TreeMap(Comparator comparator) { + this.comparator = comparator; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + @Override + public V put(K key, V value) { + keyNotNullCheck(key); + + // 添加第一个节点 + if (root == null) { + root = new Node<>(key, value, null); + size++; + + // 新添加节点之后的处理 + afterPut(root); + return null; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(key, node.key); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.key = key; + V oldValue = node.value; + node.value = value; + return oldValue; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = new Node<>(key, value, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + + // 新添加节点之后的处理 + afterPut(newNode); + return null; + } + + @Override + public V get(K key) { + Node node = node(key); + return node != null ? node.value : null; + } + + @Override + public V remove(K key) { + return remove(node(key)); + } + + @Override + public boolean containsKey(K key) { + return node(key) != null; + } + + @Override + public boolean containsValue(V value) { + if (root == null) return false; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (valEquals(value, node.value)) return true; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + + return false; + } + + @Override + public void traversal(Visitor visitor) { + if (visitor == null) return; + traversal(root, visitor); + } + + private void traversal(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + traversal(node.left, visitor); + if (visitor.stop) return; + visitor.visit(node.key, node.value); + traversal(node.right, visitor); + } + + private boolean valEquals(V v1, V v2) { + return v1 == null ? v2 == null : v1.equals(v2); + } + + private V remove(Node node) { + if (node == null) return null; + + size--; + + V oldValue = node.value; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.key = s.key; + node.value = s.value; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + + // 删除节点之后的处理 + afterRemove(replacement); + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + + // 删除节点之后的处理 + afterRemove(node); + } + + return oldValue; + } + + private void afterRemove(Node node) { + // 如果删除的节点是红色 + // 或者 用以取代删除节点的子节点是红色 + if (isRed(node)) { + black(node); + return; + } + + Node parent = node.parent; + if (parent == null) return; + + // 删除的是黑色叶子节点【下溢】 + // 判断被删除的node是左还是右 + boolean left = parent.left == null || node.isLeftChild(); + Node sibling = left ? parent.right : parent.left; + if (left) { // 被删除的节点在左边,兄弟节点在右边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateLeft(parent); + // 更换兄弟 + sibling = parent.right; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.right)) { + rotateRight(sibling); + sibling = parent.right; + } + + color(sibling, colorOf(parent)); + black(sibling.right); + black(parent); + rotateLeft(parent); + } + } else { // 被删除的节点在右边,兄弟节点在左边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateRight(parent); + // 更换兄弟 + sibling = parent.left; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.left)) { + rotateLeft(sibling); + sibling = parent.left; + } + + color(sibling, colorOf(parent)); + black(sibling.left); + black(parent); + rotateRight(parent); + } + } + } + + private Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + private Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + private Node node(K key) { + Node node = root; + while (node != null) { + int cmp = compare(key, node.key); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + + private void afterPut(Node node) { + Node parent = node.parent; + + // 添加的是根节点 或者 上溢到达了根节点 + if (parent == null) { + black(node); + return; + } + + // 如果父节点是黑色,直接返回 + if (isBlack(parent)) return; + + // 叔父节点 + Node uncle = parent.sibling(); + // 祖父节点 + Node grand = red(parent.parent); + if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】 + black(parent); + black(uncle); + // 把祖父节点当做是新添加的节点 + afterPut(grand); + return; + } + + // 叔父节点不是红色 + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + black(parent); + } else { // LR + black(node); + rotateLeft(parent); + } + rotateRight(grand); + } else { // R + if (node.isLeftChild()) { // RL + black(node); + rotateRight(parent); + } else { // RR + black(parent); + } + rotateLeft(grand); + } + } + + private void rotateLeft(Node grand) { + Node parent = grand.right; + Node child = parent.left; + grand.right = child; + parent.left = grand; + afterRotate(grand, parent, child); + } + + private void rotateRight(Node grand) { + Node parent = grand.left; + Node child = parent.right; + grand.left = child; + parent.right = grand; + afterRotate(grand, parent, child); + } + + private void afterRotate(Node grand, Node parent, Node child) { + // 让parent称为子树的根节点 + parent.parent = grand.parent; + if (grand.isLeftChild()) { + grand.parent.left = parent; + } else if (grand.isRightChild()) { + grand.parent.right = parent; + } else { // grand是root节点 + root = parent; + } + + // 更新child的parent + if (child != null) { + child.parent = grand; + } + + // 更新grand的parent + grand.parent = parent; + } + + private Node color(Node node, boolean color) { + if (node == null) return node; + node.color = color; + return node; + } + + private Node red(Node node) { + return color(node, RED); + } + + private Node black(Node node) { + return color(node, BLACK); + } + + private boolean colorOf(Node node) { + return node == null ? BLACK : node.color; + } + + private boolean isBlack(Node node) { + return colorOf(node) == BLACK; + } + + private boolean isRed(Node node) { + return colorOf(node) == RED; + } + + private int compare(K e1, K e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void keyNotNullCheck(K key) { + if (key == null) { + throw new IllegalArgumentException("key must not be null"); + } + } + + private static class Node { + K key; + V value; + boolean color = RED; + Node left; + Node right; + Node parent; + public Node(K key, V value, Node parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + + public boolean isLeftChild() { + return parent != null && this == parent.left; + } + + public boolean isRightChild() { + return parent != null && this == parent.right; + } + + public Node sibling() { + if (isLeftChild()) { + return parent.right; + } + + if (isRightChild()) { + return parent.left; + } + + return null; + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/set/Set.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/set/Set.java new file mode 100644 index 0000000..cfb49e1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/set/Set.java @@ -0,0 +1,16 @@ +package com.mj.set; + +public interface Set { + int size(); + boolean isEmpty(); + void clear(); + boolean contains(E element); + void add(E element); + void remove(E element); + void traversal(Visitor visitor); + + public static abstract class Visitor { + boolean stop; + public abstract boolean visit(E element); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/set/TreeSet.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/set/TreeSet.java new file mode 100644 index 0000000..00c4ea2 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/10-映射/src/com/mj/set/TreeSet.java @@ -0,0 +1,48 @@ +package com.mj.set; + +import com.mj.map.Map; +import com.mj.map.TreeMap; + +public class TreeSet implements Set { + Map map = new TreeMap<>(); + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public boolean contains(E element) { + return map.containsKey(element); + } + + @Override + public void add(E element) { + map.put(element, null); + } + + @Override + public void remove(E element) { + map.remove(element); + } + + @Override + public void traversal(Visitor visitor) { + map.traversal(new Map.Visitor() { + public boolean visit(E key, Object value) { + return visitor.visit(key); + } + }); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.classpath b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.classpath new file mode 100644 index 0000000..51a8bba --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.project b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.project new file mode 100644 index 0000000..29b4ecc --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.project @@ -0,0 +1,17 @@ + + + 11-哈希表 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.settings/org.eclipse.jdt.core.prefs b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Asserts.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Asserts.class new file mode 100644 index 0000000..6540fd7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Asserts.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Main$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Main$1.class new file mode 100644 index 0000000..30ace9d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Main$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Main.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Main.class new file mode 100644 index 0000000..f130845 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Main.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Times$Task.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Times$Task.class new file mode 100644 index 0000000..573edc2 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Times$Task.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Times.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Times.class new file mode 100644 index 0000000..49d99e8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/Times.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/FileInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/FileInfo.class new file mode 100644 index 0000000..3d5f61c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/FileInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/Files$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/Files$1.class new file mode 100644 index 0000000..01b769c Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/Files$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/Files.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/Files.class new file mode 100644 index 0000000..2983be9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/file/Files.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap$1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap$1.class new file mode 100644 index 0000000..a6e8cc9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap$1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap$Node.class new file mode 100644 index 0000000..242042a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap.class new file mode 100644 index 0000000..ff32eec Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/HashMap.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/Map$Visitor.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/Map$Visitor.class new file mode 100644 index 0000000..feabbc5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/Map$Visitor.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/Map.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/Map.class new file mode 100644 index 0000000..ca0f544 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/Map.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/TreeMap$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/TreeMap$Node.class new file mode 100644 index 0000000..77fd587 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/TreeMap$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/TreeMap.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/TreeMap.class new file mode 100644 index 0000000..d6083ac Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/map/TreeMap.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Key.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Key.class new file mode 100644 index 0000000..5d83a43 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Key.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Person.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Person.class new file mode 100644 index 0000000..00a464d Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Person.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Student.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Student.class new file mode 100644 index 0000000..c4e782f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/Student.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/SubKey1.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/SubKey1.class new file mode 100644 index 0000000..939fbbf Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/SubKey1.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/SubKey2.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/SubKey2.class new file mode 100644 index 0000000..2961daa Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/model/SubKey2.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTreeInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTreeInfo.class new file mode 100644 index 0000000..c84fa40 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTreeInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTrees$PrintStyle.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTrees$PrintStyle.class new file mode 100644 index 0000000..6d329fd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTrees$PrintStyle.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTrees.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTrees.class new file mode 100644 index 0000000..e00b4bb Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/BinaryTrees.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/InorderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/InorderPrinter.class new file mode 100644 index 0000000..a028890 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/InorderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class new file mode 100644 index 0000000..919f4b3 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter$LevelInfo.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter$Node.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter$Node.class new file mode 100644 index 0000000..a580601 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter$Node.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter.class new file mode 100644 index 0000000..b6c1394 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/LevelOrderPrinter.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/Printer.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/Printer.class new file mode 100644 index 0000000..24c28d4 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/Printer.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/Strings.class b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/Strings.class new file mode 100644 index 0000000..dc3c14a Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/bin/com/mj/printer/Strings.class differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Asserts.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Asserts.java new file mode 100644 index 0000000..f9b30cd --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Asserts.java @@ -0,0 +1,11 @@ +package com.mj; + +public class Asserts { + public static void test(boolean value) { + try { + if (!value) throw new Exception("测试未通过"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Main.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Main.java new file mode 100644 index 0000000..78e76cd --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Main.java @@ -0,0 +1,259 @@ +package com.mj; + +import com.mj.Times.Task; +import com.mj.file.FileInfo; +import com.mj.file.Files; +import com.mj.map.HashMap; +import com.mj.map.Map; +import com.mj.map.Map.Visitor; +import com.mj.model.Key; +import com.mj.model.Person; +import com.mj.model.SubKey1; +import com.mj.model.SubKey2; + +public class Main { + +// static void test1() { +// String string = "jack"; // 3254239 +// System.out.println(string.hashCode()); +//// int len = string.length(); +//// int hashCode = 0; +//// for (int i = 0; i < len; i++) { +//// char c = string.charAt(i); +//// hashCode = hashCode * 31 + c; +//// // hashCode = (hashCode << 5) - hashCode + c; +//// } +//// System.out.println(hashCode); +// // hashCode = ((j * 31 + a) * 31 + c) * 31 + k +// } +// +// static void test2() { +// Integer a = 110; +// Float b = 10.6f; +// Long c = 156l; +// Double d = 10.9; +// String e = "rose"; +// +// System.out.println(a.hashCode()); +// System.out.println(b.hashCode()); +// System.out.println(c.hashCode()); +// System.out.println(d.hashCode()); +// System.out.println(e.hashCode()); +// } +// +// static void test3() { +// Person p1 = new Person(10, 1.67f, "jack"); +// Person p2 = new Person(10, 1.67f, "jack"); +// +// Map map = new HashMap<>(); +// map.put(p1, "abc"); +// map.put("test", "ccc"); +// map.put(p2, "bcd"); +// System.out.println(map.size()); +// } +// +// static void test4() { +// Person p1 = new Person(10, 1.67f, "jack"); +// Person p2 = new Person(10, 1.67f, "jack"); +// +// Map map = new HashMap<>(); +// map.put(p1, 1); +// map.put(p2, 2); +// map.put("jack", 3); +// map.put("rose", 4); +// map.put("jack", 5); +// map.put(null, 6); +// +//// System.out.println(map.size()); +//// System.out.println(map.remove("jack")); +//// System.out.println(map.get("jack")); +//// System.out.println(map.size()); +// +// System.out.println(map.containsKey(p1)); +// System.out.println(map.containsKey(null)); +// System.out.println(map.containsValue(6)); +// System.out.println(map.containsValue(1)); +// +//// map.traversal(new Visitor() { +//// public boolean visit(Object key, Integer value) { +//// System.out.println(key + "_" + value); +//// return false; +//// } +//// }); +// +//// System.out.println(map.get("jack")); +//// System.out.println(map.get("rose")); +//// System.out.println(map.get(null)); +//// System.out.println(map.get(p1)); +// } +// +// static void test5() { +// Person p1 = new Person(10, 1.67f, "jack"); +// Person p2 = new Person(10, 1.67f, "jack"); +// +// Map map = new HashMap<>(); +// map.put(p1, 1); +// map.put(p2, 2); +// map.put("jack", 3); +// map.put("rose", 4); +// map.put("jack", 5); +// map.put(null, 6); +// +//// System.out.println(map.size()); +//// System.out.println(map.remove("jack")); +//// System.out.println(map.get("jack")); +//// System.out.println(map.size()); +// +// System.out.println(map.containsKey(p1)); +// System.out.println(map.containsKey(null)); +// System.out.println(map.containsValue(6)); +// System.out.println(map.containsValue(1)); +// +//// map.traversal(new Visitor() { +//// public boolean visit(Object key, Integer value) { +//// System.out.println(key + "_" + value); +//// return false; +//// } +//// }); +// +//// System.out.println(map.get("jack")); +//// System.out.println(map.get("rose")); +//// System.out.println(map.get(null)); +//// System.out.println(map.get(p1)); +// } +// +// static void test6() { +// HashMap map = new HashMap<>(); +// for (int i = 1; i <= 19; i++) { +// map.put(new Key(i), i); +// } +// +// map.put(new Key(4), 100); +// Asserts.test(map.size() == 19); +// Asserts.test(map.get(new Key(4)) == 100); +// Asserts.test(map.get(new Key(18)) == 18); +// } +// + + static void test2(HashMap map) { + for (int i = 1; i <= 20; i++) { + map.put(new Key(i), i); + } + for (int i = 5; i <= 7; i++) { + map.put(new Key(i), i + 5); + } + Asserts.test(map.size() == 20); + Asserts.test(map.get(new Key(4)) == 4); + Asserts.test(map.get(new Key(5)) == 10); + Asserts.test(map.get(new Key(6)) == 11); + Asserts.test(map.get(new Key(7)) == 12); + Asserts.test(map.get(new Key(8)) == 8); + } + + static void test3(HashMap map) { + map.put(null, 1); // 1 + map.put(new Object(), 2); // 2 + map.put("jack", 3); // 3 + map.put(10, 4); // 4 + map.put(new Object(), 5); // 5 + map.put("jack", 6); + map.put(10, 7); + map.put(null, 8); + map.put(10, null); + Asserts.test(map.size() == 5); + Asserts.test(map.get(null) == 8); + Asserts.test(map.get("jack") == 6); + Asserts.test(map.get(10) == null); + Asserts.test(map.get(new Object()) == null); + Asserts.test(map.containsKey(10)); + Asserts.test(map.containsKey(null)); + Asserts.test(map.containsValue(null)); + Asserts.test(map.containsValue(1) == false); + } + + static void test4(HashMap map) { + map.put("jack", 1); + map.put("rose", 2); + map.put("jim", 3); + map.put("jake", 4); + for (int i = 1; i <= 10; i++) { + map.put("test" + i, i); + map.put(new Key(i), i); + } + for (int i = 5; i <= 7; i++) { + Asserts.test(map.remove(new Key(i)) == i); + } + for (int i = 1; i <= 3; i++) { + map.put(new Key(i), i + 5); + } + Asserts.test(map.size() == 21); + Asserts.test(map.get(new Key(1)) == 6); + Asserts.test(map.get(new Key(2)) == 7); + Asserts.test(map.get(new Key(3)) == 8); + Asserts.test(map.get(new Key(4)) == 4); + Asserts.test(map.get(new Key(5)) == null); + Asserts.test(map.get(new Key(6)) == null); + Asserts.test(map.get(new Key(7)) == null); + Asserts.test(map.get(new Key(8)) == 8); + } + + static void test5(HashMap map) { + for (int i = 1; i <= 20; i++) { + map.put(new SubKey1(i), i); + } + map.put(new SubKey2(1), 5); + Asserts.test(map.get(new SubKey1(1)) == 5); + Asserts.test(map.get(new SubKey2(1)) == 5); + Asserts.test(map.size() == 20); + } + + static void test1() { + String filepath = "C:\\Users\\MJ Lee\\Desktop\\src\\java\\util"; + FileInfo fileInfo = Files.read(filepath, null); + String[] words = fileInfo.words(); + + System.out.println("总行数:" + fileInfo.getLines()); + System.out.println("单词总数:" + words.length); + System.out.println("-------------------------------------"); + +// java.util.HashMap map = new java.util.HashMap<>(); +// +// for (String word : words) { +// Integer count = map.get(word); +// count = count == null ? 0 : count; +// map.put(word, count + 1); +// } +// System.out.println(map.size()); // 17188 + + HashMap map = new HashMap<>(); + Times.test(map.getClass().getName(), new Task() { + @Override + public void execute() { + for (String word : words) { + Integer count = map.get(word); + count = count == null ? 0 : count; + map.put(word, count + 1); + } + System.out.println(map.size()); // 17188 + + int count = 0; + for (String word : words) { + Integer i = map.get(word); + count += i == null ? 0 : i; + map.remove(word); + } + Asserts.test(count == words.length); + Asserts.test(map.size() == 0); + } + }); + } + + public static void main(String[] args) { + test1(); + test2(new HashMap<>()); + test3(new HashMap<>()); + test4(new HashMap<>()); + test5(new HashMap<>()); + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Times.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Times.java new file mode 100644 index 0000000..35c93a4 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/Times.java @@ -0,0 +1,26 @@ +package com.mj; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Times { + private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS"); + + public interface Task { + void execute(); + } + + public static void test(String title, Task task) { + if (task == null) return; + title = (title == null) ? "" : ("【" + title + "】"); + System.out.println(title); + System.out.println("开始:" + fmt.format(new Date())); + long begin = System.currentTimeMillis(); + task.execute(); + long end = System.currentTimeMillis(); + System.out.println("结束:" + fmt.format(new Date())); + double delta = (end - begin) / 1000.0; + System.out.println("耗时:" + delta + "秒"); + System.out.println("-------------------------------------"); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/file/FileInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/file/FileInfo.java new file mode 100644 index 0000000..676fc6e --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/file/FileInfo.java @@ -0,0 +1,47 @@ +package com.mj.file; + +public class FileInfo { + private int lines; + private int files; + private String content = ""; + + public String[] words() { + return content.split("[^a-zA-Z]+"); + } + + public int getFiles() { + return files; + } + + public void setFiles(int files) { + this.files = files; + } + + public int getLines() { + return lines; + } + + public void setLines(int lines) { + this.lines = lines; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public FileInfo append(FileInfo info) { + if (info != null && info.lines > 0) { + this.files += info.files; + this.lines += info.lines; + this.content = new StringBuilder(this.content) + .append("\n") + .append(info.content) + .toString(); + } + return this; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/file/Files.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/file/Files.java new file mode 100644 index 0000000..1214723 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/file/Files.java @@ -0,0 +1,72 @@ +package com.mj.file; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.IOException; + +public class Files { + + /** + * 读取文件内容 + * @param file + * @return + */ + public static FileInfo read(String file) { + if (file == null) return null; + FileInfo info = new FileInfo(); + StringBuilder sb = new StringBuilder(); + try (FileReader reader = new FileReader(file); + BufferedReader br = new BufferedReader(reader)) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append("\n"); + info.setLines(info.getLines() + 1); + } + int len = sb.length(); + if (len > 0) { + sb.deleteCharAt(len - 1); + } + } catch (IOException e) { + e.printStackTrace(); + } + info.setFiles(info.getFiles() + 1); + info.setContent(sb.toString()); + return info; + } + + /** + * 读取文件夹下面的文件内容 + * @param dir + * @param extensions + * @return + */ + public static FileInfo read(String dir, String[] extensions) { + if (dir == null) return null; + + File dirFile = new File(dir); + if (!dirFile.exists()) return null; + + FileInfo info = new FileInfo(); + dirFile.listFiles(new FileFilter() { + public boolean accept(File subFile) { + String subFilepath = subFile.getAbsolutePath(); + if (subFile.isDirectory()) { + info.append(read(subFilepath, extensions)); + } else if (extensions != null && extensions.length > 0) { + for (String extension : extensions) { + if (subFilepath.endsWith("." + extension)) { + info.append(read(subFilepath)); + break; + } + } + } else { + info.append(read(subFilepath)); + } + return false; + } + }); + return info; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/HashMap.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/HashMap.java new file mode 100644 index 0000000..e8a25fe --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/HashMap.java @@ -0,0 +1,594 @@ +package com.mj.map; + +import java.util.LinkedList; +import java.util.Objects; +import java.util.Queue; + +import org.w3c.dom.ls.LSException; + +import com.mj.printer.BinaryTreeInfo; +import com.mj.printer.BinaryTrees; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class HashMap implements Map { + private static final boolean RED = false; + private static final boolean BLACK = true; + private int size; + private Node[] table; + private static final int DEFAULT_CAPACITY = 1 << 4; + + public HashMap() { + table = new Node[DEFAULT_CAPACITY]; + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + @Override + public void clear() { + if (size == 0) return; + size = 0; + for (int i = 0; i < table.length; i++) { + table[i] = null; + } + } + + @Override + public V put(K key, V value) { + int index = index(key); + // 取出index位置的红黑树根节点 + Node root = table[index]; + if (root == null) { + root = new Node<>(key, value, null); + table[index] = root; + size++; + afterPut(root); + return null; + } + + // 添加新的节点到红黑树上面 + Node parent = root; + Node node = root; + int cmp = 0; + K k1 = key; + int h1 = k1 == null ? 0 : k1.hashCode(); + Node result = null; + boolean searched = false; // 是否已经搜索过这个key + do { + parent = node; + K k2 = node.key; + int h2 = node.hash; + if (h1 > h2) { + cmp = 1; + } else if (h1 < h2) { + cmp = -1; + } else if (Objects.equals(k1, k2)) { + cmp = 0; + } else if (k1 != null && k2 != null + && k1.getClass() == k2.getClass() + && k1 instanceof Comparable + && (cmp = ((Comparable) k1).compareTo(k2)) != 0) { + + } else if (searched) { // 已经扫描了 + cmp = System.identityHashCode(k1) - System.identityHashCode(k2); + } else { // searched == false; 还没有扫描,然后再根据内存地址大小决定左右 + if ((node.left != null && (result = node(node.left, k1)) != null) + || (node.right != null && (result = node(node.right, k1)) != null)) { + // 已经存在这个key + node = result; + cmp = 0; + } else { // 不存在这个key + searched = true; + cmp = System.identityHashCode(k1) - System.identityHashCode(k2); + } + } + + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + V oldValue = node.value; + node.key = key; + node.value = value; + return oldValue; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = new Node<>(key, value, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + + // 新添加节点之后的处理 + afterPut(newNode); + return null; + } + + @Override + public V get(K key) { + Node node = node(key); + return node != null ? node.value : null; + } + + @Override + public V remove(K key) { + return remove(node(key)); + } + + @Override + public boolean containsKey(K key) { + return node(key) != null; + } + + @Override + public boolean containsValue(V value) { + if (size == 0) return false; + Queue> queue = new LinkedList<>(); + for (int i = 0; i < table.length; i++) { + if (table[i] == null) continue; + + queue.offer(table[i]); + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (Objects.equals(value, node.value)) return true; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + } + return false; + } + + @Override + public void traversal(Visitor visitor) { + if (size == 0 || visitor == null) return; + + Queue> queue = new LinkedList<>(); + for (int i = 0; i < table.length; i++) { + if (table[i] == null) continue; + + queue.offer(table[i]); + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (visitor.visit(node.key, node.value)) return; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + } + } + + public void print() { + if (size == 0) return; + for (int i = 0; i < table.length; i++) { + final Node root = table[i]; + System.out.println("【index = " + i + "】"); + BinaryTrees.println(new BinaryTreeInfo() { + @Override + public Object string(Object node) { + return node; + } + + @Override + public Object root() { + return root; + } + + @Override + public Object right(Object node) { + return ((Node)node).right; + } + + @Override + public Object left(Object node) { + return ((Node)node).left; + } + }); + System.out.println("---------------------------------------------------"); + } + } + + private V remove(Node node) { + if (node == null) return null; + + size--; + + V oldValue = node.value; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.key = s.key; + node.value = s.value; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + int index = index(node); + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + table[index] = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + + // 删除节点之后的处理 + afterRemove(replacement); + } else if (node.parent == null) { // node是叶子节点并且是根节点 + table[index] = null; + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + + // 删除节点之后的处理 + afterRemove(node); + } + + return oldValue; + } + + private Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + private Node node(K key) { + Node root = table[index(key)]; + return root == null ? null : node(root, key); + } + + private Node node(Node node, K k1) { + int h1 = k1 == null ? 0 : k1.hashCode(); + // 存储查找结果 + Node result = null; + int cmp = 0; + while (node != null) { + K k2 = node.key; + int h2 = node.hash; + // 先比较哈希值 + if (h1 > h2) { + node = node.right; + } else if (h1 < h2) { + node = node.left; + } else if (Objects.equals(k1, k2)) { + return node; + } else if (k1 != null && k2 != null + && k1.getClass() == k2.getClass() + && k1 instanceof Comparable + && (cmp = ((Comparable) k1).compareTo(k2)) != 0) { + node = cmp > 0 ? node.right : node.left; + } else if (node.right != null && (result = node(node.right, k1)) != null) { + return result; + } else { // 只能往左边找 + node = node.left; + } +// } else if (node.left != null && (result = node(node.left, k1)) != null) { +// return result; +// } else { +// return null; +// } + } + return null; + } + + /** + * 根据key生成对应的索引(在桶数组中的位置) + */ + private int index(K key) { + if (key == null) return 0; + int hash = key.hashCode(); + return (hash ^ (hash >>> 16)) & (table.length - 1); + } + + private int index(Node node) { + return (node.hash ^ (node.hash >>> 16)) & (table.length - 1); + } + + /** + * 比较key大小 + * @param k1 + * @param k2 + * @param h1 k1的hashCode + * @param h2 k2的hashCode + * @return + */ +// private int compare(K k1, K k2, int h1, int h2) { +// // 比较哈希值 +// int result = h1 - h2; +// if (result != 0) return result; +// +// // 比较equals +// if (Objects.equals(k1, k2)) return 0; +// +// // 哈希值相等,但是不equals +// if (k1 != null && k2 != null +// && k1.getClass() == k2.getClass() +// && k1 instanceof Comparable) { +// // 同一种类型并且具备可比较性 +// if (k1 instanceof Comparable) { +// return ((Comparable) k1).compareTo(k2); +// } +// } +// +// // 同一种类型,哈希值相等,但是不equals,但是不具备可比较性 +// // k1不为null,k2为null +// // k1为null,k2不为null +// return System.identityHashCode(k1) - System.identityHashCode(k2); +// } + + private void afterRemove(Node node) { + // 如果删除的节点是红色 + // 或者 用以取代删除节点的子节点是红色 + if (isRed(node)) { + black(node); + return; + } + + Node parent = node.parent; + if (parent == null) return; + + // 删除的是黑色叶子节点【下溢】 + // 判断被删除的node是左还是右 + boolean left = parent.left == null || node.isLeftChild(); + Node sibling = left ? parent.right : parent.left; + if (left) { // 被删除的节点在左边,兄弟节点在右边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateLeft(parent); + // 更换兄弟 + sibling = parent.right; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.right)) { + rotateRight(sibling); + sibling = parent.right; + } + + color(sibling, colorOf(parent)); + black(sibling.right); + black(parent); + rotateLeft(parent); + } + } else { // 被删除的节点在右边,兄弟节点在左边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateRight(parent); + // 更换兄弟 + sibling = parent.left; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.left)) { + rotateLeft(sibling); + sibling = parent.left; + } + + color(sibling, colorOf(parent)); + black(sibling.left); + black(parent); + rotateRight(parent); + } + } + } + + private void afterPut(Node node) { + Node parent = node.parent; + + // 添加的是根节点 或者 上溢到达了根节点 + if (parent == null) { + black(node); + return; + } + + // 如果父节点是黑色,直接返回 + if (isBlack(parent)) return; + + // 叔父节点 + Node uncle = parent.sibling(); + // 祖父节点 + Node grand = red(parent.parent); + if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】 + black(parent); + black(uncle); + // 把祖父节点当做是新添加的节点 + afterPut(grand); + return; + } + + // 叔父节点不是红色 + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + black(parent); + } else { // LR + black(node); + rotateLeft(parent); + } + rotateRight(grand); + } else { // R + if (node.isLeftChild()) { // RL + black(node); + rotateRight(parent); + } else { // RR + black(parent); + } + rotateLeft(grand); + } + } + + private void rotateLeft(Node grand) { + Node parent = grand.right; + Node child = parent.left; + grand.right = child; + parent.left = grand; + afterRotate(grand, parent, child); + } + + private void rotateRight(Node grand) { + Node parent = grand.left; + Node child = parent.right; + grand.left = child; + parent.right = grand; + afterRotate(grand, parent, child); + } + + private void afterRotate(Node grand, Node parent, Node child) { + // 让parent称为子树的根节点 + parent.parent = grand.parent; + if (grand.isLeftChild()) { + grand.parent.left = parent; + } else if (grand.isRightChild()) { + grand.parent.right = parent; + } else { // grand是root节点 + table[index(grand)] = parent; + } + + // 更新child的parent + if (child != null) { + child.parent = grand; + } + + // 更新grand的parent + grand.parent = parent; + } + + private Node color(Node node, boolean color) { + if (node == null) return node; + node.color = color; + return node; + } + + private Node red(Node node) { + return color(node, RED); + } + + private Node black(Node node) { + return color(node, BLACK); + } + + private boolean colorOf(Node node) { + return node == null ? BLACK : node.color; + } + + private boolean isBlack(Node node) { + return colorOf(node) == BLACK; + } + + private boolean isRed(Node node) { + return colorOf(node) == RED; + } + + private static class Node { + int hash; + K key; + V value; + boolean color = RED; + Node left; + Node right; + Node parent; + public Node(K key, V value, Node parent) { + this.key = key; + this.hash = key == null ? 0 : key.hashCode(); + this.value = value; + this.parent = parent; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + + public boolean isLeftChild() { + return parent != null && this == parent.left; + } + + public boolean isRightChild() { + return parent != null && this == parent.right; + } + + public Node sibling() { + if (isLeftChild()) { + return parent.right; + } + + if (isRightChild()) { + return parent.left; + } + + return null; + } + + @Override + public String toString() { + return "Node_" + key + "_" + value; + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/Map.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/Map.java new file mode 100644 index 0000000..88a91ff --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/Map.java @@ -0,0 +1,18 @@ +package com.mj.map; + +public interface Map { + int size(); + boolean isEmpty(); + void clear(); + V put(K key, V value); + V get(K key); + V remove(K key); + boolean containsKey(K key); + boolean containsValue(V value); + void traversal(Visitor visitor); + + public static abstract class Visitor { + boolean stop; + public abstract boolean visit(K key, V value); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/TreeMap.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/TreeMap.java new file mode 100644 index 0000000..e3d4433 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/map/TreeMap.java @@ -0,0 +1,486 @@ +package com.mj.map; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.Queue; + +@SuppressWarnings({"unchecked", "unused"}) +public class TreeMap implements Map { + private static final boolean RED = false; + private static final boolean BLACK = true; + private int size; + private Node root; + private Comparator comparator; + + public TreeMap() { + this(null); + } + + public TreeMap(Comparator comparator) { + this.comparator = comparator; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public void clear() { + root = null; + size = 0; + } + + @Override + public V put(K key, V value) { + keyNotNullCheck(key); + + // 添加第一个节点 + if (root == null) { + root = new Node<>(key, value, null); + size++; + + // 新添加节点之后的处理 + afterPut(root); + return null; + } + + // 添加的不是第一个节点 + // 找到父节点 + Node parent = root; + Node node = root; + int cmp = 0; + do { + cmp = compare(key, node.key); + parent = node; + if (cmp > 0) { + node = node.right; + } else if (cmp < 0) { + node = node.left; + } else { // 相等 + node.key = key; + V oldValue = node.value; + node.value = value; + return oldValue; + } + } while (node != null); + + // 看看插入到父节点的哪个位置 + Node newNode = new Node<>(key, value, parent); + if (cmp > 0) { + parent.right = newNode; + } else { + parent.left = newNode; + } + size++; + + // 新添加节点之后的处理 + afterPut(newNode); + return null; + } + + @Override + public V get(K key) { + Node node = node(key); + return node != null ? node.value : null; + } + + @Override + public V remove(K key) { + return remove(node(key)); + } + + @Override + public boolean containsKey(K key) { + return node(key) != null; + } + + @Override + public boolean containsValue(V value) { + if (root == null) return false; + + Queue> queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (valEquals(value, node.value)) return true; + + if (node.left != null) { + queue.offer(node.left); + } + + if (node.right != null) { + queue.offer(node.right); + } + } + + return false; + } + + @Override + public void traversal(Visitor visitor) { + if (visitor == null) return; + traversal(root, visitor); + } + + private void traversal(Node node, Visitor visitor) { + if (node == null || visitor.stop) return; + + traversal(node.left, visitor); + if (visitor.stop) return; + visitor.visit(node.key, node.value); + traversal(node.right, visitor); + } + + private boolean valEquals(V v1, V v2) { + return v1 == null ? v2 == null : v1.equals(v2); + } + + private V remove(Node node) { + if (node == null) return null; + + size--; + + V oldValue = node.value; + + if (node.hasTwoChildren()) { // 度为2的节点 + // 找到后继节点 + Node s = successor(node); + // 用后继节点的值覆盖度为2的节点的值 + node.key = s.key; + node.value = s.value; + // 删除后继节点 + node = s; + } + + // 删除node节点(node的度必然是1或者0) + Node replacement = node.left != null ? node.left : node.right; + + if (replacement != null) { // node是度为1的节点 + // 更改parent + replacement.parent = node.parent; + // 更改parent的left、right的指向 + if (node.parent == null) { // node是度为1的节点并且是根节点 + root = replacement; + } else if (node == node.parent.left) { + node.parent.left = replacement; + } else { // node == node.parent.right + node.parent.right = replacement; + } + + // 删除节点之后的处理 + afterRemove(replacement); + } else if (node.parent == null) { // node是叶子节点并且是根节点 + root = null; + } else { // node是叶子节点,但不是根节点 + if (node == node.parent.left) { + node.parent.left = null; + } else { // node == node.parent.right + node.parent.right = null; + } + + // 删除节点之后的处理 + afterRemove(node); + } + + return oldValue; + } + + private void afterRemove(Node node) { + // 如果删除的节点是红色 + // 或者 用以取代删除节点的子节点是红色 + if (isRed(node)) { + black(node); + return; + } + + Node parent = node.parent; + if (parent == null) return; + + // 删除的是黑色叶子节点【下溢】 + // 判断被删除的node是左还是右 + boolean left = parent.left == null || node.isLeftChild(); + Node sibling = left ? parent.right : parent.left; + if (left) { // 被删除的节点在左边,兄弟节点在右边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateLeft(parent); + // 更换兄弟 + sibling = parent.right; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.right)) { + rotateRight(sibling); + sibling = parent.right; + } + + color(sibling, colorOf(parent)); + black(sibling.right); + black(parent); + rotateLeft(parent); + } + } else { // 被删除的节点在右边,兄弟节点在左边 + if (isRed(sibling)) { // 兄弟节点是红色 + black(sibling); + red(parent); + rotateRight(parent); + // 更换兄弟 + sibling = parent.left; + } + + // 兄弟节点必然是黑色 + if (isBlack(sibling.left) && isBlack(sibling.right)) { + // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并 + boolean parentBlack = isBlack(parent); + black(parent); + red(sibling); + if (parentBlack) { + afterRemove(parent); + } + } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素 + // 兄弟节点的左边是黑色,兄弟要先旋转 + if (isBlack(sibling.left)) { + rotateLeft(sibling); + sibling = parent.left; + } + + color(sibling, colorOf(parent)); + black(sibling.left); + black(parent); + rotateRight(parent); + } + } + } + + private Node predecessor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(left.right.right.right....) + Node p = node.left; + if (p != null) { + while (p.right != null) { + p = p.right; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + // node.parent == null + // node == node.parent.right + return node.parent; + } + + private Node successor(Node node) { + if (node == null) return null; + + // 前驱节点在左子树当中(right.left.left.left....) + Node p = node.right; + if (p != null) { + while (p.left != null) { + p = p.left; + } + return p; + } + + // 从父节点、祖父节点中寻找前驱节点 + while (node.parent != null && node == node.parent.right) { + node = node.parent; + } + + return node.parent; + } + + private Node node(K key) { + Node node = root; + while (node != null) { + int cmp = compare(key, node.key); + if (cmp == 0) return node; + if (cmp > 0) { + node = node.right; + } else { // cmp < 0 + node = node.left; + } + } + return null; + } + + private void afterPut(Node node) { + Node parent = node.parent; + + // 添加的是根节点 或者 上溢到达了根节点 + if (parent == null) { + black(node); + return; + } + + // 如果父节点是黑色,直接返回 + if (isBlack(parent)) return; + + // 叔父节点 + Node uncle = parent.sibling(); + // 祖父节点 + Node grand = red(parent.parent); + if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】 + black(parent); + black(uncle); + // 把祖父节点当做是新添加的节点 + afterPut(grand); + return; + } + + // 叔父节点不是红色 + if (parent.isLeftChild()) { // L + if (node.isLeftChild()) { // LL + black(parent); + } else { // LR + black(node); + rotateLeft(parent); + } + rotateRight(grand); + } else { // R + if (node.isLeftChild()) { // RL + black(node); + rotateRight(parent); + } else { // RR + black(parent); + } + rotateLeft(grand); + } + } + + private void rotateLeft(Node grand) { + Node parent = grand.right; + Node child = parent.left; + grand.right = child; + parent.left = grand; + afterRotate(grand, parent, child); + } + + private void rotateRight(Node grand) { + Node parent = grand.left; + Node child = parent.right; + grand.left = child; + parent.right = grand; + afterRotate(grand, parent, child); + } + + private void afterRotate(Node grand, Node parent, Node child) { + // 让parent称为子树的根节点 + parent.parent = grand.parent; + if (grand.isLeftChild()) { + grand.parent.left = parent; + } else if (grand.isRightChild()) { + grand.parent.right = parent; + } else { // grand是root节点 + root = parent; + } + + // 更新child的parent + if (child != null) { + child.parent = grand; + } + + // 更新grand的parent + grand.parent = parent; + } + + private Node color(Node node, boolean color) { + if (node == null) return node; + node.color = color; + return node; + } + + private Node red(Node node) { + return color(node, RED); + } + + private Node black(Node node) { + return color(node, BLACK); + } + + private boolean colorOf(Node node) { + return node == null ? BLACK : node.color; + } + + private boolean isBlack(Node node) { + return colorOf(node) == BLACK; + } + + private boolean isRed(Node node) { + return colorOf(node) == RED; + } + + private int compare(K e1, K e2) { + if (comparator != null) { + return comparator.compare(e1, e2); + } + return ((Comparable)e1).compareTo(e2); + } + + private void keyNotNullCheck(K key) { + if (key == null) { + throw new IllegalArgumentException("key must not be null"); + } + } + + private static class Node { + K key; + V value; + boolean color = RED; + Node left; + Node right; + Node parent; + public Node(K key, V value, Node parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + public boolean isLeaf() { + return left == null && right == null; + } + + public boolean hasTwoChildren() { + return left != null && right != null; + } + + public boolean isLeftChild() { + return parent != null && this == parent.left; + } + + public boolean isRightChild() { + return parent != null && this == parent.right; + } + + public Node sibling() { + if (isLeftChild()) { + return parent.right; + } + + if (isRightChild()) { + return parent.left; + } + + return null; + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Key.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Key.java new file mode 100644 index 0000000..01e3187 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Key.java @@ -0,0 +1,26 @@ +package com.mj.model; + +public class Key { + protected int value; + + public Key(int value) { + this.value = value; + } + + @Override + public int hashCode() { + return value / 10; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != getClass()) return false; + return ((Key) obj).value == value; + } + + @Override + public String toString() { + return "v(" + value + ")"; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Person.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Person.java new file mode 100644 index 0000000..3893f2b --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Person.java @@ -0,0 +1,43 @@ +package com.mj.model; + +public class Person implements Comparable { + private int age; // 10 20 + private float height; // 1.55 1.67 + private String name; // "jack" "rose" + + public Person(int age, float height, String name) { + this.age = age; + this.height = height; + this.name = name; + } + + @Override + /** + * 用来比较2个对象是否相等 + */ + public boolean equals(Object obj) { + // 内存地址 + if (this == obj) return true; + if (obj == null || obj.getClass() != getClass()) return false; + // if (obj == null || !(obj instanceof Person)) return false; + + // 比较成员变量 + Person person = (Person) obj; + return person.age == age + && person.height == height + && (person.name == null ? name == null : person.name.equals(name)); + } + + @Override + public int hashCode() { + int hashCode = Integer.hashCode(age); + hashCode = hashCode * 31 + Float.hashCode(height); + hashCode = hashCode * 31 + (name != null ? name.hashCode() : 0); + return hashCode; + } + + @Override + public int compareTo(Person o) { + return age - o.age; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Student.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Student.java new file mode 100644 index 0000000..26d777c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/Student.java @@ -0,0 +1,10 @@ +package com.mj.model; + +public class Student extends Person { + + public Student(int age, float height, String name) { + super(age, height, name); + // TODO Auto-generated constructor stub + } + +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/SubKey1.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/SubKey1.java new file mode 100644 index 0000000..3b37271 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/SubKey1.java @@ -0,0 +1,17 @@ +package com.mj.model; + +public class SubKey1 extends Key { + + public SubKey1(int value) { + super(value); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || + (obj.getClass() != SubKey1.class + && obj.getClass() != SubKey2.class)) return false; + return ((Key) obj).value == value; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/SubKey2.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/SubKey2.java new file mode 100644 index 0000000..3536b66 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/model/SubKey2.java @@ -0,0 +1,17 @@ +package com.mj.model; + +public class SubKey2 extends Key { + + public SubKey2(int value) { + super(value); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || + (obj.getClass() != SubKey1.class + && obj.getClass() != SubKey2.class)) return false; + return ((Key) obj).value == value; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/BinaryTreeInfo.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/BinaryTreeInfo.java new file mode 100644 index 0000000..d7a6c4d --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/BinaryTreeInfo.java @@ -0,0 +1,20 @@ +package com.mj.printer; + +public interface BinaryTreeInfo { + /** + * who is the root node + */ + Object root(); + /** + * how to get the left child of the node + */ + Object left(Object node); + /** + * how to get the right child of the node + */ + Object right(Object node); + /** + * how to print the node + */ + Object string(Object node); +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/BinaryTrees.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/BinaryTrees.java new file mode 100644 index 0000000..d3b878a --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/BinaryTrees.java @@ -0,0 +1,48 @@ +package com.mj.printer; + +/** + * + * @author MJ Lee + * + */ +public final class BinaryTrees { + + private BinaryTrees() { + } + + public static void print(BinaryTreeInfo tree) { + print(tree, null); + } + + public static void println(BinaryTreeInfo tree) { + println(tree, null); + } + + public static void print(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).print(); + } + + public static void println(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return; + printer(tree, style).println(); + } + + public static String printString(BinaryTreeInfo tree) { + return printString(tree, null); + } + + public static String printString(BinaryTreeInfo tree, PrintStyle style) { + if (tree == null || tree.root() == null) return null; + return printer(tree, style).printString(); + } + + private static Printer printer(BinaryTreeInfo tree, PrintStyle style) { + if (style == PrintStyle.INORDER) return new InorderPrinter(tree); + return new LevelOrderPrinter(tree); + } + + public enum PrintStyle { + LEVEL_ORDER, INORDER + } +} \ No newline at end of file diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/InorderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/InorderPrinter.java new file mode 100644 index 0000000..85b6211 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/InorderPrinter.java @@ -0,0 +1,89 @@ +package com.mj.printer; + +/** + + ┌──800 + ┌──760 + │ └──600 + ┌──540 + │ └──476 + │ └──445 + ┌──410 + │ └──394 +381 + │ ┌──190 + │ │ └──146 + │ ┌──40 + │ │ └──35 + └──12 + └──9 + + * @author MJ Lee + * + */ +public class InorderPrinter extends Printer { + private static String rightAppend; + private static String leftAppend; + private static String blankAppend; + private static String lineAppend; + static { + int length = 2; + rightAppend = "┌" + Strings.repeat("─", length); + leftAppend = "└" + Strings.repeat("─", length); + blankAppend = Strings.blank(length + 1); + lineAppend = "│" + Strings.blank(length); + } + + public InorderPrinter(BinaryTreeInfo tree) { + super(tree); + } + + @Override + public String printString() { + StringBuilder string = new StringBuilder( + printString(tree.root(), "", "", "")); + string.deleteCharAt(string.length() - 1); + return string.toString(); + } + + /** + * 生成node节点的字符串 + * @param nodePrefix node那一行的前缀字符串 + * @param leftPrefix node整棵左子树的前缀字符串 + * @param rightPrefix node整棵右子树的前缀字符串 + * @return + */ + private String printString( + Object node, + String nodePrefix, + String leftPrefix, + String rightPrefix) { + Object left = tree.left(node); + Object right = tree.right(node); + String string = tree.string(node).toString(); + + int length = string.length(); + if (length % 2 == 0) { + length--; + } + length >>= 1; + + String nodeString = ""; + if (right != null) { + rightPrefix += Strings.blank(length); + nodeString += printString(right, + rightPrefix + rightAppend, + rightPrefix + lineAppend, + rightPrefix + blankAppend); + } + nodeString += nodePrefix + string + "\n"; + if (left != null) { + leftPrefix += Strings.blank(length); + nodeString += printString(left, + leftPrefix + leftAppend, + leftPrefix + blankAppend, + leftPrefix + lineAppend); + } + return nodeString; + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/LevelOrderPrinter.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/LevelOrderPrinter.java new file mode 100644 index 0000000..c7c229c --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/LevelOrderPrinter.java @@ -0,0 +1,528 @@ +package com.mj.printer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + + ┌───381────┐ + │ │ +┌─12─┐ ┌─410─┐ +│ │ │ │ +9 ┌─40─┐ 394 ┌─540─┐ + │ │ │ │ + 35 ┌─190 ┌─476 ┌─760─┐ + │ │ │ │ + 146 445 600 800 + + * @author MJ Lee + * + */ +public class LevelOrderPrinter extends Printer { + /** + * 节点之间允许的最小间距(最小只能填1) + */ + private static final int MIN_SPACE = 1; + private Node root; + private int minX; + private int maxWidth; + + public LevelOrderPrinter(BinaryTreeInfo tree) { + super(tree); + + root = new Node(tree.root(), tree); + maxWidth = root.width; + } + + @Override + public String printString() { + // nodes用来存放所有的节点 + List> nodes = new ArrayList<>(); + fillNodes(nodes); + cleanNodes(nodes); + compressNodes(nodes); + addLineNodes(nodes); + + int rowCount = nodes.size(); + + // 构建字符串 + StringBuilder string = new StringBuilder(); + for (int i = 0; i < rowCount; i++) { + if (i != 0) { + string.append("\n"); + } + + List rowNodes = nodes.get(i); + StringBuilder rowSb = new StringBuilder(); + for (Node node : rowNodes) { + int leftSpace = node.x - rowSb.length() - minX; + rowSb.append(Strings.blank(leftSpace)); + rowSb.append(node.string); + } + + string.append(rowSb); + } + + return string.toString(); + } + + /** + * 添加一个元素节点 + */ + private Node addNode(List nodes, Object btNode) { + Node node = null; + if (btNode != null) { + node = new Node(btNode, tree); + maxWidth = Math.max(maxWidth, node.width); + nodes.add(node); + } else { + nodes.add(null); + } + return node; + } + + /** + * 以满二叉树的形式填充节点 + */ + private void fillNodes(List> nodes) { + if (nodes == null) return; + // 第一行 + List firstRowNodes = new ArrayList<>(); + firstRowNodes.add(root); + nodes.add(firstRowNodes); + + // 其他行 + while (true) { + List preRowNodes = nodes.get(nodes.size() - 1); + List rowNodes = new ArrayList<>(); + + boolean notNull = false; + for (Node node : preRowNodes) { + if (node == null) { + rowNodes.add(null); + rowNodes.add(null); + } else { + Node left = addNode(rowNodes, tree.left(node.btNode)); + if (left != null) { + node.left = left; + left.parent = node; + notNull = true; + } + + Node right = addNode(rowNodes, tree.right(node.btNode)); + if (right != null) { + node.right = right; + right.parent = node; + notNull = true; + } + } + } + + // 全是null,就退出 + if (!notNull) break; + nodes.add(rowNodes); + } + } + + /** + * 删除全部null、更新节点的坐标 + */ + private void cleanNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + // 最后一行的节点数量 + int lastRowNodeCount = nodes.get(rowCount - 1).size(); + + // 每个节点之间的间距 + int nodeSpace = maxWidth + 2; + + // 最后一行的长度 + int lastRowLength = lastRowNodeCount * maxWidth + + nodeSpace * (lastRowNodeCount - 1); + + // 空集合 + Collection nullSet = Collections.singleton(null); + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + + int rowNodeCount = rowNodes.size(); + // 节点左右两边的间距 + int allSpace = lastRowLength - (rowNodeCount - 1) * nodeSpace; + int cornerSpace = allSpace / rowNodeCount - maxWidth; + cornerSpace >>= 1; + + int rowLength = 0; + for (int j = 0; j < rowNodeCount; j++) { + if (j != 0) { + // 每个节点之间的间距 + rowLength += nodeSpace; + } + rowLength += cornerSpace; + Node node = rowNodes.get(j); + if (node != null) { + // 居中(由于奇偶数的问题,可能有1个符号的误差) + int deltaX = (maxWidth - node.width) >> 1; + node.x = rowLength + deltaX; + node.y = i; + } + rowLength += maxWidth; + rowLength += cornerSpace; + } + // 删除所有的null + rowNodes.removeAll(nullSet); + } + } + + /** + * 压缩空格 + */ + private void compressNodes(List> nodes) { + if (nodes == null) return; + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + for (int i = rowCount - 2; i >= 0; i--) { + List rowNodes = nodes.get(i); + for (Node node : rowNodes) { + Node left = node.left; + Node right = node.right; + if (left == null && right == null) continue; + if (left != null && right != null) { + // 让左右节点对称 + node.balance(left, right); + + // left和right之间可以挪动的最小间距 + int leftEmpty = node.leftBoundEmptyLength(); + int rightEmpty = node.rightBoundEmptyLength(); + int empty = Math.min(leftEmpty, rightEmpty); + empty = Math.min(empty, (right.x - left.rightX()) >> 1); + + // left、right的子节点之间可以挪动的最小间距 + int space = left.minLevelSpaceToRight(right) - MIN_SPACE; + space = Math.min(space >> 1, empty); + + // left、right往中间挪动 + if (space > 0) { + left.translateX(space); + right.translateX(-space); + } + + // 继续挪动 + space = left.minLevelSpaceToRight(right) - MIN_SPACE; + if (space < 1) continue; + + // 可以继续挪动的间距 + leftEmpty = node.leftBoundEmptyLength(); + rightEmpty = node.rightBoundEmptyLength(); + if (leftEmpty < 1 && rightEmpty < 1) continue; + + if (leftEmpty > rightEmpty) { + left.translateX(Math.min(leftEmpty, space)); + } else { + right.translateX(-Math.min(rightEmpty, space)); + } + } else if (left != null) { + left.translateX(node.leftBoundEmptyLength()); + } else { // right != null + right.translateX(-node.rightBoundEmptyLength()); + } + } + } + } + + private void addXLineNode(List curRow, Node parent, int x) { + Node line = new Node("─"); + line.x = x; + line.y = parent.y; + curRow.add(line); + } + + private Node addLineNode(List curRow, List nextRow, Node parent, Node child) { + if (child == null) return null; + + Node top = null; + int topX = child.topLineX(); + if (child == parent.left) { + top = new Node("┌"); + curRow.add(top); + + for (int x = topX + 1; x < parent.x; x++) { + addXLineNode(curRow, parent, x); + } + } else { + for (int x = parent.rightX(); x < topX; x++) { + addXLineNode(curRow, parent, x); + } + + top = new Node("┐"); + curRow.add(top); + } + + // 坐标 + top.x = topX; + top.y = parent.y; + child.y = parent.y + 2; + minX = Math.min(minX, child.x); + + // 竖线 + Node bottom = new Node("│"); + bottom.x = topX; + bottom.y = parent.y + 1; + nextRow.add(bottom); + + return top; + } + + private void addLineNodes(List> nodes) { + List> newNodes = new ArrayList<>(); + + int rowCount = nodes.size(); + if (rowCount < 2) return; + + minX = root.x; + + for (int i = 0; i < rowCount; i++) { + List rowNodes = nodes.get(i); + if (i == rowCount - 1) { + newNodes.add(rowNodes); + continue; + } + + List newRowNodes = new ArrayList<>(); + newNodes.add(newRowNodes); + + List lineNodes = new ArrayList<>(); + newNodes.add(lineNodes); + for (Node node : rowNodes) { + addLineNode(newRowNodes, lineNodes, node, node.left); + newRowNodes.add(node); + addLineNode(newRowNodes, lineNodes, node, node.right); + } + } + + nodes.clear(); + nodes.addAll(newNodes); + } + + private static class Node { + /** + * 顶部符号距离父节点的最小距离(最小能填0) + */ + private static final int TOP_LINE_SPACE = 1; + + Object btNode; + Node left; + Node right; + Node parent; + /** + * 首字符的位置 + */ + int x; + int y; + int treeHeight; + String string; + int width; + + private void init(String string) { + string = (string == null) ? "null" : string; + string = string.isEmpty() ? " " : string; + + width = string.length(); + this.string = string; + } + + public Node(String string) { + init(string); + } + + public Node(Object btNode, BinaryTreeInfo opetaion) { + init(opetaion.string(btNode).toString()); + + this.btNode = btNode; + } + + /** + * 顶部方向字符的X(极其重要) + * + * @return + */ + private int topLineX() { + // 宽度的一半 + int delta = width; + if (delta % 2 == 0) { + delta--; + } + delta >>= 1; + + if (parent != null && this == parent.left) { + return rightX() - 1 - delta; + } else { + return x + delta; + } + } + + /** + * 右边界的位置(rightX 或者 右子节点topLineX的下一个位置)(极其重要) + */ + private int rightBound() { + if (right == null) return rightX(); + return right.topLineX() + 1; + } + + /** + * 左边界的位置(x 或者 左子节点topLineX)(极其重要) + */ + private int leftBound() { + if (left == null) return x; + return left.topLineX(); + } + + /** + * x ~ 左边界之间的长度(包括左边界字符) + * + * @return + */ + private int leftBoundLength() { + return x - leftBound(); + } + + /** + * rightX ~ 右边界之间的长度(包括右边界字符) + * + * @return + */ + private int rightBoundLength() { + return rightBound() - rightX(); + } + + /** + * 左边界可以清空的长度 + * + * @return + */ + private int leftBoundEmptyLength() { + return leftBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 右边界可以清空的长度 + * + * @return + */ + private int rightBoundEmptyLength() { + return rightBoundLength() - 1 - TOP_LINE_SPACE; + } + + /** + * 让left和right基于this对称 + */ + private void balance(Node left, Node right) { + if (left == null || right == null) + return; + // 【left的尾字符】与【this的首字符】之间的间距 + int deltaLeft = x - left.rightX(); + // 【this的尾字符】与【this的首字符】之间的间距 + int deltaRight = right.x - rightX(); + + int delta = Math.max(deltaLeft, deltaRight); + int newRightX = rightX() + delta; + right.translateX(newRightX - right.x); + + int newLeftX = x - delta - left.width; + left.translateX(newLeftX - left.x); + } + + private int treeHeight(Node node) { + if (node == null) return 0; + if (node.treeHeight != 0) return node.treeHeight; + node.treeHeight = 1 + Math.max( + treeHeight(node.left), treeHeight(node.right)); + return node.treeHeight; + } + + /** + * 和右节点之间的最小层级距离 + */ + private int minLevelSpaceToRight(Node right) { + int thisHeight = treeHeight(this); + int rightHeight = treeHeight(right); + int minSpace = Integer.MAX_VALUE; + for (int i = 0; i < thisHeight && i < rightHeight; i++) { + int space = right.levelInfo(i).leftX + - this.levelInfo(i).rightX; + minSpace = Math.min(minSpace, space); + } + return minSpace; + } + + private LevelInfo levelInfo(int level) { + if (level < 0) return null; + int levelY = y + level; + if (level >= treeHeight(this)) return null; + + List list = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(this); + + // 层序遍历找出第level行的所有节点 + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (levelY == node.y) { + list.add(node); + } else if (node.y > levelY) break; + + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + + Node left = list.get(0); + Node right = list.get(list.size() - 1); + return new LevelInfo(left, right); + } + + /** + * 尾字符的下一个位置 + */ + public int rightX() { + return x + width; + } + + public void translateX(int deltaX) { + if (deltaX == 0) return; + x += deltaX; + + // 如果是LineNode + if (btNode == null) return; + + if (left != null) { + left.translateX(deltaX); + } + if (right != null) { + right.translateX(deltaX); + } + } + } + + private static class LevelInfo { + int leftX; + int rightX; + + public LevelInfo(Node left, Node right) { + this.leftX = left.leftBound(); + this.rightX = right.rightBound(); + } + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/Printer.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/Printer.java new file mode 100644 index 0000000..a8845a1 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/Printer.java @@ -0,0 +1,32 @@ +package com.mj.printer; + +public abstract class Printer { + /** + * 二叉树的基本信息 + */ + protected BinaryTreeInfo tree; + + public Printer(BinaryTreeInfo tree) { + this.tree = tree; + } + + /** + * 生成打印的字符串 + */ + public abstract String printString(); + + /** + * 打印后换行 + */ + public void println() { + print(); + System.out.println(); + } + + /** + * 打印 + */ + public void print() { + System.out.print(printString()); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/Strings.java b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/Strings.java new file mode 100644 index 0000000..83ea770 --- /dev/null +++ b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/11-哈希表/src/com/mj/printer/Strings.java @@ -0,0 +1,19 @@ +package com.mj.printer; + +public class Strings { + public static String repeat(String string, int count) { + if (string == null) return null; + + StringBuilder builder = new StringBuilder(); + while (count-- > 0) { + builder.append(string); + } + return builder.toString(); + } + + public static String blank(int length) { + if (length < 0) return null; + if (length == 0) return ""; + return String.format("%" + length + "s", ""); + } +} diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/01-学前须知.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/01-学前须知.pdf new file mode 100644 index 0000000..11d11ad Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/01-学前须知.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/02-开发环境.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/02-开发环境.pdf new file mode 100644 index 0000000..3dd6b56 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/02-开发环境.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/03-复杂度.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/03-复杂度.pdf new file mode 100644 index 0000000..9799910 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/03-复杂度.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/04-动态数组.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/04-动态数组.pdf new file mode 100644 index 0000000..7742925 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/04-动态数组.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/05-链表.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/05-链表.pdf new file mode 100644 index 0000000..bcd17dd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/05-链表.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/06-栈.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/06-栈.pdf new file mode 100644 index 0000000..8eb3fb8 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/06-栈.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/07-队列.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/07-队列.pdf new file mode 100644 index 0000000..5bc3778 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/07-队列.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/08-二叉树.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/08-二叉树.pdf new file mode 100644 index 0000000..0b518fd Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/08-二叉树.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/09-二叉搜索树.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/09-二叉搜索树.pdf new file mode 100644 index 0000000..3252a5f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/09-二叉搜索树.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/10-平衡二叉搜索树.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/10-平衡二叉搜索树.pdf new file mode 100644 index 0000000..957b9d9 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/10-平衡二叉搜索树.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/11-AVL树.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/11-AVL树.pdf new file mode 100644 index 0000000..7fdcd45 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/11-AVL树.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/12-B树.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/12-B树.pdf new file mode 100644 index 0000000..f6cf214 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/12-B树.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/13-红黑树.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/13-红黑树.pdf new file mode 100644 index 0000000..8104d53 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/13-红黑树.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/14-集合.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/14-集合.pdf new file mode 100644 index 0000000..0b2abd5 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/14-集合.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/15-映射.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/15-映射.pdf new file mode 100644 index 0000000..d37730f Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/15-映射.pdf differ diff --git a/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/16-哈希表.pdf b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/16-哈希表.pdf new file mode 100644 index 0000000..0f79da7 Binary files /dev/null and b/数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/课件/16-哈希表.pdf differ diff --git a/数据结构(双语)/数据结构大二上.zip b/数据结构(双语)/数据结构大二上.zip new file mode 100644 index 0000000..f227b25 Binary files /dev/null and b/数据结构(双语)/数据结构大二上.zip differ diff --git a/概率与统计/往年题/仅题目-历年概率论与数理统计试题分章整理.doc b/概率与统计/往年题/仅题目-历年概率论与数理统计试题分章整理.doc new file mode 100644 index 0000000..5688989 Binary files /dev/null and b/概率与统计/往年题/仅题目-历年概率论与数理统计试题分章整理.doc differ diff --git a/概率与统计/往年题/仅题目-历年概率论与数理统计试题分章整理.pdf b/概率与统计/往年题/仅题目-历年概率论与数理统计试题分章整理.pdf new file mode 100644 index 0000000..bf3427d Binary files /dev/null and b/概率与统计/往年题/仅题目-历年概率论与数理统计试题分章整理.pdf differ diff --git a/概率与统计/往年题/历年概率论与数理统计试题分章整理.doc b/概率与统计/往年题/历年概率论与数理统计试题分章整理.doc new file mode 100644 index 0000000..fa749e7 Binary files /dev/null and b/概率与统计/往年题/历年概率论与数理统计试题分章整理.doc differ diff --git a/概率与统计/概率论.zip b/概率与统计/概率论.zip new file mode 100644 index 0000000..1a7ebdc Binary files /dev/null and b/概率与统计/概率论.zip differ diff --git a/离散数学(双语1)/题库/离散1 题目 不含图论.doc b/离散数学(双语1)/题库/离散1 题目 不含图论.doc new file mode 100644 index 0000000..1c0df57 Binary files /dev/null and b/离散数学(双语1)/题库/离散1 题目 不含图论.doc differ diff --git a/离散数学(双语1)/题库/离散1 题目 不含图论.pdf b/离散数学(双语1)/题库/离散1 题目 不含图论.pdf new file mode 100644 index 0000000..972e794 Binary files /dev/null and b/离散数学(双语1)/题库/离散1 题目 不含图论.pdf differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_1.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_1.ppt new file mode 100644 index 0000000..d65e30b Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_2.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_2.ppt new file mode 100644 index 0000000..6a84123 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_3.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_3.ppt new file mode 100644 index 0000000..b26f69b Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_4.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_4.ppt new file mode 100644 index 0000000..bab0864 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_4.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_5.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_5.ppt new file mode 100644 index 0000000..8211ece Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_5.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_6.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_6.ppt new file mode 100644 index 0000000..9fabed3 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_6.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/代数_7.ppt b/离散数学(双语2)/淘宝群/2015级课件/代数_7.ppt new file mode 100644 index 0000000..75bef04 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/代数_7.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/关系 1.pptx b/离散数学(双语2)/淘宝群/2015级课件/关系 1.pptx new file mode 100644 index 0000000..4fdaeca Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/关系 1.pptx differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/关系 2.ppt b/离散数学(双语2)/淘宝群/2015级课件/关系 2.ppt new file mode 100644 index 0000000..01e1156 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/关系 2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/关系 3.ppt b/离散数学(双语2)/淘宝群/2015级课件/关系 3.ppt new file mode 100644 index 0000000..1325fbb Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/关系 3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/关系 4.ppt b/离散数学(双语2)/淘宝群/2015级课件/关系 4.ppt new file mode 100644 index 0000000..35b3e90 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/关系 4.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/关系 5.ppt b/离散数学(双语2)/淘宝群/2015级课件/关系 5.ppt new file mode 100644 index 0000000..71aa36e Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/关系 5.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/图论 1.ppt b/离散数学(双语2)/淘宝群/2015级课件/图论 1.ppt new file mode 100644 index 0000000..e561ba7 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/图论 1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/图论 2.ppt b/离散数学(双语2)/淘宝群/2015级课件/图论 2.ppt new file mode 100644 index 0000000..f197137 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/图论 2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/图论 3.ppt b/离散数学(双语2)/淘宝群/2015级课件/图论 3.ppt new file mode 100644 index 0000000..f9c77fd Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/图论 3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/图论 4.ppt b/离散数学(双语2)/淘宝群/2015级课件/图论 4.ppt new file mode 100644 index 0000000..9496185 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/图论 4.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/拓朴排序.swf b/离散数学(双语2)/淘宝群/2015级课件/拓朴排序.swf new file mode 100644 index 0000000..125ce17 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/拓朴排序.swf differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/树 1.ppt b/离散数学(双语2)/淘宝群/2015级课件/树 1.ppt new file mode 100644 index 0000000..c9a1909 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/树 1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/树 2.ppt b/离散数学(双语2)/淘宝群/2015级课件/树 2.ppt new file mode 100644 index 0000000..183632d Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/树 2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/树 3.ppt b/离散数学(双语2)/淘宝群/2015级课件/树 3.ppt new file mode 100644 index 0000000..48e8d0e Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/树 3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/格.ppt b/离散数学(双语2)/淘宝群/2015级课件/格.ppt new file mode 100644 index 0000000..5fe0e1d Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/格.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/格_2.ppt b/离散数学(双语2)/淘宝群/2015级课件/格_2.ppt new file mode 100644 index 0000000..d290d6c Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/格_2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/格_3.ppt b/离散数学(双语2)/淘宝群/2015级课件/格_3.ppt new file mode 100644 index 0000000..be6b210 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/格_3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/棋盘多项式.doc b/离散数学(双语2)/淘宝群/2015级课件/棋盘多项式.doc new file mode 100644 index 0000000..60b74c9 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/棋盘多项式.doc differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散.doc b/离散数学(双语2)/淘宝群/2015级课件/离散.doc new file mode 100644 index 0000000..42029bb Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散.doc differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/10.1-10.2.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/10.1-10.2.ppt new file mode 100644 index 0000000..df447e2 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/10.1-10.2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/10.3-10.4.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/10.3-10.4.ppt new file mode 100644 index 0000000..fc70011 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/10.3-10.4.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/Chapter 11 树.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/Chapter 11 树.ppt new file mode 100644 index 0000000..6ca4bff Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/Chapter 11 树.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.1-8.3.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.1-8.3.ppt new file mode 100644 index 0000000..d56dc70 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.1-8.3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.4.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.4.ppt new file mode 100644 index 0000000..528e260 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.4.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.5-8.6.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.5-8.6.ppt new file mode 100644 index 0000000..8179ce3 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/关系8.5-8.6.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/图论_1.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/图论_1.ppt new file mode 100644 index 0000000..fef60b7 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/图论_1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/最短路问题10.6.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/最短路问题10.6.ppt new file mode 100644 index 0000000..ee956d3 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/最短路问题10.6.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/离散数学-第八章.pdf b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/离散数学-第八章.pdf new file mode 100644 index 0000000..3bb9133 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/离散数学-第八章.pdf differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/逻辑1.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/逻辑1.ppt new file mode 100644 index 0000000..d3c241e Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/逻辑1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/集合2.ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/集合2.ppt new file mode 100644 index 0000000..b34b3b8 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学课件/集合2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学(一).ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学(一).ppt new file mode 100644 index 0000000..3f5f0eb Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学(一).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学(三).ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学(三).ppt new file mode 100644 index 0000000..0ccaf26 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学(三).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学(二).ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学(二).ppt new file mode 100644 index 0000000..96bc707 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学(二).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/离散数学(四).ppt b/离散数学(双语2)/淘宝群/2015级课件/离散数学(四).ppt new file mode 100644 index 0000000..5cde44f Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/离散数学(四).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/练习(1).ppt b/离散数学(双语2)/淘宝群/2015级课件/练习(1).ppt new file mode 100644 index 0000000..3a40c1c Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/练习(1).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/练习(2).ppt b/离散数学(双语2)/淘宝群/2015级课件/练习(2).ppt new file mode 100644 index 0000000..9462dc9 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/练习(2).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/练习(3).ppt b/离散数学(双语2)/淘宝群/2015级课件/练习(3).ppt new file mode 100644 index 0000000..724f984 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/练习(3).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/练习(4).ppt b/离散数学(双语2)/淘宝群/2015级课件/练习(4).ppt new file mode 100644 index 0000000..e03b5fa Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/练习(4).ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/计数1.ppt b/离散数学(双语2)/淘宝群/2015级课件/计数1.ppt new file mode 100644 index 0000000..f3526d7 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/计数1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/计数2.ppt b/离散数学(双语2)/淘宝群/2015级课件/计数2.ppt new file mode 100644 index 0000000..e33011f Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/计数2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/逻辑 1.pptx b/离散数学(双语2)/淘宝群/2015级课件/逻辑 1.pptx new file mode 100644 index 0000000..3c38c40 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/逻辑 1.pptx differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/逻辑 2.pptx b/离散数学(双语2)/淘宝群/2015级课件/逻辑 2.pptx new file mode 100644 index 0000000..3a6c4eb Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/逻辑 2.pptx differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/逻辑 3.ppt b/离散数学(双语2)/淘宝群/2015级课件/逻辑 3.ppt new file mode 100644 index 0000000..2fb1df6 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/逻辑 3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2015级课件/逻辑 3.pptx b/离散数学(双语2)/淘宝群/2015级课件/逻辑 3.pptx new file mode 100644 index 0000000..78e7dcf Binary files /dev/null and b/离散数学(双语2)/淘宝群/2015级课件/逻辑 3.pptx differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/20170803组合数学.pptx b/离散数学(双语2)/淘宝群/2016级课件/20170803组合数学.pptx new file mode 100644 index 0000000..090e0ed Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/20170803组合数学.pptx differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/201709-201712离散教学2日历.doc b/离散数学(双语2)/淘宝群/2016级课件/201709-201712离散教学2日历.doc new file mode 100644 index 0000000..737b372 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/201709-201712离散教学2日历.doc differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_1.pdf b/离散数学(双语2)/淘宝群/2016级课件/代数_1.pdf new file mode 100644 index 0000000..2f181f6 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_1.pdf differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_1.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_1.ppt new file mode 100644 index 0000000..0b86d16 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_2.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_2.ppt new file mode 100644 index 0000000..4350b89 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_3.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_3.ppt new file mode 100644 index 0000000..704a546 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_4.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_4.ppt new file mode 100644 index 0000000..398d893 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_4.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_5.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_5.ppt new file mode 100644 index 0000000..b73e8e6 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_5.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_6.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_6.ppt new file mode 100644 index 0000000..17a8a9a Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_6.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/代数_7.ppt b/离散数学(双语2)/淘宝群/2016级课件/代数_7.ppt new file mode 100644 index 0000000..f8dc4ff Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/代数_7.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/格.ppt b/离散数学(双语2)/淘宝群/2016级课件/格.ppt new file mode 100644 index 0000000..498962e Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/格.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/格_2.ppt b/离散数学(双语2)/淘宝群/2016级课件/格_2.ppt new file mode 100644 index 0000000..c33c192 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/格_2.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/格_3.ppt b/离散数学(双语2)/淘宝群/2016级课件/格_3.ppt new file mode 100644 index 0000000..be6b210 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/格_3.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/棋盘多项式.doc b/离散数学(双语2)/淘宝群/2016级课件/棋盘多项式.doc new file mode 100644 index 0000000..60b74c9 Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/棋盘多项式.doc differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/离散数学(2)考试大纲--13级.doc b/离散数学(双语2)/淘宝群/2016级课件/离散数学(2)考试大纲--13级.doc new file mode 100644 index 0000000..fefc66a Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/离散数学(2)考试大纲--13级.doc differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/计数1.ppt b/离散数学(双语2)/淘宝群/2016级课件/计数1.ppt new file mode 100644 index 0000000..cf82ddf Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/计数1.ppt differ diff --git a/离散数学(双语2)/淘宝群/2016级课件/计数2.ppt b/离散数学(双语2)/淘宝群/2016级课件/计数2.ppt new file mode 100644 index 0000000..f2194fa Binary files /dev/null and b/离散数学(双语2)/淘宝群/2016级课件/计数2.ppt differ diff --git a/离散数学(双语2)/淘宝群/~$10组合数学复习题.doc b/离散数学(双语2)/淘宝群/~$10组合数学复习题.doc new file mode 100644 index 0000000..e7fc2db Binary files /dev/null and b/离散数学(双语2)/淘宝群/~$10组合数学复习题.doc differ diff --git a/离散数学(双语2)/淘宝群/~$定义集合.docx b/离散数学(双语2)/淘宝群/~$定义集合.docx new file mode 100644 index 0000000..51a95ac Binary files /dev/null and b/离散数学(双语2)/淘宝群/~$定义集合.docx differ diff --git a/离散数学(双语2)/淘宝群/~$证明集合.docx b/离散数学(双语2)/淘宝群/~$证明集合.docx new file mode 100644 index 0000000..3529ed5 Binary files /dev/null and b/离散数学(双语2)/淘宝群/~$证明集合.docx differ diff --git a/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版 (美)KENNETH H.ROSEN著.pdf b/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版 (美)KENNETH H.ROSEN著.pdf new file mode 100644 index 0000000..98a2217 Binary files /dev/null and b/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版 (美)KENNETH H.ROSEN著.pdf differ diff --git a/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版(课后答案).pdf b/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版(课后答案).pdf new file mode 100644 index 0000000..00db096 Binary files /dev/null and b/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版(课后答案).pdf differ diff --git a/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版(课后答案)未知.pdf b/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版(课后答案)未知.pdf new file mode 100644 index 0000000..cc40954 Binary files /dev/null and b/离散数学(双语2)/淘宝群/《离散数学及其应用》中文第7版(课后答案)未知.pdf differ diff --git a/离散数学(双语2)/淘宝群/代数结构.xmind b/离散数学(双语2)/淘宝群/代数结构.xmind new file mode 100644 index 0000000..4529bc0 Binary files /dev/null and b/离散数学(双语2)/淘宝群/代数结构.xmind differ diff --git a/离散数学(双语2)/淘宝群/山东大学离散数学题库及答案-离散2部分 - 副本.doc b/离散数学(双语2)/淘宝群/山东大学离散数学题库及答案-离散2部分 - 副本.doc new file mode 100644 index 0000000..f354eec Binary files /dev/null and b/离散数学(双语2)/淘宝群/山东大学离散数学题库及答案-离散2部分 - 副本.doc differ diff --git a/离散数学(双语2)/淘宝群/山东大学离散数学题库及答案-离散2部分.doc b/离散数学(双语2)/淘宝群/山东大学离散数学题库及答案-离散2部分.doc new file mode 100644 index 0000000..cf80cd1 Binary files /dev/null and b/离散数学(双语2)/淘宝群/山东大学离散数学题库及答案-离散2部分.doc differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/1、代数系统证明集合-2018年1月4日.docx b/离散数学(双语2)/淘宝群/考前从入门到精通/1、代数系统证明集合-2018年1月4日.docx new file mode 100644 index 0000000..b3890c8 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/1、代数系统证明集合-2018年1月4日.docx differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/1、定义集合-2018年1月4日.docx b/离散数学(双语2)/淘宝群/考前从入门到精通/1、定义集合-2018年1月4日.docx new file mode 100644 index 0000000..8a34146 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/1、定义集合-2018年1月4日.docx differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/16级离散期末考试题.docx b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/16级离散期末考试题.docx new file mode 100644 index 0000000..b4bf29c Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/16级离散期末考试题.docx differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/1、计数练习.pdf b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/1、计数练习.pdf new file mode 100644 index 0000000..cbd9772 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/1、计数练习.pdf differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/2、代数系统习题(无答案).ppt b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/2、代数系统习题(无答案).ppt new file mode 100644 index 0000000..8dd6585 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/2、代数系统习题(无答案).ppt differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/3、代数系统练习题(无答案).pdf b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/3、代数系统练习题(无答案).pdf new file mode 100644 index 0000000..7703261 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/3、代数系统练习题(无答案).pdf differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/4、代数系统-环-例题.doc b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/4、代数系统-环-例题.doc new file mode 100644 index 0000000..60b2287 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/4、代数系统-环-例题.doc differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/5、总练习.doc b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/5、总练习.doc new file mode 100644 index 0000000..408c9fd Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/5、总练习.doc differ diff --git a/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/6、11级离散考试题.doc b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/6、11级离散考试题.doc new file mode 100644 index 0000000..75fa2f3 Binary files /dev/null and b/离散数学(双语2)/淘宝群/考前从入门到精通/考前必刷题/6、11级离散考试题.doc differ diff --git a/离散数学(双语2)/郭总/1、代数系统证明集合-2018年1月4日.docx b/离散数学(双语2)/郭总/1、代数系统证明集合-2018年1月4日.docx new file mode 100644 index 0000000..b3890c8 Binary files /dev/null and b/离散数学(双语2)/郭总/1、代数系统证明集合-2018年1月4日.docx differ diff --git a/离散数学(双语2)/郭总/1、定义集合-2018年1月4日.docx b/离散数学(双语2)/郭总/1、定义集合-2018年1月4日.docx new file mode 100644 index 0000000..8a34146 Binary files /dev/null and b/离散数学(双语2)/郭总/1、定义集合-2018年1月4日.docx differ diff --git a/离散数学(双语2)/郭总/山东大学离散数学题库及答案-离散2部分.doc b/离散数学(双语2)/郭总/山东大学离散数学题库及答案-离散2部分.doc new file mode 100644 index 0000000..cf80cd1 Binary files /dev/null and b/离散数学(双语2)/郭总/山东大学离散数学题库及答案-离散2部分.doc differ diff --git a/离散数学(双语2)/郭总/考前必刷题/16级离散期末考试题.docx b/离散数学(双语2)/郭总/考前必刷题/16级离散期末考试题.docx new file mode 100644 index 0000000..b4bf29c Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/16级离散期末考试题.docx differ diff --git a/离散数学(双语2)/郭总/考前必刷题/1、计数练习.pdf b/离散数学(双语2)/郭总/考前必刷题/1、计数练习.pdf new file mode 100644 index 0000000..cbd9772 Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/1、计数练习.pdf differ diff --git a/离散数学(双语2)/郭总/考前必刷题/2、代数系统习题(无答案).ppt b/离散数学(双语2)/郭总/考前必刷题/2、代数系统习题(无答案).ppt new file mode 100644 index 0000000..8dd6585 Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/2、代数系统习题(无答案).ppt differ diff --git a/离散数学(双语2)/郭总/考前必刷题/3、代数系统练习题(无答案).pdf b/离散数学(双语2)/郭总/考前必刷题/3、代数系统练习题(无答案).pdf new file mode 100644 index 0000000..7703261 Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/3、代数系统练习题(无答案).pdf differ diff --git a/离散数学(双语2)/郭总/考前必刷题/4、代数系统-环-例题.doc b/离散数学(双语2)/郭总/考前必刷题/4、代数系统-环-例题.doc new file mode 100644 index 0000000..60b2287 Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/4、代数系统-环-例题.doc differ diff --git a/离散数学(双语2)/郭总/考前必刷题/5、总练习.doc b/离散数学(双语2)/郭总/考前必刷题/5、总练习.doc new file mode 100644 index 0000000..408c9fd Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/5、总练习.doc differ diff --git a/离散数学(双语2)/郭总/考前必刷题/6、11级离散考试题.doc b/离散数学(双语2)/郭总/考前必刷题/6、11级离散考试题.doc new file mode 100644 index 0000000..75fa2f3 Binary files /dev/null and b/离散数学(双语2)/郭总/考前必刷题/6、11级离散考试题.doc differ diff --git a/离散数学(双语2)/题库/山东大学离散数学题库及答案(计本).pdf b/离散数学(双语2)/题库/山东大学离散数学题库及答案(计本).pdf new file mode 100644 index 0000000..6295933 Binary files /dev/null and b/离散数学(双语2)/题库/山东大学离散数学题库及答案(计本).pdf differ diff --git a/离散数学(双语2)/题库/离散2 题目.doc b/离散数学(双语2)/题库/离散2 题目.doc new file mode 100644 index 0000000..9d24ec1 Binary files /dev/null and b/离散数学(双语2)/题库/离散2 题目.doc differ diff --git a/离散数学(双语2)/题库/离散2 题目.pdf b/离散数学(双语2)/题库/离散2 题目.pdf new file mode 100644 index 0000000..f7a15ca Binary files /dev/null and b/离散数学(双语2)/题库/离散2 题目.pdf differ diff --git a/线性代数/往年题/2013-2014线性代数A.doc b/线性代数/往年题/2013-2014线性代数A 没答案.doc similarity index 100% rename from 线性代数/往年题/2013-2014线性代数A.doc rename to 线性代数/往年题/2013-2014线性代数A 没答案.doc diff --git a/线性代数/往年题/2013-2014线性代数B.docx b/线性代数/往年题/2013-2014线性代数B 没答案.docx similarity index 100% rename from 线性代数/往年题/2013-2014线性代数B.docx rename to 线性代数/往年题/2013-2014线性代数B 没答案.docx diff --git a/计算机组织与结构/机组 (1).zip b/计算机组织与结构/机组 (1).zip new file mode 100644 index 0000000..abf3a16 Binary files /dev/null and b/计算机组织与结构/机组 (1).zip differ