增加淘宝群内容,修改部分文件组织

This commit is contained in:
juzeon 2021-10-13 17:26:45 +08:00
父節點 142168ae8e
當前提交 4152e12576
共有 646 個檔案被更改,包括 62259 行新增0 行删除

查看文件

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

查看文件

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/JavaScript.iml" filepath="$PROJECT_DIR$/.idea/JavaScript.iml" />
</modules>
</component>
</project>

查看文件

@ -0,0 +1,479 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="23be2b93-01af-4bf7-b5e4-6e0cb53250ab" name="Default" comment="" />
<ignored path="$PROJECT_DIR$/.tmp/" />
<ignored path="$PROJECT_DIR$/temp/" />
<ignored path="$PROJECT_DIR$/tmp/" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="375">
<file leaf-file-name="RedBlack.js" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/RedBlack.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="29">
<caret line="1263" column="45" lean-forward="false" selection-start-line="1263" selection-start-column="33" selection-end-line="1263" selection-end-column="45" />
<folding />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>&quot;SetText&quot;</find>
<find>&quot;Deleting:</find>
<find>&quot;Deleting</find>
<find>Node to delete is a leaf. Delete it.</find>
<find>Node to delete has no left child. \nSet parent of deleted node to right child of deleted node.</find>
<find>Node to delete has no left child.</find>
<find>Node to delete has no left child</find>
<find>Node to delete has no right child</find>
<find>Node to delete has two childern</find>
<find>Find largest node in left subtree</find>
<find>&quot;Elemet</find>
<find>&quot; not found</find>
<find>could not delete</find>
<find>valueToDelete</find>
<find>没有找到</find>
<find>调整</find>
<find>Adjusting height after recursive call</find>
<find>Unwinding Recursion</find>
<find>正在搜索</find>
<find>&quot; : &quot;</find>
<find>Show Null Leaves</find>
<find>显示</find>
<find>&quot;NULL&quot;</find>
<find>#</find>
<find>text color</find>
<find>BACKGROUND_COLOR</find>
<find>BACKGROUND_BLACK</find>
<find>deleteElement</find>
<find>treeDelete</find>
<find>Deleted node was red. No tree rotations required.</find>
</findStrings>
<replaceStrings>
<replace>找不到元素</replace>
<replace>右单旋</replace>
<replace>左单旋</replace>
<replace>, 访问左子树</replace>
<replace>, 访问右子树</replace>
<replace>&quot;正在删除</replace>
<replace>&quot;正在删除元素:</replace>
<replace>元素已删除</replace>
<replace>正在搜索元素:</replace>
<replace>未找到!</replace>
<replace>已找到!</replace>
<replace>&quot; 正在添加</replace>
<replace>&quot;正在搜索:</replace>
<replace>&quot;正在刪除:</replace>
<replace>&quot;正在刪除</replace>
<replace>需要删除的是叶子节点,直接删除!</replace>
<replace>需要删除的节点没有左子树</replace>
<replace>需要删除的节点没有右子树</replace>
<replace>需要删除的节点有2棵子树</replace>
<replace>找到左子树中最大的节点</replace>
<replace>元素</replace>
<replace>&quot;元素</replace>
<replace>&quot; 未找到</replace>
<replace>无法删除</replace>
<replace>更新高度值</replace>
<replace>检测平衡因子</replace>
<replace>&quot;&quot;</replace>
<replace>NULL</replace>
<replace>&quot;null&quot;</replace>
<replace>删除的是红色节点. 不需要旋转.</replace>
</replaceStrings>
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/AlgorithmLibrary/BTree.js" />
<option value="$PROJECT_DIR$/about.html" />
<option value="$PROJECT_DIR$/Algorithms.html" />
<option value="$PROJECT_DIR$/BTree.html" />
<option value="$PROJECT_DIR$/visualizationPageStyle.css" />
<option value="$PROJECT_DIR$/AnimationLibrary/AnimationMain.js" />
<option value="$PROJECT_DIR$/AVLtree.html" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/ClosedHash.js" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/TST.js" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/RadixTree.js" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/AVL.js" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/BST.js" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/SplayTree.js" />
<option value="$PROJECT_DIR$/RedBlack.ps" />
<option value="$PROJECT_DIR$/AlgorithmLibrary/RedBlack.js" />
</list>
</option>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
<sorting>DEFINITION_ORDER</sorting>
</component>
<component name="ProjectFrameBounds">
<option name="x" value="-9" />
<option name="y" value="-9" />
<option name="width" value="1938" />
<option name="height" value="1048" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scratches" />
<pane id="Scope" />
<pane id="ProjectPane">
<subPane>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="JavaScript" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="JavaScript" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="JavaScript" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="JavaScript" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="AnimationLibrary" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="JavaScript" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="JavaScript" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="AlgorithmLibrary" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="F:/CoderMJLee/BinaryTrees/BinaryTreeGraph" />
<property name="HbShouldOpenHtmlAsHb" value="" />
<property name="settings.editor.selected.configurable" value="watcher.settings" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration default="true" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application">
<method />
</configuration>
<configuration default="true" type="DartTestRunConfigurationType" factoryName="Dart Test">
<method />
</configuration>
<configuration default="true" type="JavaScriptTestRunnerJest" factoryName="Jest">
<node-interpreter value="project" />
<working-dir value="" />
<envs />
<scope-kind value="ALL" />
<method />
</configuration>
<configuration default="true" type="JavaScriptTestRunnerKarma" factoryName="Karma">
<config-file value="" />
<node-interpreter value="project" />
<envs />
<method />
</configuration>
<configuration default="true" type="JavaScriptTestRunnerProtractor" factoryName="Protractor">
<config-file value="" />
<node-interpreter value="project" />
<envs />
<method />
</configuration>
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
<method />
</configuration>
<configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="project" working-dir="">
<method />
</configuration>
<configuration default="true" type="cucumber.js" factoryName="Cucumber.js">
<option name="cucumberJsArguments" value="" />
<option name="executablePath" />
<option name="filePath" />
<method />
</configuration>
<configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
<node-interpreter>project</node-interpreter>
<node-options />
<gulpfile />
<tasks />
<arguments />
<envs />
<method />
</configuration>
<configuration default="true" type="js.build_tools.npm" factoryName="npm">
<command value="run" />
<scripts />
<node-interpreter value="project" />
<envs />
<method />
</configuration>
<configuration default="true" type="mocha-javascript-test-runner" factoryName="Mocha">
<node-interpreter>project</node-interpreter>
<node-options />
<working-directory />
<pass-parent-env>true</pass-parent-env>
<envs />
<ui />
<extra-mocha-options />
<test-kind>DIRECTORY</test-kind>
<test-directory />
<recursive>false</recursive>
<method />
</configuration>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="23be2b93-01af-4bf7-b5e4-6e0cb53250ab" name="Default" comment="" />
<created>1555083398362</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1555083398362</updated>
<workItem from="1555083399529" duration="5243000" />
<workItem from="1555091355028" duration="1381000" />
<workItem from="1555210249901" duration="10000" />
<workItem from="1555345623280" duration="153000" />
<workItem from="1555396769535" duration="22000" />
</task>
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="6809000" />
</component>
<component name="ToolWindowManager">
<frame x="-9" y="-9" width="1938" height="1048" extended-state="6" />
<editor active="true" />
<layout>
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.1834038" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.8074745" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="processedProjectFiles" value="true" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager />
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/RedBlack.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/RedBlack.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/RedBlack.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/Algorithm.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="283">
<caret line="95" column="9" lean-forward="false" selection-start-line="95" selection-start-column="9" selection-end-line="95" selection-end-column="9" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/about.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="116">
<caret line="4" column="23" lean-forward="false" selection-start-line="4" selection-start-column="23" selection-end-line="4" selection-end-column="23" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/Algorithms.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="319">
<caret line="11" column="18" lean-forward="false" selection-start-line="11" selection-start-column="18" selection-end-line="11" selection-end-column="18" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/BTree.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="174">
<caret line="6" column="16" lean-forward="false" selection-start-line="6" selection-start-column="16" selection-end-line="6" selection-end-column="16" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/visualizationPageStyle.css">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="355">
<caret line="106" column="0" lean-forward="true" selection-start-line="0" selection-start-column="0" selection-end-line="120" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/source.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="29">
<caret line="897" column="0" lean-forward="false" selection-start-line="897" selection-start-column="0" selection-end-line="1021" selection-end-column="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AVLtree.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="406">
<caret line="14" column="32" lean-forward="true" selection-start-line="14" selection-start-column="32" selection-end-line="14" selection-end-column="32" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/BTree.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="311">
<caret line="122" column="60" lean-forward="false" selection-start-line="122" selection-start-column="49" selection-end-line="122" selection-end-column="60" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/ClosedHash.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-1612">
<caret line="297" column="55" lean-forward="true" selection-start-line="297" selection-start-column="48" selection-end-line="297" selection-end-column="55" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/TST.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="302">
<caret line="502" column="17" lean-forward="false" selection-start-line="502" selection-start-column="17" selection-end-line="502" selection-end-column="26" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/RadixTree.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="186">
<caret line="402" column="9" lean-forward="true" selection-start-line="402" selection-start-column="9" selection-end-line="402" selection-end-column="9" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/Trie.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="167">
<caret line="327" column="0" lean-forward="true" selection-start-line="327" selection-start-column="0" selection-end-line="327" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/AVL.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="46">
<caret line="243" column="53" lean-forward="false" selection-start-line="243" selection-start-column="53" selection-end-line="243" selection-end-column="53" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/BST.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="32">
<caret line="215" column="49" lean-forward="false" selection-start-line="215" selection-start-column="49" selection-end-line="215" selection-end-column="49" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/SplayTree.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="80">
<caret line="326" column="49" lean-forward="false" selection-start-line="326" selection-start-column="49" selection-end-line="326" selection-end-column="49" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/RedBlack.ps" />
<entry file="file://$PROJECT_DIR$/AnimationLibrary/AnimationMain.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="341">
<caret line="85" column="18" lean-forward="true" selection-start-line="85" selection-start-column="18" selection-end-line="85" selection-end-column="18" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/AlgorithmLibrary/RedBlack.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="29">
<caret line="1263" column="45" lean-forward="false" selection-start-line="1263" selection-start-column="33" selection-end-line="1263" selection-end-column="45" />
<folding />
</state>
</provider>
</entry>
</component>
</project>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
AVL Tree Visualzation
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/AVL.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>AVL Tree</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>

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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;
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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], "<deleted>");
}
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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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], "<deleted>");
}
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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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 <this.size; j++)
{
var tmp = this.adj_matrix[i][j];
this.adj_matrix[i][j] = this.adj_matrix[j][i];
this.adj_matrix[j][i] = tmp;
}
}
}
ConnectedComponent.prototype.doCC = function(ignored)
{
this.visited = new Array(this.size);
this.commands = 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();
this.messageID = new Array();
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, 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);
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);
}
}
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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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 <functs.length; j++)
{
var func = functs[j];
func(event);
}
}
}
}
function Source()
{
}
Source.prototype = new EventListener();
Source.prototype.constructor = Source;
Source.prototype.testFire = function()
{
this.fireEvent("test","testcontents");
this.fireEvent("test2","test2contents");
}
function Client(eventSource)
{
this.first = function(blah)
{
alert("first:" + blah);
}
this.second = function(blah)
{
alert("second:" + blah);
}
eventSource.addListener("test", this, this.first);
eventSource.addListener("test", this, this.first);
eventSource.addListener("test", this, this.second);
if (this.first == this.first)
{
alert("same");
}
else
{
alert("different");
}
/*eventSource.addListener("test2", this.first.bind());
eventSource.addListener("test2", this.second.bind());
eventSource.addListener("test2", this.second.bind()); */
}
function init()
{
var src = new Source;
var c = new Client(src);
src.testFire();
}

查看文件

@ -0,0 +1,878 @@
// 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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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;
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}
*/

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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 <ARRAY_SIZE; i++)
{
this.arrayData[i] = this.normalizeNumber(String(ARRAY_SIZE - i), 4);
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;
}
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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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;
}
}
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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;
}

查看文件

@ -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;
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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;
}
}
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -0,0 +1,161 @@
<html lang="zh">
<head>
<link rel="stylesheet" href="visualPages.css">
<title> Data Structure Visualization </title><meta charset="UTF-8">
<link rel="shortcut icon" href="favicon.ico" />
</head>
<body>
<div class="container">
<div class="header"><h1>Data Structure Visualizations</h1> </div>
<div class="menu">
<ul>
<li> <a href="about.html">About</a> </li>
<li> <a href="Algorithms.html">Algorithms</a> </li>
<li> <a href="faq.html"> F.A.Q </a> </li>
<li> <a href="bugfeature.html"> Known Bugs /<br> &nbsp; &nbsp; Feature Requests </a> </li>
<li> <a href="java/visualization.html"> Java Version </a> </li>
<li> <a href="flash.html">Flash Version </a> </li>
<li> <a href="source.html">Create Your Own /<br> &nbsp; &nbsp; Source Code</a> </li>
<li> <a href="contact.html"> Contact </a> </li>
</ul>
<br> <br>
<div class="about">
<a href="http://www.cs.usfca.edu/galles"> David Galles </a> <br>
<a href="http://www.cs.usfca.edu"> Computer Science </a> <br>
<a href="http://www.usfca.edu"> University of San Francisco </a>
</div>
</div>
<div class="content">
Currently, we have visualizations for the following data structures
and algorithms:
<ul>
<li> Basics </li>
<ul>
<li> <a href = "StackArray.html">Stack: Array Implementation</a> </li>
<li><a href = "StackLL.html">Stack: Linked List Implementation</a> </li>
<li> <a href = "QueueArray.html">Queues: Array Implementation</a> </li>
<li> <a href = "QueueLL.html">Queues: Linked List Implementation</a> </li>
<li> Lists: Array Implementation (available in <a href = "java/visualization.html">java</a> version)</li>
<li> Lists: Linked List Implementation (available in <a href = "java/visualization.html">java</a> version) </li>
</ul>
<li> Recursion </li>
<ul>
<li> <a href = "RecFact.html">Factorial</a> </li>
<li><a href = "RecReverse.html">Reversing a String</a> </li>
<li><a href = "RecQueens.html">N-Queens Problem</a> </li>
</ul>
<li> Indexing </li>
<ul>
<li> <a href = "Search.html">Binary and Linear Search (of sorted list)</a> </li>
<li> <a href = "BST.html">Binary Search Trees</a> </li>
<li> <a href = "AVLtree.html">AVL Trees (Balanced binary search trees)</a> </li>
<li> <a href = "RedBlack.html">Red-Black Trees</a> </li>
<li> <a href = "SplayTree.html">Splay Trees</a> </li>
<li> <a href = "OpenHash.html">Open Hash Tables (Closed Addressing)</a> </li>
<li> <a href = "ClosedHash.html">Closed Hash Tables (Open Addressing)</a> </li>
<li> <a href = "ClosedHashBucket.html">Closed Hash Tables, using buckets</a> </li>
<li> <a href = "Trie.html">Trie (Prefix Tree, 26-ary Tree)</a> </li>
<li> <a href = "RadixTree.html">Radix Tree (Compact Trie)</a> </li>
<li> <a href = "TST.html">Ternary Search Tree (Trie with BST of children)</a> </li>
<li> <a href = "BTree.html">B Trees</a></li>
<li> <a href = "BPlusTree.html">B+ Trees</a></li>
</ul>
<li> Sorting </li>
<ul>
<li> <a href = "ComparisonSort.html">Comparison Sorting</a>
<ul>
<li> Bubble Sort </li>
<li> Selection Sort </li>
<li> Insertion Sort</li>
<li> Shell Sort </li>
<li> Merge Sort </li>
<li> Quck Sort </li>
</ul>
</li>
<li> <a href = "BucketSort.html">Bucket Sort</a> </li>
<li> <a href = "CountingSort.html">Counting Sort</a> </li>
<li> <a href = "RadixSort.html">Radix Sort</a> </li>
<li> <a href = "HeapSort.html">Heap Sort</a> </li>
</ul>
<li> Heap-like Data Structures </li>
<ul>
<li> <a href = "Heap.html">Heaps</a> </li>
<li> <a href = "BinomialQueue.html">Binomial Queues</a> </li>
<li> <a href = "FibonacciHeap.html">Fibonacci Heaps</a> </li>
<li> <a href = "LeftistHeap.html">Leftist Heaps</a> </li>
<li> <a href = "SkewHeap.html">Skew Heaps</a> </li>
</ul>
<li> Graph Algorithms </li>
<ul>
<li> <a href = "BFS.html">Breadth-First Search</a> </li>
<li> <a href = "DFS.html">Depth-First Search</a> </li>
<li> <a href = "ConnectedComponent.html">Connected Components</a> </li>
<li> <a href = "Dijkstra.html">Dijkstra's Shortest Path</a> </li>
<li> <a href = "Prim.html">Prim's Minimum Cost Spanning Tree</a> </li>
<li> <a href = "TopoSortIndegree.html">Topological Sort (Using Indegree array) </a> </li>
<li> <a href = "TopoSortDFS.html">Topological Sort (Using DFS) </a> </li>
<li> <a href = "Floyd.html">Floyd-Warshall (all pairs shortest paths)</a> </li>
<li> <a href = "Kruskal.html">Kruskal Minimum Cost Spanning Tree Algorithm</a></li>
</ul>
<li> Dynamic Programming </li>
<ul>
<li> <a href = "DPFib.html">Calculating nth Fibonacci number</a></li>
<li> <a href = "DPChange.html">Making Change</a></li>
<li> <a href = "DPLCS.html">Longest Common Subsequence</a></li>
</ul>
<li> Geometric Algorithms</li>
<!-- <li> B-Trees -->
<ul>
<li> <a href = "RotateScale2D.html">2D Rotation and Scale Matrices</a> </li>
<li> <a href = "RotateTranslate2D.html">2D Rotation and Translation Matrices</a> </li>
<li> <a href = "ChangingCoordinates2D.html">2D Changing Coordinate Systems</a> </li>
<li> <a href = "RotateScale3D.html">3D Rotation and Scale Matrices</a> </li>
<li> <a href = "ChangingCoordinates3D.html">3D Changing Coordinate Systems</a> </li>
</ul>
<li> Others ... </li>
<!-- <li> B-Trees -->
<ul>
<li> <a href = "DisjointSets.html">Disjoint Sets</a> </li>
<li> Huffman Coding (available in <a href = "java/visualization.html">java</a> version) </li>
</ul>
</ul>
</div>
<div class="footer">Copyright 2011 <a href = "http://www.cs.usfca.edu/galles">David Galles </a> </div>
</div>
</body>
</html>

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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;
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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 <functs.length; j++)
{
var func = functs[j];
func.call(scope,event);
}
}
}
}
/*
function Source()
{
}
Source.prototype = new EventListener();
Source.prototype.constructor = Source;
Source.prototype.testFire = function()
{
this.fireEvent("test","testcontents");
this.fireEvent("test2","test2contents");
}
function Client(eventSource)
{
this.first = function(blah)
{
alert("first:" + blah);
}
this.second = function(blah)
{
alert("second:" + blah);
}
eventSource.addListener("test", this, this.first);
eventSource.addListener("test", this, this.first);
eventSource.addListener("test", this, this.second);
eventSource.removeListener("test", this, this.first);
}
function init()
{
var src = new Source;
var c = new Client(src);
src.testFire();
}
*/

查看文件

@ -0,0 +1,87 @@
// 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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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)
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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;
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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 <this.Nodes.length; i++)
{
if (this.Nodes[i] != null && this.Nodes[i] != undefined)
{
this.Nodes[i].addedToScene = this.activeLayers[this.Nodes[i].layer] == true;
}
}
for (i = this.Edges.length - 1; 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)
}*/
}
}

查看文件

@ -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 <COPYRIGHT HOLDER> ``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 <COPYRIGHT HOLDER> 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);
}

查看文件

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Breadth-First Search
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Graph.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/BFS.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Breadth-First Search</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>

查看文件

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
B+ Tree Visualization
</title><meta charset="UTF-8">
<!-- 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/AnimatedBTreeNode.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 = "AlgorithmLibrary/BPlusTree.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>B<sup>+</sup> Trees</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>

查看文件

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Binary Search Tree Visualization
</title><meta charset="UTF-8">
<!-- 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 = "application/javascript" src = "AnimationLibrary/CustomEvents.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/UndoFunctions.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/AnimatedObject.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/AnimatedLabel.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/AnimatedCircle.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/AnimatedRectangle.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/AnimatedLinkedList.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/HighlightCircle.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/Line.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/ObjectManager.js"> </script>
<script type = "application/javascript" src = "AnimationLibrary/AnimationMain.js"> </script>
<script type = "application/javascript" src = "AlgorithmLibrary/Algorithm.js"> </script>
<script type = "application/javascript" src = "AlgorithmLibrary/BST.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Binary Search Tree</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>

查看文件

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
B-Tree Visualization
</title>
<meta charset="UTF-8">
<!-- 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/AnimatedBTreeNode.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 = "AlgorithmLibrary/BTree.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>B-Trees</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Binomial Queue Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/BinomialQueue.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Binomial Queue</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>

查看文件

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Bucket Sort Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/BucketSort.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Bucket Sort</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Changing Coordinate Spaces Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/ChangingCoordinate2D.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Changing Coordinate Spaces</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Changing Coordinate Spaces (3D) Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/ChangingCoordinate3D.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Changing Coordinate Spaces (3D)</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>

查看文件

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Closed Hashing Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Hash.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/ClosedHash.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Closed Hashing</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>

查看文件

@ -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], "<deleted>");
}
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);
}

查看文件

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Closed Hashing (Buckets) Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Hash.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/ClosedHashBucket.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Closed Hashing, Using Buckets</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>

查看文件

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Comparison Sorting Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/ComparisonSort.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Comparison Sorting Algorithms</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>

查看文件

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Connected Component Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Graph.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/ConnectedComponent.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Connected Components</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>

查看文件

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Counting Sort Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/CountingSort.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Counting Sort</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>
<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>
<!-- Drawing canvas where all animation is done. Note: can be resized in code -->
<canvas id="canvas" width="1000" height="500"></canvas>
</div> <!-- mainContent -->
<div id="footer">
<p><a href="Algorithms.html">首页</a></p>
</div>
</div><!-- container -->
</body>
</html>

查看文件

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Depth-First Search Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Graph.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/DFS.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Depth-First Search</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Dynamic Programming (Making Change)
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/DPChange.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Dynamic Programming (Making Change)</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Dynamic Programming (Fibonacci)
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/DPFib.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Dynamic Programming (Fibonacci)</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Dynamic Programming (Longest Common Subsequence)
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/DPLCS.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Dynamic Programming (Longest Common Subsequence)</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>

查看文件

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Dijkstra Visualzation
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Graph.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/DijkstraPrim.js"> </script>
</head>
<body onload="init(true);" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Dijkstra Shortest Path</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Disjoint Sets Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/DisjointSet.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Disjoint Sets</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Fibonacci Heap Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/FibonacciHeap.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Fibonacci Heap</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>

查看文件

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Floyd-Warshall All-Pairs Shortest Path
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Graph.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/Floyd.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Floyd-Warshall All-Pairs Shortest Path</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Heap Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Heap.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Min Heap</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>

查看文件

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Heap Sort Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/HeapSort.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Heap Sort</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>

查看文件

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Kruskal MST Visualzation
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/Graph.js"> </script>
<script type = "text/javascript" src = "AlgorithmLibrary/Kruskal.js"> </script>
</head>
<body onload="init(false);" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Kruskal Minimum Cost Spanning Treeh</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>

查看文件

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>
Leftist Heap Visualization
</title><meta charset="UTF-8">
<!-- 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 = "AlgorithmLibrary/LeftistHeap.js"> </script>
</head>
<body onload="init();" class="VisualizationMainPage">
<div id = "container">
<div id="header">
<h1>Leftist Heap</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>

本差異變更的檔案數量過多導致部分檔案未顯示 顯示更多