updating morris

This commit is contained in:
Jidong Xiao
2025-04-22 16:55:25 -04:00
committed by JamesFlare1212
parent 3c88acac9f
commit 28243a596d

View File

@@ -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 PostOrder Traversal Animation. // Morris PostOrder 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();
if (current.left !== null) {
updateExplanation("Current: " + current.val + " - Has left child, finding rightmost in left subtree"); highlightLine(4);
updateExplanation("Checking if current node " + current.val + " has a left child");
await waitForNext(); await waitForNext();
if (current.left !== null) {
highlightLine(5);
updateExplanation("Current: " + current.val + " has left child, initializing rightmost = current.left (node " + current.left.val + ")");
await waitForNext();
let rightmost = current.left; let rightmost = current.left;
highlightNode(rightmost, '#2196f3'); highlightNode(rightmost, '#2196f3');
layer.draw(); layer.draw();
while (rightmost.right !== null && rightmost.right !== current) {
updateExplanation("Moving to right: " + rightmost.val); highlightLine(6);
updateExplanation("Finding the rightmost node in left subtree that doesn't have a thread");
await waitForNext(); await waitForNext();
while (rightmost.right !== null && rightmost.right !== current) {
highlightLine(7);
updateExplanation("Moving rightmost from " + rightmost.val + " to its right child");
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;
} }
}
updateExplanation("Processing final right edge"); highlightLine(3);
updateExplanation("Checking if current is null");
await waitForNext(); await waitForNext();
}
highlightLine(21);
updateExplanation("Processing the final right edge starting from root");
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);
}; };