adding hash table animations
This commit is contained in:
committed by
JamesFlare1212
parent
fea90f2b4d
commit
cc21696e46
18
animations/hash_tables/index.html
Normal file
18
animations/hash_tables/index.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Separate Chaining Based Hash Table</title>
|
||||||
|
<script src="../konva.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Separate Chaining Based Hash Table</h1>
|
||||||
|
<p>This is the animation of Separate Chaining Based Hash Table. Click the "next step" button to run the animation.</p>
|
||||||
|
|
||||||
|
<button onclick="nextstep()">next step</button>
|
||||||
|
|
||||||
|
<div id="container"></div>
|
||||||
|
<script src="main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
659
animations/hash_tables/main.js
Normal file
659
animations/hash_tables/main.js
Normal file
@@ -0,0 +1,659 @@
|
|||||||
|
// Author: Xi Chen
|
||||||
|
// first we need to create a stage
|
||||||
|
var stage = new Konva.Stage({
|
||||||
|
container: 'container', // id of container <div>
|
||||||
|
width: 2000,
|
||||||
|
height: 1000
|
||||||
|
});
|
||||||
|
|
||||||
|
// then create layer
|
||||||
|
var layer = new Konva.Layer();
|
||||||
|
|
||||||
|
function makeMemory(xstart, ystart, bufferSize, w, h)
|
||||||
|
{
|
||||||
|
for (let i = 0; i < bufferSize; ++i)
|
||||||
|
{
|
||||||
|
let tr = new Konva.Rect
|
||||||
|
({
|
||||||
|
x: xstart,
|
||||||
|
y: ystart+i*h,
|
||||||
|
id:"brec"+i,
|
||||||
|
stroke: '#343434',
|
||||||
|
strokeWidth: 5,
|
||||||
|
fill: '#ddd',
|
||||||
|
width: w,
|
||||||
|
height: h,
|
||||||
|
shadowColor: 'black',
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetX: 10,
|
||||||
|
shadowOffsetY: 10,
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(tr);
|
||||||
|
|
||||||
|
// Add index number to the left of each box
|
||||||
|
let indexText = new Konva.Text
|
||||||
|
({
|
||||||
|
x: xstart - 30, // Position to the left of the box
|
||||||
|
y: ystart + i*h + h/2 - 10, // Center vertically
|
||||||
|
text: i.toString(),
|
||||||
|
fontSize: 18,
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fill: '#000000',
|
||||||
|
align: 'center',
|
||||||
|
width: 30,
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(indexText);
|
||||||
|
} // end of for loop
|
||||||
|
}
|
||||||
|
|
||||||
|
makeMemory(1650,60,10,50,50);
|
||||||
|
|
||||||
|
var memoryText = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 1625,
|
||||||
|
y: 25,
|
||||||
|
id:"memory",
|
||||||
|
text: "Memory",
|
||||||
|
fontSize: 28,
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fill: '#000000',
|
||||||
|
});
|
||||||
|
|
||||||
|
var mainLabel = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 400,
|
||||||
|
y: 0,
|
||||||
|
id:"main",
|
||||||
|
text: "Main",
|
||||||
|
fontSize: 28,
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fill: '#000000',
|
||||||
|
});
|
||||||
|
|
||||||
|
// box for code
|
||||||
|
layer.add(memoryText);
|
||||||
|
layer.add(mainLabel);
|
||||||
|
|
||||||
|
// add the layer to the stage
|
||||||
|
stage.add(layer);
|
||||||
|
|
||||||
|
// draw the image
|
||||||
|
layer.draw();
|
||||||
|
|
||||||
|
const steps =
|
||||||
|
[
|
||||||
|
// Initialize phonebook
|
||||||
|
{mainHighlight: [1], funcHighlight: [], action: null, console: "Initializing phonebook array with size 10"},
|
||||||
|
|
||||||
|
// Add dan
|
||||||
|
{mainHighlight: [2], funcHighlight: [], action: null, console: "Adding entry: dan (5182764321)"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [13], action: null, console: "Entering add function"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [14], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [2], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [11], action: null, console: "5182764321 % 10 = 1"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [14], action: null, console: "Hash index: 1"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [15], action: null, console: "Creating new node"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [16], action: null, console: "Setting name: dan"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [17], action: null, console: "Setting number: 5182764321"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [18], action: null, console: "Setting next pointer"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [19], action: {type: 'add', index: 1, name: 'dan', number: '5182764321'}, console: "Adding node to index 1"},
|
||||||
|
{mainHighlight: [2], funcHighlight: [20], action: null, console: "Returning from add function"},
|
||||||
|
|
||||||
|
// Add fred
|
||||||
|
{mainHighlight: [3], funcHighlight: [], action: null, console: "Adding entry: fred (6173551212)"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [13], action: null, console: "Entering add function"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [14], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [3], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [11], action: null, console: "6173551212 % 10 = 2"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [14], action: null, console: "Hash index: 2"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [15], action: null, console: "Creating new node"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [16], action: null, console: "Setting name: fred"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [17], action: null, console: "Setting number: 6173551212"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [18], action: null, console: "Setting next pointer"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [19], action: {type: 'add', index: 2, name: 'fred', number: '6173551212'}, console: "Adding node to index 2"},
|
||||||
|
{mainHighlight: [3], funcHighlight: [20], action: null, console: "Returning from add function"},
|
||||||
|
|
||||||
|
// Add alice
|
||||||
|
{mainHighlight: [4], funcHighlight: [], action: null, console: "Adding entry: alice (5182761234)"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [13], action: null, console: "Entering add function"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [14], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [4], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [11], action: null, console: "5182761234 % 10 = 4"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [14], action: null, console: "Hash index: 4"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [15], action: null, console: "Creating new node"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [16], action: null, console: "Setting name: alice"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [17], action: null, console: "Setting number: 5182761234"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [18], action: null, console: "Setting next pointer"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [19], action: {type: 'add', index: 4, name: 'alice', number: '5182761234'}, console: "Adding node to index 4"},
|
||||||
|
{mainHighlight: [4], funcHighlight: [20], action: null, console: "Returning from add function"},
|
||||||
|
|
||||||
|
// Add carol
|
||||||
|
{mainHighlight: [5], funcHighlight: [], action: null, console: "Adding entry: carol (5182761267)"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [13], action: null, console: "Entering add function"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [14], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [5], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [11], action: null, console: "5182761267 % 10 = 7"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [14], action: null, console: "Hash index: 7"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [15], action: null, console: "Creating new node"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [16], action: null, console: "Setting name: carol"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [17], action: null, console: "Setting number: 5182761267"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [18], action: null, console: "Setting next pointer"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [19], action: {type: 'add', index: 7, name: 'carol', number: '5182761267'}, console: "Adding node to index 7"},
|
||||||
|
{mainHighlight: [5], funcHighlight: [20], action: null, console: "Returning from add function"},
|
||||||
|
|
||||||
|
// Add bob
|
||||||
|
{mainHighlight: [6], funcHighlight: [], action: null, console: "Adding entry: bob (5182765678)"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [13], action: null, console: "Entering add function"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [14], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [6], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [11], action: null, console: "5182765678 % 10 = 8"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [14], action: null, console: "Hash index: 8"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [15], action: null, console: "Creating new node"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [16], action: null, console: "Setting name: bob"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [17], action: null, console: "Setting number: 5182765678"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [18], action: null, console: "Setting next pointer"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [19], action: {type: 'add', index: 8, name: 'bob', number: '5182765678'}, console: "Adding node to index 8"},
|
||||||
|
{mainHighlight: [6], funcHighlight: [20], action: null, console: "Returning from add function"},
|
||||||
|
|
||||||
|
// Add erin
|
||||||
|
{mainHighlight: [7], funcHighlight: [], action: null, console: "Adding entry: erin (5182764488)"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [13], action: null, console: "Entering add function"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [14], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [7], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [11], action: null, console: "5182764488 % 10 = 8"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [14], action: null, console: "Hash index: 8"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [15], action: null, console: "Creating new node"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [16], action: null, console: "Setting name: erin"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [17], action: null, console: "Setting number: 5182764488"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [18], action: null, console: "Setting next pointer"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [19], action: {type: 'add', index: 8, name: 'erin', number: '5182764488', chain: true}, console: "Adding node to index 8 (chaining)"},
|
||||||
|
{mainHighlight: [7], funcHighlight: [20], action: null, console: "Returning from add function"},
|
||||||
|
|
||||||
|
// Identify dan
|
||||||
|
{mainHighlight: [8], funcHighlight: [], action: null, console: "Searching for number: 5182764321"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [21], action: null, console: "Entering identify function"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [22], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [8], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [11], action: null, console: "5182764321 % 10 = 1"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [22], action: null, console: "Hash index: 1"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [23], action: null, console: "Starting search at index 1"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [24], action: null, console: "phonebook[1] is not nullptr(true)"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [25], action: null, console: "5182764321 == 5182764321(true)"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [26], action: null, console: "Returning: dan"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [31], action: null, console: "Returning from identify function"},
|
||||||
|
{mainHighlight: [8], funcHighlight: [], action: null, console: "Identify 5182764321: dan"},
|
||||||
|
|
||||||
|
// Identify erin
|
||||||
|
{mainHighlight: [9], funcHighlight: [], action: null, console: "Searching for number: 5182764488"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [21], action: null, console: "Entering identify function"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [22], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [9], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [11], action: null, console: "5182764488 % 10 = 8"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [22], action: null, console: "Hash index: 8"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [23], action: null, console: "Starting search at index 8"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [24], action: null, console: "phonebook[8] is not nullptr(true)"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [25], action: null, console: "5182765678 != 5182764488(false)"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [28], action: null, console: "Moving to next node"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [24], action: null, console: "phonebook[8]->next is not nullptr(true)"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [25], action: null, console: "5182764488 == 5182764488(true)"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [26], action: null, console: "Returning: erin"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [31], action: null, console: "Returning from identify function"},
|
||||||
|
{mainHighlight: [9], funcHighlight: [], action: null, console: "Identify 5182764488: erin"},
|
||||||
|
|
||||||
|
// Identify fred
|
||||||
|
{mainHighlight: [10], funcHighlight: [], action: null, console: "Searching for number: 6173551212"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [21], action: null, console: "Entering identify function"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [22], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [10], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [11], action: null, console: "6173551212 % 10 = 2"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [22], action: null, console: "Hash index: 2"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [23], action: null, console: "Starting search at index 2"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [24], action: null, console: "phonebook[2] is not nullptr(true)"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [25], action: null, console: "6173551212 == 6173551212(true)"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [26], action: null, console: "Returning: fred"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [31], action: null, console: "Returning from identify function"},
|
||||||
|
{mainHighlight: [10], funcHighlight: [], action: null, console: "Identify 6173551212: fred"},
|
||||||
|
|
||||||
|
// Identify not found
|
||||||
|
{mainHighlight: [11], funcHighlight: [], action: null, console: "Searching for number: 1234567890"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [21], action: null, console: "Entering identify function"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [22], action: null, console: "Calculating hash index..."},
|
||||||
|
{mainHighlight: [11], funcHighlight: [10], action: null, console: "Entering hash_function"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [11], action: null, console: "1234567890 % 10 = 0"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [22], action: null, console: "Hash index: 0"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [23], action: null, console: "Starting search at index 0"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [24], action: null, console: "phonebook[0] is not nullptr(false)"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [30], action: null, console: "Returning: Not found"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [31], action: null, console: "Returning from identify function"},
|
||||||
|
{mainHighlight: [11], funcHighlight: [], action: null, console: "Identify 1234567890: Not found"},
|
||||||
|
|
||||||
|
// Return 0
|
||||||
|
{mainHighlight: [12], funcHighlight: [], action: null, console: "Program completed"}
|
||||||
|
];
|
||||||
|
|
||||||
|
function highlightCodeLines(mainLines, funcLines)
|
||||||
|
{
|
||||||
|
for (let i = 0; i < mainCodeTextNodes.length; ++i)
|
||||||
|
{
|
||||||
|
if (mainLines.includes(i))
|
||||||
|
{
|
||||||
|
mainCodeTextNodes[i].fontStyle('normal');
|
||||||
|
mainCodeTextNodes[i].fill('#FF0000'); // Bright red for current line
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mainCodeTextNodes[i].fontStyle('normal');
|
||||||
|
mainCodeTextNodes[i].fill('#222');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < funcCodeTextNodes.length; ++i)
|
||||||
|
{
|
||||||
|
if (funcLines.includes(i))
|
||||||
|
{
|
||||||
|
funcCodeTextNodes[i].fontStyle('normal');
|
||||||
|
funcCodeTextNodes[i].fill('#FF0000'); // Bright red for current line
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
funcCodeTextNodes[i].fontStyle('normal');
|
||||||
|
funcCodeTextNodes[i].fill('#222');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
let stepIndex = 0;
|
||||||
|
|
||||||
|
function nextstep()
|
||||||
|
{
|
||||||
|
if (stepIndex >= steps.length)
|
||||||
|
{
|
||||||
|
alert('End of animation! Refresh to restart.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let step = steps[stepIndex];
|
||||||
|
highlightCodeLines(step.mainHighlight, step.funcHighlight);
|
||||||
|
|
||||||
|
// Perform the action first
|
||||||
|
if (step.action && step.action.type === 'add')
|
||||||
|
{
|
||||||
|
addNodeToMemory(step.action.index, step.action.name, step.action.number, step.action.chain);
|
||||||
|
// Then show the console message
|
||||||
|
if (step.console)
|
||||||
|
{
|
||||||
|
addConsoleText(step.console);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.draw();
|
||||||
|
++stepIndex;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (step.action && step.action.type === 'identify')
|
||||||
|
{
|
||||||
|
highlightIdentifyPath(step.action.index, step.action.path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No action, just show console message
|
||||||
|
if (step.console)
|
||||||
|
{
|
||||||
|
addConsoleText(step.console);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.draw();
|
||||||
|
++stepIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.nextstep = nextstep;
|
||||||
|
|
||||||
|
function highlightNext(index, path, i)
|
||||||
|
{
|
||||||
|
if (i < path.length)
|
||||||
|
{
|
||||||
|
let obj = memoryNodes[index][path[i]];
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
obj.group.children.each(child => {
|
||||||
|
if (child instanceof Konva.Rect)
|
||||||
|
{
|
||||||
|
child.stroke('#FF0000'); // red for current
|
||||||
|
child.strokeWidth(5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.draw();
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if (i < path.length)
|
||||||
|
{
|
||||||
|
setTimeout(() => highlightNext(index, path, i), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightIdentifyPath(index, path)
|
||||||
|
{
|
||||||
|
// Remove previous highlights
|
||||||
|
for (let idx in memoryNodes)
|
||||||
|
{
|
||||||
|
memoryNodes[idx].forEach(obj => {
|
||||||
|
obj.group.children.each(child => {
|
||||||
|
if (child instanceof Konva.Rect)
|
||||||
|
{
|
||||||
|
child.stroke('#222');
|
||||||
|
child.strokeWidth(2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memoryNodes[index]) return;
|
||||||
|
|
||||||
|
// Start the animation
|
||||||
|
highlightNext(index, path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main Code Box (left) ---
|
||||||
|
const mainCodeLines =
|
||||||
|
[
|
||||||
|
'int main(){',
|
||||||
|
' Node *phonebook[PHONEBOOK_SIZE] = {nullptr};',
|
||||||
|
' add(phonebook, 5182764321, "dan");',
|
||||||
|
' add(phonebook, 6173551212, "fred");',
|
||||||
|
' add(phonebook, 5182761234, "alice");',
|
||||||
|
' add(phonebook, 5182761267, "carol");',
|
||||||
|
' add(phonebook, 5182765678, "bob");',
|
||||||
|
' add(phonebook, 5182764488, "erin");',
|
||||||
|
' std::cout << "Identify 5182764321: " << identify(phonebook, 5182764321) << std::endl;',
|
||||||
|
' std::cout << "Identify 5182764488: " << identify(phonebook, 5182764488) << std::endl;',
|
||||||
|
' std::cout << "Identify 6173551212: " << identify(phonebook, 6173551212) << std::endl;',
|
||||||
|
' std::cout << "Identify 1234567890: " << identify(phonebook, 1234567890) << std::endl;',
|
||||||
|
' return 0;',
|
||||||
|
'}'
|
||||||
|
];
|
||||||
|
|
||||||
|
// --- Function Code Box (center) ---
|
||||||
|
const funcCodeLines =
|
||||||
|
[
|
||||||
|
'#include <iostream>',
|
||||||
|
'#include <string>',
|
||||||
|
'const int PHONEBOOK_SIZE = 10;',
|
||||||
|
'struct Node{',
|
||||||
|
'public:',
|
||||||
|
' int number;',
|
||||||
|
' std::string name;',
|
||||||
|
' Node *next;',
|
||||||
|
' Node() : name(""), number(0), next(nullptr) {}',
|
||||||
|
'};',
|
||||||
|
'int hash_function(int number){',
|
||||||
|
' return number % PHONEBOOK_SIZE;',
|
||||||
|
'}',
|
||||||
|
'void add(Node *phonebook[PHONEBOOK_SIZE], int number, const std::string &name){',
|
||||||
|
' int index = hash_function(number);',
|
||||||
|
' Node *tmp = new Node;',
|
||||||
|
' tmp->name = name;',
|
||||||
|
' tmp->number = number;',
|
||||||
|
' tmp->next = phonebook[index];',
|
||||||
|
' phonebook[index] = tmp;',
|
||||||
|
'}',
|
||||||
|
'std::string identify(Node *phonebook[PHONEBOOK_SIZE], int number){',
|
||||||
|
' int index = hash_function(number);',
|
||||||
|
' Node *curr = phonebook[index];',
|
||||||
|
' while (curr != nullptr){',
|
||||||
|
' if (curr->number == number){',
|
||||||
|
' return curr->name;',
|
||||||
|
' }',
|
||||||
|
' curr = curr->next;',
|
||||||
|
' }',
|
||||||
|
' return "Not found";',
|
||||||
|
'}'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Draw main code box (left)
|
||||||
|
var mainCodeBox = new Konva.Rect
|
||||||
|
({
|
||||||
|
x: 20,
|
||||||
|
y: 25,
|
||||||
|
width: 800,
|
||||||
|
height: mainCodeLines.length * 24 + 40,
|
||||||
|
fill: '#ddd',
|
||||||
|
stroke: '#555',
|
||||||
|
strokeWidth: 5,
|
||||||
|
shadowColor: 'black',
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetX: 10,
|
||||||
|
shadowOffsetY: 10,
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
cornerRadius: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(mainCodeBox);
|
||||||
|
|
||||||
|
// Draw console box under main code box
|
||||||
|
var consoleBox = new Konva.Rect
|
||||||
|
({
|
||||||
|
x: 20,
|
||||||
|
y: mainCodeBox.y() + mainCodeBox.height() + 40,
|
||||||
|
width: 800,
|
||||||
|
height: 100,
|
||||||
|
fill: '#ddd',
|
||||||
|
stroke: '#555',
|
||||||
|
strokeWidth: 5,
|
||||||
|
shadowColor: 'black',
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetX: 10,
|
||||||
|
shadowOffsetY: 10,
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
cornerRadius: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(consoleBox);
|
||||||
|
|
||||||
|
var consoleLabel = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 375,
|
||||||
|
y: consoleBox.y() - 25,
|
||||||
|
id: 'console',
|
||||||
|
text: 'Console',
|
||||||
|
fontSize: 28,
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fill: '#000000',
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(consoleLabel);
|
||||||
|
|
||||||
|
let consoleTextNode = null;
|
||||||
|
|
||||||
|
function addConsoleText(text)
|
||||||
|
{
|
||||||
|
if (consoleTextNode)
|
||||||
|
{
|
||||||
|
consoleTextNode.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
consoleTextNode = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 30,
|
||||||
|
y: consoleBox.y() + 30,
|
||||||
|
text: text,
|
||||||
|
id: 'console_line',
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Consolas',
|
||||||
|
fill: '#000000',
|
||||||
|
width: 785,
|
||||||
|
padding: 1,
|
||||||
|
wrap: 'none',
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(consoleTextNode);
|
||||||
|
layer.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mainCodeTextNodes = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < mainCodeLines.length; ++i)
|
||||||
|
{
|
||||||
|
let t = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 30,
|
||||||
|
y: 40 + i * 24,
|
||||||
|
text: mainCodeLines[i],
|
||||||
|
id: 'main_code_line_' + i,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Consolas',
|
||||||
|
fill: '#222',
|
||||||
|
width: 785,
|
||||||
|
padding: 1,
|
||||||
|
wrap: 'none',
|
||||||
|
});
|
||||||
|
|
||||||
|
mainCodeTextNodes.push(t);
|
||||||
|
layer.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function code box (center)
|
||||||
|
var funcCodeBox = new Konva.Rect
|
||||||
|
({
|
||||||
|
x: 850,
|
||||||
|
y: 25,
|
||||||
|
width: 750,
|
||||||
|
height: funcCodeLines.length * 24 + 30,
|
||||||
|
fill: '#ddd',
|
||||||
|
stroke: '#555',
|
||||||
|
strokeWidth: 5,
|
||||||
|
shadowColor: 'black',
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetX: 10,
|
||||||
|
shadowOffsetY: 10,
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
cornerRadius: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(funcCodeBox);
|
||||||
|
|
||||||
|
var funcCodeLabel = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 1175,
|
||||||
|
y: 0,
|
||||||
|
id: 'func_code',
|
||||||
|
text: 'Functions',
|
||||||
|
fontSize: 28,
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fill: '#000000',
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(funcCodeLabel);
|
||||||
|
|
||||||
|
let funcCodeTextNodes = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < funcCodeLines.length; ++i)
|
||||||
|
{
|
||||||
|
let t = new Konva.Text
|
||||||
|
({
|
||||||
|
x: 875,
|
||||||
|
y: 40 + i * 24,
|
||||||
|
text: funcCodeLines[i],
|
||||||
|
id: 'func_code_line_' + i,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Consolas',
|
||||||
|
fill: '#222',
|
||||||
|
width: 750,
|
||||||
|
padding: 1,
|
||||||
|
wrap: 'none',
|
||||||
|
});
|
||||||
|
|
||||||
|
funcCodeTextNodes.push(t);
|
||||||
|
layer.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
let memoryNodes = {};
|
||||||
|
|
||||||
|
function addNodeToMemory(index, name, number, chain = false)
|
||||||
|
{
|
||||||
|
if (!memoryNodes[index]) memoryNodes[index] = [];
|
||||||
|
let y = 60 + index * 50 + 10;
|
||||||
|
let x = 1725 + memoryNodes[index].length * 150;
|
||||||
|
|
||||||
|
// Draw node group (rectangle + text)
|
||||||
|
let group = new Konva.Group();
|
||||||
|
|
||||||
|
let nodeRect = new Konva.Rect
|
||||||
|
({
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: 100,
|
||||||
|
height: 30,
|
||||||
|
fill: '#fff',
|
||||||
|
stroke: '#222',
|
||||||
|
strokeWidth: 2,
|
||||||
|
cornerRadius: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
let numberText = new Konva.Text
|
||||||
|
({
|
||||||
|
x: x + 5,
|
||||||
|
y: y + 2,
|
||||||
|
text: number,
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Consolas',
|
||||||
|
fill: '#333',
|
||||||
|
});
|
||||||
|
|
||||||
|
let nameText = new Konva.Text
|
||||||
|
({
|
||||||
|
x: x + 5,
|
||||||
|
y: y + 15,
|
||||||
|
text: name,
|
||||||
|
fontSize: 15,
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fill: '#000',
|
||||||
|
fontStyle: 'bold',
|
||||||
|
});
|
||||||
|
|
||||||
|
group.add(nodeRect);
|
||||||
|
group.add(numberText);
|
||||||
|
group.add(nameText);
|
||||||
|
layer.add(group);
|
||||||
|
|
||||||
|
// Draw arrow from memory box or previous node
|
||||||
|
let arrow;
|
||||||
|
|
||||||
|
if (memoryNodes[index].length === 0)
|
||||||
|
{
|
||||||
|
arrow = new Konva.Arrow
|
||||||
|
({
|
||||||
|
points: [1700, y + 15, x, y + 15],
|
||||||
|
pointerLength: 10,
|
||||||
|
pointerWidth: 10,
|
||||||
|
fill: 'black',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let prevX = 1725 + (memoryNodes[index].length - 1) * 150 + 100;
|
||||||
|
|
||||||
|
arrow = new Konva.Arrow
|
||||||
|
({
|
||||||
|
points: [prevX, y + 15, x, y + 15],
|
||||||
|
pointerLength: 10,
|
||||||
|
pointerWidth: 10,
|
||||||
|
fill: 'black',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.add(arrow);
|
||||||
|
memoryNodes[index].push({group, arrow});
|
||||||
|
}
|
||||||
@@ -138,6 +138,8 @@ std::string identify(Node* phonebook[PHONEBOOK_SIZE], int number) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Play this [animation](https://jidongxiao.github.io/CSCI1200-DataStructures/animations/hash_tables/index.html) to understand how this works.
|
||||||
|
|
||||||
## 22.7 Exercise: Hash Table Performance
|
## 22.7 Exercise: Hash Table Performance
|
||||||
|
|
||||||
- What's the memory complexity for the hash-table-based Caller ID system?
|
- What's the memory complexity for the hash-table-based Caller ID system?
|
||||||
|
|||||||
Reference in New Issue
Block a user