updating morris
This commit is contained in:
committed by
JamesFlare1212
parent
3c88acac9f
commit
28243a596d
@@ -22,7 +22,7 @@
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
width: 48%;
|
width: 48%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 88vh;
|
height: 87vh;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +43,21 @@
|
|||||||
min-width: 30px;
|
min-width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.code-line {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-line.highlighted {
|
||||||
|
background-color: #ffeb3b;
|
||||||
|
}
|
||||||
|
|
||||||
.tree-container {
|
.tree-container {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
width: 48%;
|
width: 48%;
|
||||||
height: 88vh;
|
height: 80vh;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -134,56 +143,11 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Morris Post-Order Traversal Visualization</h1>
|
<h1>Morris Post-Order Traversal Visualization</h1>
|
||||||
<p>This animation shows how the Morris post-order traversal algorithm works without using a stack or recursion. Click the "Next Step" button to run the animation.</p>
|
<p>This animation shows how the Morris post-order traversal algorithm works without using a stack or recursion. Click the "Next Step" button to run the animation step by step.</p>
|
||||||
|
|
||||||
<div class="visualization-container">
|
<div class="visualization-container">
|
||||||
<div class="code-container">
|
<div class="code-container">
|
||||||
<pre><code><span class="line-number">0.</span> <span style="color:blue">void</span> postorderTraversal(<span style="color:blue">TreeNode</span>* root) {
|
<pre><code id="codeDisplay"></code></pre>
|
||||||
<span class="line-number">1.</span> <span style="color:blue">TreeNode</span>* current = root;
|
|
||||||
<span class="line-number">2.</span> <span style="color:blue">TreeNode</span>* rightmost;
|
|
||||||
<span class="line-number">3.</span> <span style="color:blue">while</span> (current != <span style="color:blue">nullptr</span>) {
|
|
||||||
<span class="line-number">4.</span> <span style="color:blue">if</span> (current->left != <span style="color:blue">nullptr</span>) {
|
|
||||||
<span class="line-number">5.</span> rightmost = current->left;
|
|
||||||
<span class="line-number">6.</span> <span style="color:blue">while</span> (rightmost->right != <span style="color:blue">nullptr</span> && rightmost->right != current) {
|
|
||||||
<span class="line-number">7.</span> rightmost = rightmost->right;
|
|
||||||
<span class="line-number">8.</span> }
|
|
||||||
<span class="line-number">9.</span> <span style="color:blue">if</span> (rightmost->right == <span style="color:blue">nullptr</span>) {
|
|
||||||
<span class="line-number">10.</span> rightmost->right = current;
|
|
||||||
<span class="line-number">11.</span> current = current->left;
|
|
||||||
<span class="line-number">12.</span> } <span style="color:blue">else</span> {
|
|
||||||
<span class="line-number">13.</span> rightmost->right = <span style="color:blue">nullptr</span>;
|
|
||||||
<span class="line-number">14.</span> reverseTraverseRightEdge(current->left);
|
|
||||||
<span class="line-number">15.</span> current = current->right;
|
|
||||||
<span class="line-number">16.</span> }
|
|
||||||
<span class="line-number">17.</span> } <span style="color:blue">else</span> {
|
|
||||||
<span class="line-number">18.</span> current = current->right;
|
|
||||||
<span class="line-number">19.</span> }
|
|
||||||
<span class="line-number">20.</span> }
|
|
||||||
<span class="line-number">21.</span> reverseTraverseRightEdge(root); <span style="color:green">// final right edge</span>
|
|
||||||
<span class="line-number">22.</span> <span style="color:blue">return</span>;
|
|
||||||
<span class="line-number">23.</span> }
|
|
||||||
<span class="line-number">24.</span>
|
|
||||||
<span class="line-number">25.</span> <span style="color:blue">TreeNode</span>* reverse(<span style="color:blue">TreeNode</span>* head) {
|
|
||||||
<span class="line-number">26.</span> <span style="color:blue">TreeNode</span>* prev = <span style="color:blue">nullptr</span>;
|
|
||||||
<span class="line-number">27.</span> <span style="color:blue">TreeNode</span>* next = <span style="color:blue">nullptr</span>;
|
|
||||||
<span class="line-number">28.</span> <span style="color:blue">while</span> (head != <span style="color:blue">nullptr</span>) {
|
|
||||||
<span class="line-number">29.</span> next = head->right;
|
|
||||||
<span class="line-number">30.</span> head->right = prev;
|
|
||||||
<span class="line-number">31.</span> prev = head;
|
|
||||||
<span class="line-number">32.</span> head = next;
|
|
||||||
<span class="line-number">33.</span> }
|
|
||||||
<span class="line-number">34.</span> <span style="color:blue">return</span> prev;
|
|
||||||
<span class="line-number">35.</span> }
|
|
||||||
<span class="line-number">36.</span>
|
|
||||||
<span class="line-number">37.</span> <span style="color:blue">void</span> reverseTraverseRightEdge(<span style="color:blue">TreeNode</span>* head) {
|
|
||||||
<span class="line-number">38.</span> <span style="color:blue">TreeNode</span>* tail = reverse(head);
|
|
||||||
<span class="line-number">39.</span> <span style="color:blue">TreeNode</span>* current = tail;
|
|
||||||
<span class="line-number">40.</span> <span style="color:blue">while</span> (current != <span style="color:blue">nullptr</span>) {
|
|
||||||
<span class="line-number">41.</span> std::cout << current->val << " ";
|
|
||||||
<span class="line-number">42.</span> current = current->right;
|
|
||||||
<span class="line-number">43.</span> }
|
|
||||||
<span class="line-number">44.</span> reverse(tail); <span style="color:green">// restore structure</span>
|
|
||||||
<span class="line-number">45.</span> }</code></pre>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tree-container">
|
<div class="tree-container">
|
||||||
<div class="color-key">
|
<div class="color-key">
|
||||||
@@ -227,6 +191,88 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Define code content
|
||||||
|
const codeContent = [
|
||||||
|
'<span class="line-number">0.</span> <span style="color:blue">void</span> postorderTraversal(<span style="color:blue">TreeNode</span>* root) {',
|
||||||
|
'<span class="line-number">1.</span> <span style="color:blue">TreeNode</span>* current = root;',
|
||||||
|
'<span class="line-number">2.</span> <span style="color:blue">TreeNode</span>* rightmost;',
|
||||||
|
'<span class="line-number">3.</span> <span style="color:blue">while</span> (current != <span style="color:blue">nullptr</span>) {',
|
||||||
|
'<span class="line-number">4.</span> <span style="color:blue">if</span> (current->left != <span style="color:blue">nullptr</span>) {',
|
||||||
|
'<span class="line-number">5.</span> rightmost = current->left;',
|
||||||
|
'<span class="line-number">6.</span> <span style="color:blue">while</span> (rightmost->right != <span style="color:blue">nullptr</span> && rightmost->right != current) {',
|
||||||
|
'<span class="line-number">7.</span> rightmost = rightmost->right;',
|
||||||
|
'<span class="line-number">8.</span> }',
|
||||||
|
'<span class="line-number">9.</span> <span style="color:blue">if</span> (rightmost->right == <span style="color:blue">nullptr</span>) {',
|
||||||
|
'<span class="line-number">10.</span> rightmost->right = current;',
|
||||||
|
'<span class="line-number">11.</span> current = current->left;',
|
||||||
|
'<span class="line-number">12.</span> } <span style="color:blue">else</span> {',
|
||||||
|
'<span class="line-number">13.</span> rightmost->right = <span style="color:blue">nullptr</span>;',
|
||||||
|
'<span class="line-number">14.</span> reverseTraverseRightEdge(current->left);',
|
||||||
|
'<span class="line-number">15.</span> current = current->right;',
|
||||||
|
'<span class="line-number">16.</span> }',
|
||||||
|
'<span class="line-number">17.</span> } <span style="color:blue">else</span> {',
|
||||||
|
'<span class="line-number">18.</span> current = current->right;',
|
||||||
|
'<span class="line-number">19.</span> }',
|
||||||
|
'<span class="line-number">20.</span> }',
|
||||||
|
'<span class="line-number">21.</span> reverseTraverseRightEdge(root); <span style="color:green">// final right edge</span>',
|
||||||
|
'<span class="line-number">22.</span> <span style="color:blue">return</span>;',
|
||||||
|
'<span class="line-number">23.</span> }',
|
||||||
|
'<span class="line-number">24.</span> ',
|
||||||
|
'<span class="line-number">25.</span> <span style="color:blue">TreeNode</span>* reverse(<span style="color:blue">TreeNode</span>* head) {',
|
||||||
|
'<span class="line-number">26.</span> <span style="color:blue">TreeNode</span>* prev = <span style="color:blue">nullptr</span>;',
|
||||||
|
'<span class="line-number">27.</span> <span style="color:blue">TreeNode</span>* next = <span style="color:blue">nullptr</span>;',
|
||||||
|
'<span class="line-number">28.</span> <span style="color:blue">while</span> (head != <span style="color:blue">nullptr</span>) {',
|
||||||
|
'<span class="line-number">29.</span> next = head->right;',
|
||||||
|
'<span class="line-number">30.</span> head->right = prev;',
|
||||||
|
'<span class="line-number">31.</span> prev = head;',
|
||||||
|
'<span class="line-number">32.</span> head = next;',
|
||||||
|
'<span class="line-number">33.</span> }',
|
||||||
|
'<span class="line-number">34.</span> <span style="color:blue">return</span> prev;',
|
||||||
|
'<span class="line-number">35.</span> }',
|
||||||
|
'<span class="line-number">36.</span> ',
|
||||||
|
'<span class="line-number">37.</span> <span style="color:blue">void</span> reverseTraverseRightEdge(<span style="color:blue">TreeNode</span>* head) {',
|
||||||
|
'<span class="line-number">38.</span> <span style="color:blue">TreeNode</span>* tail = reverse(head);',
|
||||||
|
'<span class="line-number">39.</span> <span style="color:blue">TreeNode</span>* current = tail;',
|
||||||
|
'<span class="line-number">40.</span> <span style="color:blue">while</span> (current != <span style="color:blue">nullptr</span>) {',
|
||||||
|
'<span class="line-number">41.</span> std::cout << current->val << " ";',
|
||||||
|
'<span class="line-number">42.</span> current = current->right;',
|
||||||
|
'<span class="line-number">43.</span> }',
|
||||||
|
'<span class="line-number">44.</span> reverse(tail); <span style="color:green">// restore structure</span>',
|
||||||
|
'<span class="line-number">45.</span> }'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Initialize code display with proper structure for highlighting
|
||||||
|
function initCodeDisplay() {
|
||||||
|
const codeDisplay = document.getElementById('codeDisplay');
|
||||||
|
codeContent.forEach((line, index) => {
|
||||||
|
const lineDiv = document.createElement('div');
|
||||||
|
lineDiv.className = 'code-line';
|
||||||
|
lineDiv.setAttribute('data-line', index);
|
||||||
|
lineDiv.innerHTML = line;
|
||||||
|
codeDisplay.appendChild(lineDiv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to highlight a specific line of code
|
||||||
|
function highlightLine(lineNum) {
|
||||||
|
// First, remove all highlights
|
||||||
|
const codeLines = document.querySelectorAll('.code-line');
|
||||||
|
codeLines.forEach(line => {
|
||||||
|
line.classList.remove('highlighted');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add highlight to the specified line
|
||||||
|
if (lineNum >= 0 && lineNum < codeContent.length) {
|
||||||
|
const targetLine = document.querySelector(`.code-line[data-line="${lineNum}"]`);
|
||||||
|
if (targetLine) {
|
||||||
|
targetLine.classList.add('highlighted');
|
||||||
|
|
||||||
|
// Scroll to make the highlighted line visible
|
||||||
|
targetLine.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for the "Next Step" button click.
|
// Wait for the "Next Step" button click.
|
||||||
function waitForNext() {
|
function waitForNext() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
@@ -495,7 +541,8 @@
|
|||||||
// Reverse traverse the right edge of a subtree.
|
// Reverse traverse the right edge of a subtree.
|
||||||
async function reverseTraverseRightEdge(head) {
|
async function reverseTraverseRightEdge(head) {
|
||||||
if (!head) return;
|
if (!head) return;
|
||||||
updateExplanation("Reversing the right edge starting from node " + head.val);
|
highlightLine(-1); // Clear code highlighting during reverse traversal
|
||||||
|
updateExplanation("Executing reverseTraverseRightEdge on node " + head.val);
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
let tail = await reverseChain(head);
|
let tail = await reverseChain(head);
|
||||||
layer.draw();
|
layer.draw();
|
||||||
@@ -519,58 +566,135 @@
|
|||||||
|
|
||||||
// Morris Post‑Order Traversal Animation.
|
// Morris Post‑Order Traversal Animation.
|
||||||
async function postorderTraversal(root) {
|
async function postorderTraversal(root) {
|
||||||
|
// Highlight the initialization steps
|
||||||
|
highlightLine(0);
|
||||||
|
updateExplanation("Starting the Morris Post-Order Traversal");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
|
highlightLine(1);
|
||||||
|
updateExplanation("Initializing current = root (node 1)");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
|
highlightLine(2);
|
||||||
|
updateExplanation("Declaring rightmost pointer");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
let current = root;
|
let current = root;
|
||||||
|
|
||||||
while (current !== null) {
|
while (current !== null) {
|
||||||
|
highlightLine(3);
|
||||||
|
updateExplanation("Checking if current is null");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
highlightNode(current, '#ffeb3b');
|
highlightNode(current, '#ffeb3b');
|
||||||
layer.draw();
|
layer.draw();
|
||||||
|
|
||||||
|
highlightLine(4);
|
||||||
|
updateExplanation("Checking if current node " + current.val + " has a left child");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
if (current.left !== null) {
|
if (current.left !== null) {
|
||||||
updateExplanation("Current: " + current.val + " - Has left child, finding rightmost in left subtree");
|
highlightLine(5);
|
||||||
|
updateExplanation("Current: " + current.val + " has left child, initializing rightmost = current.left (node " + current.left.val + ")");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
let rightmost = current.left;
|
let rightmost = current.left;
|
||||||
highlightNode(rightmost, '#2196f3');
|
highlightNode(rightmost, '#2196f3');
|
||||||
layer.draw();
|
layer.draw();
|
||||||
|
|
||||||
|
highlightLine(6);
|
||||||
|
updateExplanation("Finding the rightmost node in left subtree that doesn't have a thread");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
while (rightmost.right !== null && rightmost.right !== current) {
|
while (rightmost.right !== null && rightmost.right !== current) {
|
||||||
updateExplanation("Moving to right: " + rightmost.val);
|
highlightLine(7);
|
||||||
|
updateExplanation("Moving rightmost from " + rightmost.val + " to its right child");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
unhighlightNode(rightmost, 'white');
|
unhighlightNode(rightmost, 'white');
|
||||||
rightmost = rightmost.right;
|
rightmost = rightmost.right;
|
||||||
highlightNode(rightmost, '#2196f3');
|
highlightNode(rightmost, '#2196f3');
|
||||||
layer.draw();
|
layer.draw();
|
||||||
}
|
|
||||||
if (rightmost.right === null) {
|
highlightLine(6);
|
||||||
updateExplanation("Rightmost: " + rightmost.val + " - Creating thread to current: " + current.val);
|
updateExplanation("Checking if we've reached the rightmost node or a thread");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightLine(9);
|
||||||
|
updateExplanation("Checking if rightmost (" + rightmost.val + ") has no thread");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
|
if (rightmost.right === null) {
|
||||||
|
highlightLine(10);
|
||||||
|
updateExplanation("Creating thread from rightmost (" + rightmost.val + ") to current (" + current.val + ")");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
createThreadEdge(rightmost, current);
|
createThreadEdge(rightmost, current);
|
||||||
rightmost.right = current;
|
rightmost.right = current;
|
||||||
highlightNode(rightmost, '#03a9f4');
|
highlightNode(rightmost, '#03a9f4');
|
||||||
layer.draw();
|
layer.draw();
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
|
highlightLine(11);
|
||||||
|
updateExplanation("Moving current to its left child (" + current.left.val + ")");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
unhighlightNode(rightmost, 'white');
|
unhighlightNode(rightmost, 'white');
|
||||||
unhighlightNode(current, 'white');
|
unhighlightNode(current, 'white');
|
||||||
current = current.left;
|
current = current.left;
|
||||||
} else {
|
} else {
|
||||||
updateExplanation("Thread detected at rightmost: " + rightmost.val + " - Removing thread and processing subtree");
|
highlightLine(13);
|
||||||
|
updateExplanation("Thread detected from rightmost (" + rightmost.val + ") to current (" + current.val + ") - removing thread");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
removeThreadEdge(rightmost);
|
removeThreadEdge(rightmost);
|
||||||
rightmost.right = null;
|
rightmost.right = null;
|
||||||
unhighlightNode(rightmost, 'white');
|
unhighlightNode(rightmost, 'white');
|
||||||
layer.draw();
|
layer.draw();
|
||||||
|
|
||||||
|
highlightLine(14);
|
||||||
|
updateExplanation("Processing left subtree of current (" + current.val + ")");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
await reverseTraverseRightEdge(current.left);
|
await reverseTraverseRightEdge(current.left);
|
||||||
|
|
||||||
|
highlightLine(15);
|
||||||
|
updateExplanation("Moving current to its right child");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
unhighlightNode(current, 'white');
|
unhighlightNode(current, 'white');
|
||||||
current = current.right;
|
current = current.right;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updateExplanation("Current: " + current.val + " - No left child, moving right");
|
highlightLine(17);
|
||||||
|
updateExplanation("Current: " + current.val + " has no left child");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
|
highlightLine(18);
|
||||||
|
updateExplanation("Moving current to its right child");
|
||||||
|
await waitForNext();
|
||||||
|
|
||||||
unhighlightNode(current, 'white');
|
unhighlightNode(current, 'white');
|
||||||
current = current.right;
|
current = current.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
highlightLine(3);
|
||||||
|
updateExplanation("Checking if current is null");
|
||||||
|
await waitForNext();
|
||||||
}
|
}
|
||||||
updateExplanation("Processing final right edge");
|
|
||||||
|
highlightLine(21);
|
||||||
|
updateExplanation("Processing the final right edge starting from root");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
await reverseTraverseRightEdge(root);
|
await reverseTraverseRightEdge(root);
|
||||||
|
|
||||||
|
highlightLine(22);
|
||||||
updateExplanation("Morris Post-Order Traversal complete");
|
updateExplanation("Morris Post-Order Traversal complete");
|
||||||
await waitForNext();
|
await waitForNext();
|
||||||
|
|
||||||
|
highlightLine(-1); // Clear highlighting
|
||||||
updateExplanation("Final post-order traversal result: " + document.getElementById('output').innerText);
|
updateExplanation("Final post-order traversal result: " + document.getElementById('output').innerText);
|
||||||
nodes.forEach(n => {
|
nodes.forEach(n => {
|
||||||
n.shape.moveToTop();
|
n.shape.moveToTop();
|
||||||
@@ -586,6 +710,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
initCodeDisplay();
|
||||||
document.getElementById('nextStep').disabled = false;
|
document.getElementById('nextStep').disabled = false;
|
||||||
postorderTraversal(node1);
|
postorderTraversal(node1);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user