@tomaszjarosz/react-visualizers 0.2.13 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +288 -45
- package/dist/index.cjs +1272 -204
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1272 -204
- package/dist/index.js.map +1 -1
- package/dist/react-visualizers.css +53 -0
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -501,17 +501,20 @@ const ControlPanel = ({
|
|
|
501
501
|
extraControls
|
|
502
502
|
}) => {
|
|
503
503
|
const colors = ACCENT_COLORS$4[accentColor];
|
|
504
|
-
|
|
505
|
-
|
|
504
|
+
const speedLabelId = React.useId();
|
|
505
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between flex-wrap gap-3", role: "toolbar", "aria-label": "Playback controls", children: [
|
|
506
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Navigation", children: [
|
|
506
507
|
isPlaying && /* @__PURE__ */ jsxs(
|
|
507
508
|
"span",
|
|
508
509
|
{
|
|
509
510
|
className: `flex items-center gap-1 text-xs ${colors.playing} font-medium`,
|
|
511
|
+
"aria-live": "polite",
|
|
510
512
|
children: [
|
|
511
513
|
/* @__PURE__ */ jsx(
|
|
512
514
|
"span",
|
|
513
515
|
{
|
|
514
|
-
className: `w-2 h-2 ${colors.playingDot} rounded-full animate-pulse
|
|
516
|
+
className: `w-2 h-2 ${colors.playingDot} rounded-full animate-pulse`,
|
|
517
|
+
"aria-hidden": "true"
|
|
515
518
|
}
|
|
516
519
|
),
|
|
517
520
|
"Playing"
|
|
@@ -524,7 +527,9 @@ const ControlPanel = ({
|
|
|
524
527
|
onClick: onPlayPause,
|
|
525
528
|
className: `p-2 text-white rounded-lg transition-colors ${isPlaying ? colors.buttonActive : colors.button}`,
|
|
526
529
|
title: "Play/Pause (P)",
|
|
527
|
-
|
|
530
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
531
|
+
"aria-pressed": isPlaying,
|
|
532
|
+
children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "w-4 h-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Play, { className: "w-4 h-4", "aria-hidden": "true" })
|
|
528
533
|
}
|
|
529
534
|
),
|
|
530
535
|
/* @__PURE__ */ jsx(
|
|
@@ -534,7 +539,8 @@ const ControlPanel = ({
|
|
|
534
539
|
disabled: isPlaying || currentStep <= 0,
|
|
535
540
|
className: "p-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors disabled:opacity-50",
|
|
536
541
|
title: "Step Back ([)",
|
|
537
|
-
|
|
542
|
+
"aria-label": "Step back",
|
|
543
|
+
children: /* @__PURE__ */ jsx(SkipBack, { className: "w-4 h-4", "aria-hidden": "true" })
|
|
538
544
|
}
|
|
539
545
|
),
|
|
540
546
|
/* @__PURE__ */ jsx(
|
|
@@ -544,7 +550,8 @@ const ControlPanel = ({
|
|
|
544
550
|
disabled: isPlaying || currentStep >= totalSteps - 1,
|
|
545
551
|
className: "p-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors disabled:opacity-50",
|
|
546
552
|
title: "Step Forward (])",
|
|
547
|
-
|
|
553
|
+
"aria-label": "Step forward",
|
|
554
|
+
children: /* @__PURE__ */ jsx(SkipForward, { className: "w-4 h-4", "aria-hidden": "true" })
|
|
548
555
|
}
|
|
549
556
|
),
|
|
550
557
|
/* @__PURE__ */ jsx(
|
|
@@ -553,7 +560,8 @@ const ControlPanel = ({
|
|
|
553
560
|
onClick: onReset,
|
|
554
561
|
className: "p-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors",
|
|
555
562
|
title: "Reset (R)",
|
|
556
|
-
|
|
563
|
+
"aria-label": "Reset",
|
|
564
|
+
children: /* @__PURE__ */ jsx(RotateCcw, { className: "w-4 h-4", "aria-hidden": "true" })
|
|
557
565
|
}
|
|
558
566
|
),
|
|
559
567
|
showShuffle && onShuffle && /* @__PURE__ */ jsx(
|
|
@@ -563,13 +571,14 @@ const ControlPanel = ({
|
|
|
563
571
|
disabled: isPlaying,
|
|
564
572
|
className: `bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors disabled:opacity-50 ${shuffleLabel ? "px-3 py-2 text-sm" : "p-2"}`,
|
|
565
573
|
title: shuffleLabel || "Shuffle",
|
|
566
|
-
|
|
574
|
+
"aria-label": shuffleLabel || "Shuffle",
|
|
575
|
+
children: shuffleLabel || /* @__PURE__ */ jsx(Shuffle, { className: "w-4 h-4", "aria-hidden": "true" })
|
|
567
576
|
}
|
|
568
577
|
)
|
|
569
578
|
] }),
|
|
570
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
579
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", role: "group", "aria-label": "Speed control", children: [
|
|
571
580
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
572
|
-
/* @__PURE__ */ jsx("label", { className: "text-xs text-gray-500", children: "Speed" }),
|
|
581
|
+
/* @__PURE__ */ jsx("label", { id: speedLabelId, className: "text-xs text-gray-500", children: "Speed" }),
|
|
573
582
|
/* @__PURE__ */ jsx(
|
|
574
583
|
"input",
|
|
575
584
|
{
|
|
@@ -578,7 +587,11 @@ const ControlPanel = ({
|
|
|
578
587
|
max: "100",
|
|
579
588
|
value: speed,
|
|
580
589
|
onChange: (e) => onSpeedChange(Number(e.target.value)),
|
|
581
|
-
className: "w-24 h-1 bg-gray-300 rounded-lg appearance-none cursor-pointer"
|
|
590
|
+
className: "w-24 h-1 bg-gray-300 rounded-lg appearance-none cursor-pointer",
|
|
591
|
+
"aria-labelledby": speedLabelId,
|
|
592
|
+
"aria-valuemin": 1,
|
|
593
|
+
"aria-valuemax": 100,
|
|
594
|
+
"aria-valuenow": speed
|
|
582
595
|
}
|
|
583
596
|
)
|
|
584
597
|
] }),
|
|
@@ -1446,11 +1459,11 @@ const InterviewModePanel = ({
|
|
|
1446
1459
|
}) => {
|
|
1447
1460
|
const colors = ACCENT_COLORS[accentColor];
|
|
1448
1461
|
if (isComplete) {
|
|
1449
|
-
return /* @__PURE__ */ jsx("div", { className: "p-6 bg-gradient-to-br from-gray-50 to-white rounded-xl border border-gray-200", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
1450
|
-
/* @__PURE__ */ jsx(Trophy, { className: "w-16 h-16 mx-auto mb-4 text-yellow-500" }),
|
|
1462
|
+
return /* @__PURE__ */ jsx("div", { className: "p-6 bg-gradient-to-br from-gray-50 to-white rounded-xl border border-gray-200", role: "region", "aria-label": "Quiz results", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
1463
|
+
/* @__PURE__ */ jsx(Trophy, { className: "w-16 h-16 mx-auto mb-4 text-yellow-500", "aria-hidden": "true" }),
|
|
1451
1464
|
/* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold text-gray-900 mb-2", children: "Interview Complete!" }),
|
|
1452
|
-
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
1453
|
-
/* @__PURE__ */ jsxs("div", { className: "text-5xl font-bold text-gray-900 mb-1", children: [
|
|
1465
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", "aria-live": "polite", children: [
|
|
1466
|
+
/* @__PURE__ */ jsxs("div", { className: "text-5xl font-bold text-gray-900 mb-1", "aria-label": `Score: ${score.percentage} percent`, children: [
|
|
1454
1467
|
score.percentage,
|
|
1455
1468
|
"%"
|
|
1456
1469
|
] }),
|
|
@@ -1466,7 +1479,7 @@ const InterviewModePanel = ({
|
|
|
1466
1479
|
${score.percentage >= 80 ? "bg-green-100 text-green-700" : ""}
|
|
1467
1480
|
${score.percentage >= 60 && score.percentage < 80 ? "bg-yellow-100 text-yellow-700" : ""}
|
|
1468
1481
|
${score.percentage < 60 ? "bg-red-100 text-red-700" : ""}
|
|
1469
|
-
`, children: [
|
|
1482
|
+
`, role: "status", children: [
|
|
1470
1483
|
score.percentage >= 80 && "🎉 Excellent! Ready for interviews!",
|
|
1471
1484
|
score.percentage >= 60 && score.percentage < 80 && "👍 Good job! Keep practicing!",
|
|
1472
1485
|
score.percentage < 60 && "📚 Review the concepts and try again!"
|
|
@@ -1475,13 +1488,14 @@ const InterviewModePanel = ({
|
|
|
1475
1488
|
"button",
|
|
1476
1489
|
{
|
|
1477
1490
|
onClick: onRestart,
|
|
1491
|
+
"aria-label": "Restart quiz",
|
|
1478
1492
|
className: `
|
|
1479
1493
|
flex items-center gap-2 mx-auto px-6 py-3 rounded-lg
|
|
1480
1494
|
text-white font-medium transition-colors
|
|
1481
1495
|
${colors.button}
|
|
1482
1496
|
`,
|
|
1483
1497
|
children: [
|
|
1484
|
-
/* @__PURE__ */ jsx(RotateCcw, { className: "w-5 h-5" }),
|
|
1498
|
+
/* @__PURE__ */ jsx(RotateCcw, { className: "w-5 h-5", "aria-hidden": "true" }),
|
|
1485
1499
|
"Try Again"
|
|
1486
1500
|
]
|
|
1487
1501
|
}
|
|
@@ -1521,7 +1535,7 @@ const InterviewModePanel = ({
|
|
|
1521
1535
|
] }),
|
|
1522
1536
|
/* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
1523
1537
|
/* @__PURE__ */ jsx("h4", { className: "text-lg font-semibold text-gray-900 mb-4", children: currentQuestion.question }),
|
|
1524
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-2 mb-4", children: currentQuestion.options.map((option, index) => {
|
|
1538
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2 mb-4", role: "radiogroup", "aria-label": "Answer options", children: currentQuestion.options.map((option, index) => {
|
|
1525
1539
|
const isSelected = selectedAnswer === index;
|
|
1526
1540
|
const isCorrect = index === currentQuestion.correctAnswer;
|
|
1527
1541
|
const showResult = showExplanation;
|
|
@@ -1540,6 +1554,9 @@ const InterviewModePanel = ({
|
|
|
1540
1554
|
{
|
|
1541
1555
|
onClick: () => !isAnswered && onSelectAnswer(index),
|
|
1542
1556
|
disabled: isAnswered,
|
|
1557
|
+
role: "radio",
|
|
1558
|
+
"aria-checked": isSelected,
|
|
1559
|
+
"aria-disabled": isAnswered,
|
|
1543
1560
|
className: `
|
|
1544
1561
|
w-full p-3 rounded-lg border-2 text-left transition-all
|
|
1545
1562
|
flex items-center gap-3
|
|
@@ -1547,24 +1564,31 @@ const InterviewModePanel = ({
|
|
|
1547
1564
|
${isAnswered ? "cursor-default" : "cursor-pointer"}
|
|
1548
1565
|
`,
|
|
1549
1566
|
children: [
|
|
1550
|
-
/* @__PURE__ */ jsxs(
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1567
|
+
/* @__PURE__ */ jsxs(
|
|
1568
|
+
"span",
|
|
1569
|
+
{
|
|
1570
|
+
className: `
|
|
1571
|
+
w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold
|
|
1572
|
+
${showResult && isCorrect ? "bg-green-500 text-white" : ""}
|
|
1573
|
+
${showResult && isSelected && !isCorrect ? "bg-red-500 text-white" : ""}
|
|
1574
|
+
${!showResult ? "bg-gray-200 text-gray-600" : ""}
|
|
1575
|
+
`,
|
|
1576
|
+
"aria-hidden": "true",
|
|
1577
|
+
children: [
|
|
1578
|
+
showResult && isCorrect && /* @__PURE__ */ jsx(CircleCheckBig, { className: "w-4 h-4" }),
|
|
1579
|
+
showResult && isSelected && !isCorrect && /* @__PURE__ */ jsx(CircleX, { className: "w-4 h-4" }),
|
|
1580
|
+
!showResult && String.fromCharCode(65 + index)
|
|
1581
|
+
]
|
|
1582
|
+
}
|
|
1583
|
+
),
|
|
1560
1584
|
/* @__PURE__ */ jsx("span", { className: `flex-1 ${showResult && isCorrect ? "font-medium text-green-700" : ""}`, children: option })
|
|
1561
1585
|
]
|
|
1562
1586
|
},
|
|
1563
1587
|
index
|
|
1564
1588
|
);
|
|
1565
1589
|
}) }),
|
|
1566
|
-
currentQuestion.hint && !showExplanation && /* @__PURE__ */ jsx("div", { className: "mb-4", children: showHint ? /* @__PURE__ */ jsx("div", { className: "p-3 bg-yellow-50 rounded-lg border border-yellow-200", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
1567
|
-
/* @__PURE__ */ jsx(Lightbulb, { className: "w-5 h-5 text-yellow-600 flex-shrink-0 mt-0.5" }),
|
|
1590
|
+
currentQuestion.hint && !showExplanation && /* @__PURE__ */ jsx("div", { className: "mb-4", children: showHint ? /* @__PURE__ */ jsx("div", { className: "p-3 bg-yellow-50 rounded-lg border border-yellow-200", role: "note", "aria-label": "Hint", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
1591
|
+
/* @__PURE__ */ jsx(Lightbulb, { className: "w-5 h-5 text-yellow-600 flex-shrink-0 mt-0.5", "aria-hidden": "true" }),
|
|
1568
1592
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1569
1593
|
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-yellow-800 mb-1", children: "Hint" }),
|
|
1570
1594
|
/* @__PURE__ */ jsx("div", { className: "text-sm text-yellow-700", children: currentQuestion.hint })
|
|
@@ -1574,8 +1598,9 @@ const InterviewModePanel = ({
|
|
|
1574
1598
|
{
|
|
1575
1599
|
onClick: onUseHint,
|
|
1576
1600
|
className: "flex items-center gap-2 text-sm text-yellow-600 hover:text-yellow-700",
|
|
1601
|
+
"aria-label": "Show hint for this question",
|
|
1577
1602
|
children: [
|
|
1578
|
-
/* @__PURE__ */ jsx(Lightbulb, { className: "w-4 h-4" }),
|
|
1603
|
+
/* @__PURE__ */ jsx(Lightbulb, { className: "w-4 h-4", "aria-hidden": "true" }),
|
|
1579
1604
|
"Show hint"
|
|
1580
1605
|
]
|
|
1581
1606
|
}
|
|
@@ -1591,19 +1616,20 @@ const InterviewModePanel = ({
|
|
|
1591
1616
|
] })
|
|
1592
1617
|
] }) })
|
|
1593
1618
|
] }),
|
|
1594
|
-
/* @__PURE__ */ jsxs("
|
|
1619
|
+
/* @__PURE__ */ jsxs("nav", { className: "px-4 py-3 bg-gray-50 border-t border-gray-200 flex items-center justify-between", "aria-label": "Question navigation", children: [
|
|
1595
1620
|
/* @__PURE__ */ jsxs(
|
|
1596
1621
|
"button",
|
|
1597
1622
|
{
|
|
1598
1623
|
onClick: onPreviousQuestion,
|
|
1599
1624
|
disabled: currentQuestionIndex === 0,
|
|
1625
|
+
"aria-label": "Previous question",
|
|
1600
1626
|
className: `
|
|
1601
1627
|
flex items-center gap-1 px-3 py-2 rounded-lg text-sm font-medium
|
|
1602
1628
|
transition-colors
|
|
1603
1629
|
${currentQuestionIndex === 0 ? "text-gray-300 cursor-not-allowed" : "text-gray-600 hover:bg-gray-200"}
|
|
1604
1630
|
`,
|
|
1605
1631
|
children: [
|
|
1606
|
-
/* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" }),
|
|
1632
|
+
/* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4", "aria-hidden": "true" }),
|
|
1607
1633
|
"Previous"
|
|
1608
1634
|
]
|
|
1609
1635
|
}
|
|
@@ -1613,6 +1639,7 @@ const InterviewModePanel = ({
|
|
|
1613
1639
|
{
|
|
1614
1640
|
onClick: onNextQuestion,
|
|
1615
1641
|
disabled: currentQuestionIndex === totalQuestions - 1,
|
|
1642
|
+
"aria-label": currentQuestionIndex === totalQuestions - 1 ? "Finish quiz" : "Next question",
|
|
1616
1643
|
className: `
|
|
1617
1644
|
flex items-center gap-1 px-4 py-2 rounded-lg text-sm font-medium
|
|
1618
1645
|
transition-colors text-white
|
|
@@ -1620,7 +1647,7 @@ const InterviewModePanel = ({
|
|
|
1620
1647
|
`,
|
|
1621
1648
|
children: [
|
|
1622
1649
|
currentQuestionIndex === totalQuestions - 1 ? "Finish" : "Next",
|
|
1623
|
-
/* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
|
|
1650
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4", "aria-hidden": "true" })
|
|
1624
1651
|
]
|
|
1625
1652
|
}
|
|
1626
1653
|
)
|
|
@@ -1635,11 +1662,46 @@ const ALGORITHM_NAMES$1 = {
|
|
|
1635
1662
|
merge: "MergeSort"
|
|
1636
1663
|
};
|
|
1637
1664
|
const ALGORITHM_COMPLEXITIES$1 = {
|
|
1638
|
-
bubble: {
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1665
|
+
bubble: {
|
|
1666
|
+
time: "O(n²)",
|
|
1667
|
+
best: "O(n)",
|
|
1668
|
+
average: "O(n²)",
|
|
1669
|
+
worst: "O(n²)",
|
|
1670
|
+
space: "O(1)",
|
|
1671
|
+
stable: true
|
|
1672
|
+
},
|
|
1673
|
+
selection: {
|
|
1674
|
+
time: "O(n²)",
|
|
1675
|
+
best: "O(n²)",
|
|
1676
|
+
average: "O(n²)",
|
|
1677
|
+
worst: "O(n²)",
|
|
1678
|
+
space: "O(1)",
|
|
1679
|
+
stable: false
|
|
1680
|
+
},
|
|
1681
|
+
insertion: {
|
|
1682
|
+
time: "O(n²)",
|
|
1683
|
+
best: "O(n)",
|
|
1684
|
+
average: "O(n²)",
|
|
1685
|
+
worst: "O(n²)",
|
|
1686
|
+
space: "O(1)",
|
|
1687
|
+
stable: true
|
|
1688
|
+
},
|
|
1689
|
+
quick: {
|
|
1690
|
+
time: "O(n log n)",
|
|
1691
|
+
best: "O(n log n)",
|
|
1692
|
+
average: "O(n log n)",
|
|
1693
|
+
worst: "O(n²)",
|
|
1694
|
+
space: "O(log n)",
|
|
1695
|
+
stable: false
|
|
1696
|
+
},
|
|
1697
|
+
merge: {
|
|
1698
|
+
time: "O(n log n)",
|
|
1699
|
+
best: "O(n log n)",
|
|
1700
|
+
average: "O(n log n)",
|
|
1701
|
+
worst: "O(n log n)",
|
|
1702
|
+
space: "O(n)",
|
|
1703
|
+
stable: true
|
|
1704
|
+
}
|
|
1643
1705
|
};
|
|
1644
1706
|
const ALGORITHM_CODE$1 = {
|
|
1645
1707
|
bubble: [
|
|
@@ -1694,7 +1756,7 @@ const BINARY_SEARCH_CODE = [
|
|
|
1694
1756
|
" right = mid - 1",
|
|
1695
1757
|
" return -1 // Not found"
|
|
1696
1758
|
];
|
|
1697
|
-
const LEGEND_ITEMS$
|
|
1759
|
+
const LEGEND_ITEMS$A = [
|
|
1698
1760
|
{ color: "bg-blue-100", label: "Search Space" },
|
|
1699
1761
|
{ color: "bg-gray-200", label: "Eliminated" },
|
|
1700
1762
|
{ color: "bg-purple-500", label: "Mid" },
|
|
@@ -2094,7 +2156,7 @@ const BinarySearchVisualizerComponent = ({
|
|
|
2094
2156
|
accentColor: "green"
|
|
2095
2157
|
}
|
|
2096
2158
|
),
|
|
2097
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
2159
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$A })
|
|
2098
2160
|
] })
|
|
2099
2161
|
]
|
|
2100
2162
|
}
|
|
@@ -2159,7 +2221,7 @@ const ALGORITHM_CODE = {
|
|
|
2159
2221
|
" else arr[k++] = right[j++]"
|
|
2160
2222
|
]
|
|
2161
2223
|
};
|
|
2162
|
-
const LEGEND_ITEMS$
|
|
2224
|
+
const LEGEND_ITEMS$z = [
|
|
2163
2225
|
{ color: "bg-blue-500", label: "Default" },
|
|
2164
2226
|
{ color: "bg-yellow-400", label: "Comparing" },
|
|
2165
2227
|
{ color: "bg-red-500", label: "Swapping" },
|
|
@@ -2640,6 +2702,7 @@ const SortingVisualizerComponent = ({
|
|
|
2640
2702
|
const [customArray, setCustomArray] = useState(null);
|
|
2641
2703
|
const [historyCollapsed, setHistoryCollapsed] = useState(true);
|
|
2642
2704
|
const [urlStateLoaded, setUrlStateLoaded] = useState(false);
|
|
2705
|
+
const [showComplexityTable, setShowComplexityTable] = useState(false);
|
|
2643
2706
|
const playingRef = useRef(false);
|
|
2644
2707
|
const timeoutRef = useRef(null);
|
|
2645
2708
|
const VISUALIZER_ID = "sorting-visualizer";
|
|
@@ -2944,6 +3007,63 @@ const SortingVisualizerComponent = ({
|
|
|
2944
3007
|
/* @__PURE__ */ jsx(HelpPanel, {})
|
|
2945
3008
|
] })
|
|
2946
3009
|
] }) }),
|
|
3010
|
+
/* @__PURE__ */ jsxs("div", { className: "px-4 pb-2", children: [
|
|
3011
|
+
/* @__PURE__ */ jsxs(
|
|
3012
|
+
"button",
|
|
3013
|
+
{
|
|
3014
|
+
onClick: () => setShowComplexityTable(!showComplexityTable),
|
|
3015
|
+
className: "flex items-center gap-2 text-sm text-indigo-600 hover:text-indigo-800 font-medium transition-colors",
|
|
3016
|
+
children: [
|
|
3017
|
+
/* @__PURE__ */ jsx(
|
|
3018
|
+
"svg",
|
|
3019
|
+
{
|
|
3020
|
+
className: `w-4 h-4 transition-transform ${showComplexityTable ? "rotate-90" : ""}`,
|
|
3021
|
+
fill: "none",
|
|
3022
|
+
viewBox: "0 0 24 24",
|
|
3023
|
+
stroke: "currentColor",
|
|
3024
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
|
|
3025
|
+
}
|
|
3026
|
+
),
|
|
3027
|
+
"Algorithm Complexity Comparison"
|
|
3028
|
+
]
|
|
3029
|
+
}
|
|
3030
|
+
),
|
|
3031
|
+
showComplexityTable && /* @__PURE__ */ jsxs("div", { className: "mt-3 p-4 bg-gradient-to-r from-indigo-50 to-blue-50 rounded-xl border border-indigo-200", children: [
|
|
3032
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
3033
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "text-left text-indigo-900", children: [
|
|
3034
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 pr-4 font-semibold", children: "Algorithm" }),
|
|
3035
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 px-3 font-semibold text-center", children: "Best" }),
|
|
3036
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 px-3 font-semibold text-center", children: "Average" }),
|
|
3037
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 px-3 font-semibold text-center", children: "Worst" }),
|
|
3038
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 px-3 font-semibold text-center", children: "Space" }),
|
|
3039
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 pl-3 font-semibold text-center", children: "Stable" })
|
|
3040
|
+
] }) }),
|
|
3041
|
+
/* @__PURE__ */ jsx("tbody", { className: "text-gray-700", children: Object.keys(ALGORITHM_NAMES$1).map((alg) => {
|
|
3042
|
+
const comp = ALGORITHM_COMPLEXITIES$1[alg];
|
|
3043
|
+
const isCurrentAlgorithm = alg === algorithm;
|
|
3044
|
+
return /* @__PURE__ */ jsxs(
|
|
3045
|
+
"tr",
|
|
3046
|
+
{
|
|
3047
|
+
className: `border-t border-indigo-100 ${isCurrentAlgorithm ? "bg-indigo-100/50 font-medium" : ""}`,
|
|
3048
|
+
children: [
|
|
3049
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 pr-4", children: /* @__PURE__ */ jsx("span", { className: isCurrentAlgorithm ? "text-indigo-700" : "", children: ALGORITHM_NAMES$1[alg] }) }),
|
|
3050
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsx("span", { className: `px-2 py-0.5 rounded text-xs ${comp.best.includes("log") ? "bg-green-100 text-green-700" : "bg-yellow-100 text-yellow-700"}`, children: comp.best }) }),
|
|
3051
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsx("span", { className: `px-2 py-0.5 rounded text-xs ${comp.average.includes("log") ? "bg-green-100 text-green-700" : "bg-yellow-100 text-yellow-700"}`, children: comp.average }) }),
|
|
3052
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsx("span", { className: `px-2 py-0.5 rounded text-xs ${comp.worst.includes("log") ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700"}`, children: comp.worst }) }),
|
|
3053
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsx("span", { className: `px-2 py-0.5 rounded text-xs ${comp.space === "O(1)" ? "bg-green-100 text-green-700" : "bg-purple-100 text-purple-700"}`, children: comp.space }) }),
|
|
3054
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 pl-3 text-center", children: comp.stable ? /* @__PURE__ */ jsx("span", { className: "text-green-600", children: "✓" }) : /* @__PURE__ */ jsx("span", { className: "text-red-400", children: "✗" }) })
|
|
3055
|
+
]
|
|
3056
|
+
},
|
|
3057
|
+
alg
|
|
3058
|
+
);
|
|
3059
|
+
}) })
|
|
3060
|
+
] }) }),
|
|
3061
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-3 text-xs text-indigo-600", children: [
|
|
3062
|
+
/* @__PURE__ */ jsx("strong", { children: "Stable:" }),
|
|
3063
|
+
" A sorting algorithm is stable if elements with equal keys maintain their relative order."
|
|
3064
|
+
] })
|
|
3065
|
+
] })
|
|
3066
|
+
] }),
|
|
2947
3067
|
showControls && /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 bg-gray-50 border-t border-gray-200", children: [
|
|
2948
3068
|
/* @__PURE__ */ jsx(
|
|
2949
3069
|
ControlPanel,
|
|
@@ -2963,7 +3083,7 @@ const SortingVisualizerComponent = ({
|
|
|
2963
3083
|
extraControls: sizeControl
|
|
2964
3084
|
}
|
|
2965
3085
|
),
|
|
2966
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
3086
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$z })
|
|
2967
3087
|
] })
|
|
2968
3088
|
]
|
|
2969
3089
|
}
|
|
@@ -3509,7 +3629,7 @@ const DIJKSTRA_CODE = [
|
|
|
3509
3629
|
" dist[v] = dist[u]+w",
|
|
3510
3630
|
" pq.add((dist[v], v))"
|
|
3511
3631
|
];
|
|
3512
|
-
const LEGEND_ITEMS$
|
|
3632
|
+
const LEGEND_ITEMS$y = [
|
|
3513
3633
|
{ color: "bg-blue-100", label: "Unvisited", border: "#60a5fa" },
|
|
3514
3634
|
{ color: "bg-yellow-400", label: "Current", border: "#ca8a04" },
|
|
3515
3635
|
{ color: "bg-green-400", label: "Visited", border: "#16a34a" }
|
|
@@ -3870,7 +3990,7 @@ const DijkstraVisualizerComponent = ({
|
|
|
3870
3990
|
accentColor: "orange"
|
|
3871
3991
|
}
|
|
3872
3992
|
),
|
|
3873
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
3993
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$y })
|
|
3874
3994
|
] })
|
|
3875
3995
|
]
|
|
3876
3996
|
}
|
|
@@ -3894,7 +4014,7 @@ const KNAPSACK_CODE = [
|
|
|
3894
4014
|
" take = dp[i-1][w-weight] + value",
|
|
3895
4015
|
" dp[i][w] = max(skip, take)"
|
|
3896
4016
|
];
|
|
3897
|
-
const LEGEND_ITEMS$
|
|
4017
|
+
const LEGEND_ITEMS$x = [
|
|
3898
4018
|
{ color: "bg-gray-50", label: "Not computed", border: "#d1d5db" },
|
|
3899
4019
|
{ color: "bg-blue-100", label: "Computed" },
|
|
3900
4020
|
{ color: "bg-green-400", label: "Take item" },
|
|
@@ -4190,7 +4310,7 @@ const DPVisualizerComponent = ({
|
|
|
4190
4310
|
accentColor: "teal"
|
|
4191
4311
|
}
|
|
4192
4312
|
),
|
|
4193
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
4313
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$x })
|
|
4194
4314
|
] })
|
|
4195
4315
|
]
|
|
4196
4316
|
}
|
|
@@ -4229,7 +4349,7 @@ const BFS_CODE = [
|
|
|
4229
4349
|
" visited[neighbor] = true",
|
|
4230
4350
|
" queue.enqueue(neighbor)"
|
|
4231
4351
|
];
|
|
4232
|
-
const LEGEND_ITEMS$
|
|
4352
|
+
const LEGEND_ITEMS$w = [
|
|
4233
4353
|
{ color: "bg-blue-100", label: "Unvisited", border: "#60a5fa" },
|
|
4234
4354
|
{ color: "bg-yellow-400", label: "Current", border: "#ca8a04" },
|
|
4235
4355
|
{ color: "bg-green-400", label: "Visited", border: "#16a34a" }
|
|
@@ -4656,7 +4776,7 @@ const GraphVisualizerComponent = ({
|
|
|
4656
4776
|
accentColor: "purple"
|
|
4657
4777
|
}
|
|
4658
4778
|
),
|
|
4659
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
4779
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$w })
|
|
4660
4780
|
] })
|
|
4661
4781
|
]
|
|
4662
4782
|
}
|
|
@@ -4664,7 +4784,7 @@ const GraphVisualizerComponent = ({
|
|
|
4664
4784
|
};
|
|
4665
4785
|
const GraphVisualizer = React.memo(GraphVisualizerComponent);
|
|
4666
4786
|
const BUCKET_COUNT$2 = 8;
|
|
4667
|
-
const OPERATIONS$
|
|
4787
|
+
const OPERATIONS$j = [
|
|
4668
4788
|
{ op: "put", key: "Alice", value: 25 },
|
|
4669
4789
|
{ op: "put", key: "Bob", value: 30 },
|
|
4670
4790
|
{ op: "put", key: "Charlie", value: 35 },
|
|
@@ -4696,7 +4816,7 @@ const HASHMAP_CODE = [
|
|
|
4696
4816
|
" return entry.value",
|
|
4697
4817
|
" return null"
|
|
4698
4818
|
];
|
|
4699
|
-
const LEGEND_ITEMS$
|
|
4819
|
+
const LEGEND_ITEMS$v = [
|
|
4700
4820
|
{ color: "bg-blue-50", label: "Current bucket", border: "#60a5fa" },
|
|
4701
4821
|
{ color: "bg-blue-500", label: "Insert/Update" },
|
|
4702
4822
|
{ color: "bg-green-400", label: "Found" },
|
|
@@ -4721,7 +4841,7 @@ function generateHashMapSteps$1() {
|
|
|
4721
4841
|
description: `Initialize HashMap with ${BUCKET_COUNT$2} buckets. Each bucket is a linked list for collision handling.`,
|
|
4722
4842
|
codeLine: -1
|
|
4723
4843
|
});
|
|
4724
|
-
for (const { op, key, value } of OPERATIONS$
|
|
4844
|
+
for (const { op, key, value } of OPERATIONS$j) {
|
|
4725
4845
|
const hash = simpleHash$7(key);
|
|
4726
4846
|
const index = hash % BUCKET_COUNT$2;
|
|
4727
4847
|
if (op === "put") {
|
|
@@ -5008,7 +5128,7 @@ const HashMapVisualizerComponent = ({
|
|
|
5008
5128
|
accentColor: "indigo"
|
|
5009
5129
|
}
|
|
5010
5130
|
),
|
|
5011
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
5131
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$v })
|
|
5012
5132
|
] })
|
|
5013
5133
|
]
|
|
5014
5134
|
}
|
|
@@ -5016,7 +5136,7 @@ const HashMapVisualizerComponent = ({
|
|
|
5016
5136
|
};
|
|
5017
5137
|
const HashMapVisualizer = React.memo(HashMapVisualizerComponent);
|
|
5018
5138
|
const BUCKET_COUNT$1 = 8;
|
|
5019
|
-
const OPERATIONS$
|
|
5139
|
+
const OPERATIONS$i = [
|
|
5020
5140
|
{ op: "put", key: "Alice", value: 25 },
|
|
5021
5141
|
{ op: "put", key: "Bob", value: 30 },
|
|
5022
5142
|
{ op: "put", key: "Charlie", value: 35 },
|
|
@@ -5025,7 +5145,7 @@ const OPERATIONS$g = [
|
|
|
5025
5145
|
{ op: "put", key: "Alice", value: 26 },
|
|
5026
5146
|
{ op: "get", key: "Frank" }
|
|
5027
5147
|
];
|
|
5028
|
-
const LEGEND_ITEMS$
|
|
5148
|
+
const LEGEND_ITEMS$u = [
|
|
5029
5149
|
{ color: "bg-blue-50", label: "Current bucket", border: "#60a5fa" },
|
|
5030
5150
|
{ color: "bg-blue-500", label: "Insert/Update" },
|
|
5031
5151
|
{ color: "bg-green-400", label: "Found" },
|
|
@@ -5154,7 +5274,7 @@ function generateHashMapSteps() {
|
|
|
5154
5274
|
buckets: buckets.map((b) => ({ entries: [...b.entries] })),
|
|
5155
5275
|
description: `Initialize HashMap with ${BUCKET_COUNT$1} buckets`
|
|
5156
5276
|
});
|
|
5157
|
-
for (const { op, key, value } of OPERATIONS$
|
|
5277
|
+
for (const { op, key, value } of OPERATIONS$i) {
|
|
5158
5278
|
const hash = simpleHash$6(key);
|
|
5159
5279
|
const index = hash % BUCKET_COUNT$1;
|
|
5160
5280
|
if (op === "put") {
|
|
@@ -5395,7 +5515,7 @@ const HashMapInterviewVisualizerComponent = ({
|
|
|
5395
5515
|
accentColor: "indigo"
|
|
5396
5516
|
}
|
|
5397
5517
|
),
|
|
5398
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
5518
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$u })
|
|
5399
5519
|
] })
|
|
5400
5520
|
]
|
|
5401
5521
|
}
|
|
@@ -5403,7 +5523,7 @@ const HashMapInterviewVisualizerComponent = ({
|
|
|
5403
5523
|
};
|
|
5404
5524
|
const HashMapInterviewVisualizer = React.memo(HashMapInterviewVisualizerComponent);
|
|
5405
5525
|
const INITIAL_DATA = [10, 20, 30, 40, 50];
|
|
5406
|
-
const OPERATIONS$
|
|
5526
|
+
const OPERATIONS$h = [
|
|
5407
5527
|
{ op: "get", index: 2 },
|
|
5408
5528
|
{ op: "addLast", value: 60 },
|
|
5409
5529
|
{ op: "addFirst", value: 5 },
|
|
@@ -5412,7 +5532,7 @@ const OPERATIONS$f = [
|
|
|
5412
5532
|
{ op: "removeLast" },
|
|
5413
5533
|
{ op: "removeMiddle", index: 2 }
|
|
5414
5534
|
];
|
|
5415
|
-
const LEGEND_ITEMS$
|
|
5535
|
+
const LEGEND_ITEMS$t = [
|
|
5416
5536
|
{ color: "bg-blue-500", label: "ArrayList" },
|
|
5417
5537
|
{ color: "bg-green-500", label: "LinkedList" },
|
|
5418
5538
|
{ color: "bg-yellow-400", label: "Current element" },
|
|
@@ -5438,7 +5558,7 @@ function generateListComparisonSteps() {
|
|
|
5438
5558
|
description: `Initialize both lists with [${INITIAL_DATA.join(", ")}]`,
|
|
5439
5559
|
phase: "complete"
|
|
5440
5560
|
});
|
|
5441
|
-
for (const { op, index, value } of OPERATIONS$
|
|
5561
|
+
for (const { op, index, value } of OPERATIONS$h) {
|
|
5442
5562
|
switch (op) {
|
|
5443
5563
|
case "get": {
|
|
5444
5564
|
const idx = index;
|
|
@@ -5940,14 +6060,14 @@ const ListComparisonVisualizerComponent = ({
|
|
|
5940
6060
|
accentColor: "blue"
|
|
5941
6061
|
}
|
|
5942
6062
|
),
|
|
5943
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
6063
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$t })
|
|
5944
6064
|
] })
|
|
5945
6065
|
]
|
|
5946
6066
|
}
|
|
5947
6067
|
);
|
|
5948
6068
|
};
|
|
5949
6069
|
const ListComparisonVisualizer = React.memo(ListComparisonVisualizerComponent);
|
|
5950
|
-
const OPERATIONS$
|
|
6070
|
+
const OPERATIONS$g = [
|
|
5951
6071
|
{ op: "add", value: 50 },
|
|
5952
6072
|
{ op: "add", value: 30 },
|
|
5953
6073
|
{ op: "add", value: 70 },
|
|
@@ -5958,7 +6078,7 @@ const OPERATIONS$e = [
|
|
|
5958
6078
|
{ op: "contains", value: 40 },
|
|
5959
6079
|
{ op: "contains", value: 55 }
|
|
5960
6080
|
];
|
|
5961
|
-
const LEGEND_ITEMS$
|
|
6081
|
+
const LEGEND_ITEMS$s = [
|
|
5962
6082
|
{ color: "bg-yellow-100", label: "Path", border: "#facc15" },
|
|
5963
6083
|
{ color: "bg-green-500", label: "Current/Found" },
|
|
5964
6084
|
{ color: "bg-red-500", label: "Not found" }
|
|
@@ -6122,7 +6242,7 @@ function generateTreeSetSteps$1() {
|
|
|
6122
6242
|
path: [],
|
|
6123
6243
|
description: "Initialize empty TreeSet (Binary Search Tree)"
|
|
6124
6244
|
});
|
|
6125
|
-
for (const { op, value } of OPERATIONS$
|
|
6245
|
+
for (const { op, value } of OPERATIONS$g) {
|
|
6126
6246
|
if (op === "add") {
|
|
6127
6247
|
const path = tree ? findPath$1(tree, value) : [];
|
|
6128
6248
|
if (tree) {
|
|
@@ -6421,7 +6541,7 @@ const TreeSetInterviewVisualizerComponent = ({
|
|
|
6421
6541
|
accentColor: "green"
|
|
6422
6542
|
}
|
|
6423
6543
|
),
|
|
6424
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
6544
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$s })
|
|
6425
6545
|
] })
|
|
6426
6546
|
]
|
|
6427
6547
|
}
|
|
@@ -6429,7 +6549,7 @@ const TreeSetInterviewVisualizerComponent = ({
|
|
|
6429
6549
|
};
|
|
6430
6550
|
const TreeSetInterviewVisualizer = React.memo(TreeSetInterviewVisualizerComponent);
|
|
6431
6551
|
const INITIAL_ARRAY = [64, 34, 25, 12, 22, 11, 90];
|
|
6432
|
-
const LEGEND_ITEMS$
|
|
6552
|
+
const LEGEND_ITEMS$r = [
|
|
6433
6553
|
{ color: "bg-yellow-400", label: "Comparing" },
|
|
6434
6554
|
{ color: "bg-red-400", label: "Swapping" },
|
|
6435
6555
|
{ color: "bg-green-400", label: "Sorted" },
|
|
@@ -6752,7 +6872,7 @@ const SortingInterviewVisualizerComponent = ({
|
|
|
6752
6872
|
accentColor: "orange"
|
|
6753
6873
|
}
|
|
6754
6874
|
),
|
|
6755
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
6875
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$r })
|
|
6756
6876
|
] })
|
|
6757
6877
|
]
|
|
6758
6878
|
}
|
|
@@ -6777,7 +6897,7 @@ const EDGES$1 = [
|
|
|
6777
6897
|
{ from: "C", to: "G" },
|
|
6778
6898
|
{ from: "E", to: "F" }
|
|
6779
6899
|
];
|
|
6780
|
-
const LEGEND_ITEMS$
|
|
6900
|
+
const LEGEND_ITEMS$q = [
|
|
6781
6901
|
{ color: "bg-blue-500", label: "Current" },
|
|
6782
6902
|
{ color: "bg-green-400", label: "Visited" },
|
|
6783
6903
|
{ color: "bg-yellow-100", label: "In Queue/Stack", border: "#facc15" }
|
|
@@ -7199,7 +7319,7 @@ const GraphInterviewVisualizerComponent = ({
|
|
|
7199
7319
|
accentColor: "blue"
|
|
7200
7320
|
}
|
|
7201
7321
|
),
|
|
7202
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
7322
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$q })
|
|
7203
7323
|
] })
|
|
7204
7324
|
]
|
|
7205
7325
|
}
|
|
@@ -7208,7 +7328,7 @@ const GraphInterviewVisualizerComponent = ({
|
|
|
7208
7328
|
const GraphInterviewVisualizer = React.memo(GraphInterviewVisualizerComponent);
|
|
7209
7329
|
const BIT_ARRAY_SIZE$1 = 16;
|
|
7210
7330
|
const K_HASH_FUNCTIONS = 3;
|
|
7211
|
-
const OPERATIONS$
|
|
7331
|
+
const OPERATIONS$f = [
|
|
7212
7332
|
{ op: "add", element: "apple" },
|
|
7213
7333
|
{ op: "add", element: "banana" },
|
|
7214
7334
|
{ op: "add", element: "cherry" },
|
|
@@ -7216,7 +7336,7 @@ const OPERATIONS$d = [
|
|
|
7216
7336
|
{ op: "query", element: "grape" },
|
|
7217
7337
|
{ op: "query", element: "banana" }
|
|
7218
7338
|
];
|
|
7219
|
-
const LEGEND_ITEMS$
|
|
7339
|
+
const LEGEND_ITEMS$p = [
|
|
7220
7340
|
{ color: "bg-gray-200", label: "Bit = 0" },
|
|
7221
7341
|
{ color: "bg-purple-500", label: "Bit = 1" },
|
|
7222
7342
|
{ color: "bg-pink-400", label: "Current hash position" }
|
|
@@ -7374,7 +7494,7 @@ function generateBloomFilterSteps$1() {
|
|
|
7374
7494
|
bitArray: [...bitArray],
|
|
7375
7495
|
description: `Initialize Bloom Filter: ${BIT_ARRAY_SIZE$1} bits, ${K_HASH_FUNCTIONS} hash functions`
|
|
7376
7496
|
});
|
|
7377
|
-
for (const { op, element } of OPERATIONS$
|
|
7497
|
+
for (const { op, element } of OPERATIONS$f) {
|
|
7378
7498
|
const positions = getHashPositions(element);
|
|
7379
7499
|
if (op === "add") {
|
|
7380
7500
|
steps.push({
|
|
@@ -7564,7 +7684,7 @@ const BloomFilterInterviewVisualizerComponent = ({
|
|
|
7564
7684
|
accentColor: "purple"
|
|
7565
7685
|
}
|
|
7566
7686
|
),
|
|
7567
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
7687
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$p })
|
|
7568
7688
|
] })
|
|
7569
7689
|
]
|
|
7570
7690
|
}
|
|
@@ -7572,7 +7692,7 @@ const BloomFilterInterviewVisualizerComponent = ({
|
|
|
7572
7692
|
};
|
|
7573
7693
|
const BloomFilterInterviewVisualizer = React.memo(BloomFilterInterviewVisualizerComponent);
|
|
7574
7694
|
const ORDER$1 = 3;
|
|
7575
|
-
const OPERATIONS$
|
|
7695
|
+
const OPERATIONS$e = [
|
|
7576
7696
|
{ op: "insert", value: 10 },
|
|
7577
7697
|
{ op: "insert", value: 20 },
|
|
7578
7698
|
{ op: "insert", value: 5 },
|
|
@@ -7581,7 +7701,7 @@ const OPERATIONS$c = [
|
|
|
7581
7701
|
{ op: "search", value: 15 },
|
|
7582
7702
|
{ op: "search", value: 12 }
|
|
7583
7703
|
];
|
|
7584
|
-
const LEGEND_ITEMS$
|
|
7704
|
+
const LEGEND_ITEMS$o = [
|
|
7585
7705
|
{ color: "bg-green-400", label: "Current node" },
|
|
7586
7706
|
{ color: "bg-yellow-100", label: "Search path", border: "#facc15" },
|
|
7587
7707
|
{ color: "bg-blue-400", label: "Found/Inserted" }
|
|
@@ -7773,7 +7893,7 @@ function generateBTreeSteps$1() {
|
|
|
7773
7893
|
}
|
|
7774
7894
|
return { node };
|
|
7775
7895
|
}
|
|
7776
|
-
for (const { op, value } of OPERATIONS$
|
|
7896
|
+
for (const { op, value } of OPERATIONS$e) {
|
|
7777
7897
|
if (op === "insert") {
|
|
7778
7898
|
steps.push({
|
|
7779
7899
|
operation: "insert",
|
|
@@ -8008,14 +8128,14 @@ const BTreeInterviewVisualizerComponent = ({
|
|
|
8008
8128
|
accentColor: "green"
|
|
8009
8129
|
}
|
|
8010
8130
|
),
|
|
8011
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
8131
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$o })
|
|
8012
8132
|
] })
|
|
8013
8133
|
]
|
|
8014
8134
|
}
|
|
8015
8135
|
);
|
|
8016
8136
|
};
|
|
8017
8137
|
const BTreeInterviewVisualizer = React.memo(BTreeInterviewVisualizerComponent);
|
|
8018
|
-
const LEGEND_ITEMS$
|
|
8138
|
+
const LEGEND_ITEMS$n = [
|
|
8019
8139
|
{ color: "bg-blue-100", label: "Unvisited", border: "#60a5fa" },
|
|
8020
8140
|
{ color: "bg-yellow-400", label: "Current" },
|
|
8021
8141
|
{ color: "bg-green-400", label: "Visited" }
|
|
@@ -8409,14 +8529,14 @@ const DijkstraInterviewVisualizerComponent = ({
|
|
|
8409
8529
|
accentColor: "orange"
|
|
8410
8530
|
}
|
|
8411
8531
|
),
|
|
8412
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
8532
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$n })
|
|
8413
8533
|
] })
|
|
8414
8534
|
]
|
|
8415
8535
|
}
|
|
8416
8536
|
);
|
|
8417
8537
|
};
|
|
8418
8538
|
const DijkstraInterviewVisualizer = React.memo(DijkstraInterviewVisualizerComponent);
|
|
8419
|
-
const LEGEND_ITEMS$
|
|
8539
|
+
const LEGEND_ITEMS$m = [
|
|
8420
8540
|
{ color: "bg-gray-50", label: "Not computed", border: "#d1d5db" },
|
|
8421
8541
|
{ color: "bg-blue-100", label: "Computed" },
|
|
8422
8542
|
{ color: "bg-green-400", label: "Take item" },
|
|
@@ -8803,14 +8923,14 @@ const DPInterviewVisualizerComponent = ({
|
|
|
8803
8923
|
accentColor: "cyan"
|
|
8804
8924
|
}
|
|
8805
8925
|
),
|
|
8806
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
8926
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$m })
|
|
8807
8927
|
] })
|
|
8808
8928
|
]
|
|
8809
8929
|
}
|
|
8810
8930
|
);
|
|
8811
8931
|
};
|
|
8812
8932
|
const DPInterviewVisualizer = React.memo(DPInterviewVisualizerComponent);
|
|
8813
|
-
const LEGEND_ITEMS$
|
|
8933
|
+
const LEGEND_ITEMS$l = [
|
|
8814
8934
|
{ color: "bg-blue-500", label: "Server A" },
|
|
8815
8935
|
{ color: "bg-green-500", label: "Server B" },
|
|
8816
8936
|
{ color: "bg-purple-500", label: "Server C" },
|
|
@@ -9253,14 +9373,14 @@ const ConsistentHashingInterviewVisualizerComponent = ({
|
|
|
9253
9373
|
accentColor: "cyan"
|
|
9254
9374
|
}
|
|
9255
9375
|
),
|
|
9256
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
9376
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$l })
|
|
9257
9377
|
] })
|
|
9258
9378
|
]
|
|
9259
9379
|
}
|
|
9260
9380
|
);
|
|
9261
9381
|
};
|
|
9262
9382
|
const ConsistentHashingInterviewVisualizer = React.memo(ConsistentHashingInterviewVisualizerComponent);
|
|
9263
|
-
const LEGEND_ITEMS$
|
|
9383
|
+
const LEGEND_ITEMS$k = [
|
|
9264
9384
|
{ color: "bg-gray-400", label: "Follower" },
|
|
9265
9385
|
{ color: "bg-yellow-500", label: "Candidate" },
|
|
9266
9386
|
{ color: "bg-green-500", label: "Leader" },
|
|
@@ -9417,7 +9537,7 @@ const STATE_COLORS$1 = {
|
|
|
9417
9537
|
candidate: "bg-yellow-500",
|
|
9418
9538
|
leader: "bg-green-500"
|
|
9419
9539
|
};
|
|
9420
|
-
function cloneNodes$
|
|
9540
|
+
function cloneNodes$3(nodes) {
|
|
9421
9541
|
return nodes.map((n) => ({
|
|
9422
9542
|
...n,
|
|
9423
9543
|
log: n.log.map((e) => ({ ...e }))
|
|
@@ -9435,7 +9555,7 @@ function generateRaftSteps$1() {
|
|
|
9435
9555
|
}));
|
|
9436
9556
|
steps.push({
|
|
9437
9557
|
operation: "init",
|
|
9438
|
-
nodes: cloneNodes$
|
|
9558
|
+
nodes: cloneNodes$3(nodes),
|
|
9439
9559
|
description: `Initialize ${NODE_IDS$1.length} nodes as followers (term 0)`
|
|
9440
9560
|
});
|
|
9441
9561
|
const candidateId = "N1";
|
|
@@ -9445,7 +9565,7 @@ function generateRaftSteps$1() {
|
|
|
9445
9565
|
candidateNode.votedFor = candidateId;
|
|
9446
9566
|
steps.push({
|
|
9447
9567
|
operation: "timeout",
|
|
9448
|
-
nodes: cloneNodes$
|
|
9568
|
+
nodes: cloneNodes$3(nodes),
|
|
9449
9569
|
description: `${candidateId} timeout! Becomes candidate, term=1`,
|
|
9450
9570
|
highlightNode: candidateId
|
|
9451
9571
|
});
|
|
@@ -9457,7 +9577,7 @@ function generateRaftSteps$1() {
|
|
|
9457
9577
|
votes++;
|
|
9458
9578
|
steps.push({
|
|
9459
9579
|
operation: "vote",
|
|
9460
|
-
nodes: cloneNodes$
|
|
9580
|
+
nodes: cloneNodes$3(nodes),
|
|
9461
9581
|
description: `${node.id} votes for ${candidateId} (${votes}/${NODE_IDS$1.length})`,
|
|
9462
9582
|
highlightNode: node.id,
|
|
9463
9583
|
highlightEdge: { from: node.id, to: candidateId, type: "vote" }
|
|
@@ -9466,7 +9586,7 @@ function generateRaftSteps$1() {
|
|
|
9466
9586
|
candidateNode.state = "leader";
|
|
9467
9587
|
steps.push({
|
|
9468
9588
|
operation: "becomeLeader",
|
|
9469
|
-
nodes: cloneNodes$
|
|
9589
|
+
nodes: cloneNodes$3(nodes),
|
|
9470
9590
|
description: `${candidateId} wins election! (${votes} votes)`,
|
|
9471
9591
|
highlightNode: candidateId
|
|
9472
9592
|
});
|
|
@@ -9476,7 +9596,7 @@ function generateRaftSteps$1() {
|
|
|
9476
9596
|
}
|
|
9477
9597
|
steps.push({
|
|
9478
9598
|
operation: "heartbeat",
|
|
9479
|
-
nodes: cloneNodes$
|
|
9599
|
+
nodes: cloneNodes$3(nodes),
|
|
9480
9600
|
description: `Leader ${candidateId} sends heartbeats`,
|
|
9481
9601
|
highlightNode: candidateId,
|
|
9482
9602
|
messageType: "Heartbeat"
|
|
@@ -9486,7 +9606,7 @@ function generateRaftSteps$1() {
|
|
|
9486
9606
|
leader.log.push({ term: 1, command, committed: false });
|
|
9487
9607
|
steps.push({
|
|
9488
9608
|
operation: "replicate",
|
|
9489
|
-
nodes: cloneNodes$
|
|
9609
|
+
nodes: cloneNodes$3(nodes),
|
|
9490
9610
|
description: `Client request: "${command}"`,
|
|
9491
9611
|
highlightNode: leader.id
|
|
9492
9612
|
});
|
|
@@ -9506,7 +9626,7 @@ function generateRaftSteps$1() {
|
|
|
9506
9626
|
}
|
|
9507
9627
|
steps.push({
|
|
9508
9628
|
operation: "commit",
|
|
9509
|
-
nodes: cloneNodes$
|
|
9629
|
+
nodes: cloneNodes$3(nodes),
|
|
9510
9630
|
description: `Entry committed! (${acks} acks)`,
|
|
9511
9631
|
highlightNode: leader.id
|
|
9512
9632
|
});
|
|
@@ -9516,7 +9636,7 @@ function generateRaftSteps$1() {
|
|
|
9516
9636
|
}
|
|
9517
9637
|
steps.push({
|
|
9518
9638
|
operation: "done",
|
|
9519
|
-
nodes: cloneNodes$
|
|
9639
|
+
nodes: cloneNodes$3(nodes),
|
|
9520
9640
|
description: `✓ Consensus achieved! Leader: ${leader.id}`
|
|
9521
9641
|
});
|
|
9522
9642
|
return steps;
|
|
@@ -9720,14 +9840,14 @@ const RaftInterviewVisualizerComponent = ({
|
|
|
9720
9840
|
accentColor: "orange"
|
|
9721
9841
|
}
|
|
9722
9842
|
),
|
|
9723
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
9843
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$k })
|
|
9724
9844
|
] })
|
|
9725
9845
|
]
|
|
9726
9846
|
}
|
|
9727
9847
|
);
|
|
9728
9848
|
};
|
|
9729
9849
|
const RaftInterviewVisualizer = React.memo(RaftInterviewVisualizerComponent);
|
|
9730
|
-
const INITIAL_SIZE = 7;
|
|
9850
|
+
const INITIAL_SIZE$1 = 7;
|
|
9731
9851
|
const LOAD_FACTOR_THRESHOLD = 0.7;
|
|
9732
9852
|
const SAMPLE_KEYS = [
|
|
9733
9853
|
"apple",
|
|
@@ -9748,7 +9868,7 @@ const HASH_TABLE_CODE = [
|
|
|
9748
9868
|
" if loadFactor > threshold:",
|
|
9749
9869
|
" rehash(newSize = size * 2)"
|
|
9750
9870
|
];
|
|
9751
|
-
const LEGEND_ITEMS$
|
|
9871
|
+
const LEGEND_ITEMS$j = [
|
|
9752
9872
|
{ color: "bg-gray-50", label: "Empty", border: "#d1d5db" },
|
|
9753
9873
|
{ color: "bg-yellow-50", label: "Hashing", border: "#facc15" },
|
|
9754
9874
|
{ color: "bg-red-50", label: "Collision", border: "#f87171" },
|
|
@@ -9763,7 +9883,7 @@ function simpleHash$3(key, size) {
|
|
|
9763
9883
|
}
|
|
9764
9884
|
function generateHashSteps(keys) {
|
|
9765
9885
|
const steps = [];
|
|
9766
|
-
let buckets = Array(INITIAL_SIZE).fill(null).map(() => []);
|
|
9886
|
+
let buckets = Array(INITIAL_SIZE$1).fill(null).map(() => []);
|
|
9767
9887
|
let itemCount = 0;
|
|
9768
9888
|
steps.push({
|
|
9769
9889
|
operation: "done",
|
|
@@ -9771,7 +9891,7 @@ function generateHashSteps(keys) {
|
|
|
9771
9891
|
hashValue: 0,
|
|
9772
9892
|
bucketIndex: -1,
|
|
9773
9893
|
buckets: buckets.map((b) => [...b]),
|
|
9774
|
-
description: `Initialize hash table with ${INITIAL_SIZE} buckets (chaining)`,
|
|
9894
|
+
description: `Initialize hash table with ${INITIAL_SIZE$1} buckets (chaining)`,
|
|
9775
9895
|
codeLine: -1
|
|
9776
9896
|
});
|
|
9777
9897
|
for (const key of keys) {
|
|
@@ -10105,14 +10225,14 @@ const HashTableVisualizerComponent = ({
|
|
|
10105
10225
|
] })
|
|
10106
10226
|
}
|
|
10107
10227
|
),
|
|
10108
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
10228
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$j })
|
|
10109
10229
|
] })
|
|
10110
10230
|
]
|
|
10111
10231
|
}
|
|
10112
10232
|
);
|
|
10113
10233
|
};
|
|
10114
10234
|
const HashTableVisualizer = React.memo(HashTableVisualizerComponent);
|
|
10115
|
-
const OPERATIONS$
|
|
10235
|
+
const OPERATIONS$d = [
|
|
10116
10236
|
{ op: "addFirst", value: 10 },
|
|
10117
10237
|
{ op: "addLast", value: 20 },
|
|
10118
10238
|
{ op: "addLast", value: 30 },
|
|
@@ -10144,25 +10264,25 @@ const LINKEDLIST_CODE = [
|
|
|
10144
10264
|
" node = node.next",
|
|
10145
10265
|
" return node.value"
|
|
10146
10266
|
];
|
|
10147
|
-
const LEGEND_ITEMS$
|
|
10267
|
+
const LEGEND_ITEMS$i = [
|
|
10148
10268
|
{ color: "bg-white", label: "Node", border: "#d1d5db" },
|
|
10149
10269
|
{ color: "bg-blue-500", label: "Active" }
|
|
10150
10270
|
];
|
|
10151
|
-
let nodeIdCounter$
|
|
10271
|
+
let nodeIdCounter$2 = 0;
|
|
10152
10272
|
function generateLinkedListSteps() {
|
|
10153
10273
|
var _a, _b, _c;
|
|
10154
10274
|
const steps = [];
|
|
10155
10275
|
let nodes = [];
|
|
10156
|
-
nodeIdCounter$
|
|
10276
|
+
nodeIdCounter$2 = 0;
|
|
10157
10277
|
steps.push({
|
|
10158
10278
|
operation: "init",
|
|
10159
10279
|
nodes: [],
|
|
10160
10280
|
description: "Initialize empty LinkedList (doubly-linked). O(1) for add/remove at ends, O(n) for indexed access.",
|
|
10161
10281
|
codeLine: -1
|
|
10162
10282
|
});
|
|
10163
|
-
for (const { op, value, index } of OPERATIONS$
|
|
10283
|
+
for (const { op, value, index } of OPERATIONS$d) {
|
|
10164
10284
|
if (op === "addFirst" && value !== void 0) {
|
|
10165
|
-
const newNode = { value, id: nodeIdCounter$
|
|
10285
|
+
const newNode = { value, id: nodeIdCounter$2++ };
|
|
10166
10286
|
nodes = [newNode, ...nodes];
|
|
10167
10287
|
steps.push({
|
|
10168
10288
|
operation: "addFirst",
|
|
@@ -10174,7 +10294,7 @@ function generateLinkedListSteps() {
|
|
|
10174
10294
|
highlightNode: newNode.id
|
|
10175
10295
|
});
|
|
10176
10296
|
} else if (op === "addLast" && value !== void 0) {
|
|
10177
|
-
const newNode = { value, id: nodeIdCounter$
|
|
10297
|
+
const newNode = { value, id: nodeIdCounter$2++ };
|
|
10178
10298
|
nodes = [...nodes, newNode];
|
|
10179
10299
|
steps.push({
|
|
10180
10300
|
operation: "addLast",
|
|
@@ -10390,7 +10510,7 @@ const LinkedListVisualizerComponent = ({
|
|
|
10390
10510
|
accentColor: "blue"
|
|
10391
10511
|
}
|
|
10392
10512
|
),
|
|
10393
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
10513
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$i })
|
|
10394
10514
|
] })
|
|
10395
10515
|
]
|
|
10396
10516
|
}
|
|
@@ -10398,7 +10518,7 @@ const LinkedListVisualizerComponent = ({
|
|
|
10398
10518
|
};
|
|
10399
10519
|
const LinkedListVisualizer = React.memo(LinkedListVisualizerComponent);
|
|
10400
10520
|
const BUCKET_COUNT = 6;
|
|
10401
|
-
const OPERATIONS$
|
|
10521
|
+
const OPERATIONS$c = [
|
|
10402
10522
|
{ op: "put", key: "A", value: 10 },
|
|
10403
10523
|
{ op: "put", key: "B", value: 20 },
|
|
10404
10524
|
{ op: "put", key: "C", value: 30 },
|
|
@@ -10434,7 +10554,7 @@ const LINKEDHASHMAP_CODE = [
|
|
|
10434
10554
|
" }",
|
|
10435
10555
|
"}"
|
|
10436
10556
|
];
|
|
10437
|
-
const LEGEND_ITEMS$
|
|
10557
|
+
const LEGEND_ITEMS$h = [
|
|
10438
10558
|
{ color: "bg-blue-50", label: "Current bucket", border: "#60a5fa" },
|
|
10439
10559
|
{ color: "bg-blue-500", label: "Insert/Update" },
|
|
10440
10560
|
{ color: "bg-green-400", label: "Found" },
|
|
@@ -10463,7 +10583,7 @@ function generateLinkedHashMapSteps(accessOrder = true) {
|
|
|
10463
10583
|
codeLine: 0,
|
|
10464
10584
|
accessOrder
|
|
10465
10585
|
});
|
|
10466
|
-
for (const { op, key, value } of OPERATIONS$
|
|
10586
|
+
for (const { op, key, value } of OPERATIONS$c) {
|
|
10467
10587
|
const hash = simpleHash$2(key);
|
|
10468
10588
|
const index = hash % BUCKET_COUNT;
|
|
10469
10589
|
if (op === "put") {
|
|
@@ -10899,7 +11019,7 @@ const LinkedHashMapVisualizerComponent = ({
|
|
|
10899
11019
|
accentColor: "orange"
|
|
10900
11020
|
}
|
|
10901
11021
|
),
|
|
10902
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
11022
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$h })
|
|
10903
11023
|
] })
|
|
10904
11024
|
]
|
|
10905
11025
|
}
|
|
@@ -10907,7 +11027,7 @@ const LinkedHashMapVisualizerComponent = ({
|
|
|
10907
11027
|
};
|
|
10908
11028
|
const LinkedHashMapVisualizer = React.memo(LinkedHashMapVisualizerComponent);
|
|
10909
11029
|
const INITIAL_CAPACITY$1 = 4;
|
|
10910
|
-
const OPERATIONS$
|
|
11030
|
+
const OPERATIONS$b = [
|
|
10911
11031
|
{ op: "add", value: 10 },
|
|
10912
11032
|
{ op: "add", value: 20 },
|
|
10913
11033
|
{ op: "add", value: 30 },
|
|
@@ -10938,7 +11058,7 @@ const ARRAYLIST_CODE = [
|
|
|
10938
11058
|
" shift elements left",
|
|
10939
11059
|
" size--"
|
|
10940
11060
|
];
|
|
10941
|
-
const LEGEND_ITEMS$
|
|
11061
|
+
const LEGEND_ITEMS$g = [
|
|
10942
11062
|
{ color: "bg-white border-gray-300", label: "Used", border: "#d1d5db" },
|
|
10943
11063
|
{ color: "bg-gray-100", label: "Empty" },
|
|
10944
11064
|
{ color: "bg-orange-500", label: "Active" },
|
|
@@ -10957,7 +11077,7 @@ function generateArrayListSteps() {
|
|
|
10957
11077
|
description: `Initialize ArrayList with capacity ${capacity}. Auto-grows when full (amortized O(1) add).`,
|
|
10958
11078
|
codeLine: -1
|
|
10959
11079
|
});
|
|
10960
|
-
for (const { op, value, index } of OPERATIONS$
|
|
11080
|
+
for (const { op, value, index } of OPERATIONS$b) {
|
|
10961
11081
|
if (op === "add" && value !== void 0) {
|
|
10962
11082
|
if (size === capacity) {
|
|
10963
11083
|
const oldCapacity = capacity;
|
|
@@ -11278,7 +11398,7 @@ const ArrayListVisualizerComponent = ({
|
|
|
11278
11398
|
accentColor: "orange"
|
|
11279
11399
|
}
|
|
11280
11400
|
),
|
|
11281
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
11401
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$g })
|
|
11282
11402
|
] })
|
|
11283
11403
|
]
|
|
11284
11404
|
}
|
|
@@ -11286,7 +11406,7 @@ const ArrayListVisualizerComponent = ({
|
|
|
11286
11406
|
};
|
|
11287
11407
|
const ArrayListVisualizer = React.memo(ArrayListVisualizerComponent);
|
|
11288
11408
|
const INITIAL_CAPACITY = 8;
|
|
11289
|
-
const OPERATIONS$
|
|
11409
|
+
const OPERATIONS$a = [
|
|
11290
11410
|
{ op: "addLast", value: 10 },
|
|
11291
11411
|
{ op: "addLast", value: 20 },
|
|
11292
11412
|
{ op: "addFirst", value: 5 },
|
|
@@ -11332,7 +11452,7 @@ const ARRAYDEQUE_CODE = [
|
|
|
11332
11452
|
" }",
|
|
11333
11453
|
"}"
|
|
11334
11454
|
];
|
|
11335
|
-
const LEGEND_ITEMS$
|
|
11455
|
+
const LEGEND_ITEMS$f = [
|
|
11336
11456
|
{ color: "bg-teal-500", label: "Head pointer" },
|
|
11337
11457
|
{ color: "bg-violet-500", label: "Tail pointer" },
|
|
11338
11458
|
{ color: "bg-green-400", label: "Added element" },
|
|
@@ -11356,7 +11476,7 @@ function generateArrayDequeSteps() {
|
|
|
11356
11476
|
codeLine: 0,
|
|
11357
11477
|
variables: { head, tail, capacity, size: 0 }
|
|
11358
11478
|
});
|
|
11359
|
-
for (const { op, value } of OPERATIONS$
|
|
11479
|
+
for (const { op, value } of OPERATIONS$a) {
|
|
11360
11480
|
if (op === "addFirst" && value !== void 0) {
|
|
11361
11481
|
if (getSize() === capacity - 1) {
|
|
11362
11482
|
const oldCapacity = capacity;
|
|
@@ -11738,14 +11858,14 @@ const ArrayDequeVisualizerComponent = ({
|
|
|
11738
11858
|
accentColor: "teal"
|
|
11739
11859
|
}
|
|
11740
11860
|
),
|
|
11741
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
11861
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$f })
|
|
11742
11862
|
] })
|
|
11743
11863
|
]
|
|
11744
11864
|
}
|
|
11745
11865
|
);
|
|
11746
11866
|
};
|
|
11747
11867
|
const ArrayDequeVisualizer = React.memo(ArrayDequeVisualizerComponent);
|
|
11748
|
-
const OPERATIONS$
|
|
11868
|
+
const OPERATIONS$9 = [
|
|
11749
11869
|
{ op: "add", value: 50 },
|
|
11750
11870
|
{ op: "add", value: 30 },
|
|
11751
11871
|
{ op: "add", value: 70 },
|
|
@@ -11776,7 +11896,7 @@ const TREESET_CODE = [
|
|
|
11776
11896
|
" node = node.right",
|
|
11777
11897
|
" else: return // duplicate"
|
|
11778
11898
|
];
|
|
11779
|
-
const LEGEND_ITEMS$
|
|
11899
|
+
const LEGEND_ITEMS$e = [
|
|
11780
11900
|
{ color: "bg-yellow-100", label: "Path", border: "#facc15" },
|
|
11781
11901
|
{ color: "bg-blue-500", label: "Current/Insert" },
|
|
11782
11902
|
{ color: "bg-green-500", label: "Found" },
|
|
@@ -11825,7 +11945,7 @@ function generateTreeSetSteps() {
|
|
|
11825
11945
|
description: "Initialize empty TreeSet (Binary Search Tree). Values are stored in sorted order.",
|
|
11826
11946
|
codeLine: -1
|
|
11827
11947
|
});
|
|
11828
|
-
for (const { op, value } of OPERATIONS$
|
|
11948
|
+
for (const { op, value } of OPERATIONS$9) {
|
|
11829
11949
|
if (op === "add") {
|
|
11830
11950
|
const path = tree ? findPath(tree, value) : [];
|
|
11831
11951
|
if (tree) {
|
|
@@ -12205,7 +12325,7 @@ const TreeSetVisualizerComponent = ({
|
|
|
12205
12325
|
accentColor: "green"
|
|
12206
12326
|
}
|
|
12207
12327
|
),
|
|
12208
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
12328
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$e })
|
|
12209
12329
|
] })
|
|
12210
12330
|
]
|
|
12211
12331
|
}
|
|
@@ -12221,7 +12341,7 @@ const DAYS_OF_WEEK = [
|
|
|
12221
12341
|
"SATURDAY",
|
|
12222
12342
|
"SUNDAY"
|
|
12223
12343
|
];
|
|
12224
|
-
const OPERATIONS$
|
|
12344
|
+
const OPERATIONS$8 = [
|
|
12225
12345
|
{ op: "add", value: "MONDAY" },
|
|
12226
12346
|
{ op: "add", value: "WEDNESDAY" },
|
|
12227
12347
|
{ op: "add", value: "FRIDAY" },
|
|
@@ -12254,7 +12374,7 @@ const ENUMSET_CODE = [
|
|
|
12254
12374
|
" }",
|
|
12255
12375
|
"}"
|
|
12256
12376
|
];
|
|
12257
|
-
const LEGEND_ITEMS$
|
|
12377
|
+
const LEGEND_ITEMS$d = [
|
|
12258
12378
|
{ color: "bg-green-500", label: "Bit set (1)" },
|
|
12259
12379
|
{ color: "bg-gray-200", label: "Bit clear (0)" },
|
|
12260
12380
|
{ color: "bg-blue-500", label: "Current operation" },
|
|
@@ -12273,7 +12393,7 @@ function generateEnumSetSteps() {
|
|
|
12273
12393
|
codeLine: 1,
|
|
12274
12394
|
variables: { elements: "0b0000000" }
|
|
12275
12395
|
});
|
|
12276
|
-
for (const { op, value } of OPERATIONS$
|
|
12396
|
+
for (const { op, value } of OPERATIONS$8) {
|
|
12277
12397
|
const bitPos = getBitPosition(value);
|
|
12278
12398
|
const bitMaskForValue = 1 << bitPos;
|
|
12279
12399
|
const previousBitmask = bitmask;
|
|
@@ -12574,14 +12694,14 @@ const EnumSetVisualizerComponent = ({
|
|
|
12574
12694
|
accentColor: "lime"
|
|
12575
12695
|
}
|
|
12576
12696
|
),
|
|
12577
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
12697
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$d })
|
|
12578
12698
|
] })
|
|
12579
12699
|
]
|
|
12580
12700
|
}
|
|
12581
12701
|
);
|
|
12582
12702
|
};
|
|
12583
12703
|
const EnumSetVisualizer = React.memo(EnumSetVisualizerComponent);
|
|
12584
|
-
const OPERATIONS$
|
|
12704
|
+
const OPERATIONS$7 = [
|
|
12585
12705
|
{ op: "offer", value: 50 },
|
|
12586
12706
|
{ op: "offer", value: 30 },
|
|
12587
12707
|
{ op: "offer", value: 70 },
|
|
@@ -12610,7 +12730,7 @@ const HEAP_CODE = [
|
|
|
12610
12730
|
" siftDown(0)",
|
|
12611
12731
|
" return result"
|
|
12612
12732
|
];
|
|
12613
|
-
const LEGEND_ITEMS$
|
|
12733
|
+
const LEGEND_ITEMS$c = [
|
|
12614
12734
|
{ color: "bg-purple-100", label: "Root (min)", border: "#c4b5fd" },
|
|
12615
12735
|
{ color: "bg-purple-500", label: "Active" },
|
|
12616
12736
|
{ color: "bg-purple-200", label: "Sift Path", border: "#a78bfa" },
|
|
@@ -12626,7 +12746,7 @@ function generateHeapSteps() {
|
|
|
12626
12746
|
description: "Initialize min-heap PriorityQueue. Parent is always smaller than children. O(log n) insert/remove.",
|
|
12627
12747
|
codeLine: -1
|
|
12628
12748
|
});
|
|
12629
|
-
for (const { op, value } of OPERATIONS$
|
|
12749
|
+
for (const { op, value } of OPERATIONS$7) {
|
|
12630
12750
|
if (op === "offer" && value !== void 0) {
|
|
12631
12751
|
heap.push(value);
|
|
12632
12752
|
let idx = heap.length - 1;
|
|
@@ -13132,7 +13252,7 @@ const PriorityQueueVisualizerComponent = ({ showControls = true, showCode = true
|
|
|
13132
13252
|
accentColor: "purple"
|
|
13133
13253
|
}
|
|
13134
13254
|
),
|
|
13135
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
13255
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$c })
|
|
13136
13256
|
] })
|
|
13137
13257
|
]
|
|
13138
13258
|
}
|
|
@@ -13142,7 +13262,7 @@ const PriorityQueueVisualizer = React.memo(
|
|
|
13142
13262
|
PriorityQueueVisualizerComponent
|
|
13143
13263
|
);
|
|
13144
13264
|
const SEGMENT_COUNT = 4;
|
|
13145
|
-
const OPERATIONS$
|
|
13265
|
+
const OPERATIONS$6 = [
|
|
13146
13266
|
{ thread: "T1", op: "put", key: "Alice", value: 100 },
|
|
13147
13267
|
{ thread: "T2", op: "put", key: "Bob", value: 200 },
|
|
13148
13268
|
{ thread: "T1", op: "put", key: "Charlie", value: 150 },
|
|
@@ -13165,7 +13285,7 @@ const CHM_CODE = [
|
|
|
13165
13285
|
" // Volatile reads ensure visibility",
|
|
13166
13286
|
" return bucket.get(key)"
|
|
13167
13287
|
];
|
|
13168
|
-
const LEGEND_ITEMS$
|
|
13288
|
+
const LEGEND_ITEMS$b = [
|
|
13169
13289
|
{ color: "bg-blue-50", label: "Active segment", border: "#60a5fa" },
|
|
13170
13290
|
{ color: "bg-red-50", label: "Locked", border: "#f87171" },
|
|
13171
13291
|
{ color: "bg-gray-50", label: "Unlocked", border: "#d1d5db" }
|
|
@@ -13192,7 +13312,7 @@ function generateConcurrentSteps() {
|
|
|
13192
13312
|
codeLine: -1,
|
|
13193
13313
|
activeThreads: []
|
|
13194
13314
|
});
|
|
13195
|
-
for (const { thread, op, key, value } of OPERATIONS$
|
|
13315
|
+
for (const { thread, op, key, value } of OPERATIONS$6) {
|
|
13196
13316
|
const hash = simpleHash$1(key);
|
|
13197
13317
|
const segmentId = hash % SEGMENT_COUNT;
|
|
13198
13318
|
if (op === "put") {
|
|
@@ -13521,7 +13641,7 @@ const ConcurrentHashMapVisualizerComponent = ({ showControls = true, showCode =
|
|
|
13521
13641
|
accentColor: "red"
|
|
13522
13642
|
}
|
|
13523
13643
|
),
|
|
13524
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
13644
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$b })
|
|
13525
13645
|
] })
|
|
13526
13646
|
]
|
|
13527
13647
|
}
|
|
@@ -13531,7 +13651,7 @@ const ConcurrentHashMapVisualizer = React.memo(
|
|
|
13531
13651
|
ConcurrentHashMapVisualizerComponent
|
|
13532
13652
|
);
|
|
13533
13653
|
const CAPACITY = 3;
|
|
13534
|
-
const OPERATIONS$
|
|
13654
|
+
const OPERATIONS$5 = [
|
|
13535
13655
|
{ thread: "P1", role: "producer", value: "Task-A" },
|
|
13536
13656
|
{ thread: "P2", role: "producer", value: "Task-B" },
|
|
13537
13657
|
{ thread: "C1", role: "consumer" },
|
|
@@ -13564,7 +13684,7 @@ const BQ_CODE = [
|
|
|
13564
13684
|
" notFull.signal()",
|
|
13565
13685
|
" lock.unlock()"
|
|
13566
13686
|
];
|
|
13567
|
-
const LEGEND_ITEMS$
|
|
13687
|
+
const LEGEND_ITEMS$a = [
|
|
13568
13688
|
{ color: "bg-green-100", label: "Producer" },
|
|
13569
13689
|
{ color: "bg-blue-100", label: "Consumer" },
|
|
13570
13690
|
{ color: "bg-red-100", label: "Blocked", border: "#fca5a5" }
|
|
@@ -13586,7 +13706,7 @@ function generateBlockingQueueSteps() {
|
|
|
13586
13706
|
blockedProducers: [],
|
|
13587
13707
|
blockedConsumers: []
|
|
13588
13708
|
});
|
|
13589
|
-
for (const { thread, role, value } of OPERATIONS$
|
|
13709
|
+
for (const { thread, role, value } of OPERATIONS$5) {
|
|
13590
13710
|
if (role === "producer") {
|
|
13591
13711
|
if (queue.length >= CAPACITY) {
|
|
13592
13712
|
blockedProducers.push(thread);
|
|
@@ -13919,7 +14039,7 @@ const BlockingQueueVisualizerComponent = ({ showControls = true, showCode = true
|
|
|
13919
14039
|
accentColor: "cyan"
|
|
13920
14040
|
}
|
|
13921
14041
|
),
|
|
13922
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
14042
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$a })
|
|
13923
14043
|
] })
|
|
13924
14044
|
]
|
|
13925
14045
|
}
|
|
@@ -13928,7 +14048,7 @@ const BlockingQueueVisualizerComponent = ({ showControls = true, showCode = true
|
|
|
13928
14048
|
const BlockingQueueVisualizer = React.memo(
|
|
13929
14049
|
BlockingQueueVisualizerComponent
|
|
13930
14050
|
);
|
|
13931
|
-
const OPERATIONS$
|
|
14051
|
+
const OPERATIONS$4 = [
|
|
13932
14052
|
{ thread: "R1", op: "read" },
|
|
13933
14053
|
{ thread: "R2", op: "read" },
|
|
13934
14054
|
{ thread: "W1", op: "write", value: "D" },
|
|
@@ -13950,7 +14070,7 @@ const COW_CODE = [
|
|
|
13950
14070
|
" array = newArray // Atomic swap",
|
|
13951
14071
|
" lock.unlock()"
|
|
13952
14072
|
];
|
|
13953
|
-
const LEGEND_ITEMS$
|
|
14073
|
+
const LEGEND_ITEMS$9 = [
|
|
13954
14074
|
{ color: "bg-blue-500", label: "Reader" },
|
|
13955
14075
|
{ color: "bg-orange-500", label: "Writer" },
|
|
13956
14076
|
{ color: "bg-green-500", label: "New element" }
|
|
@@ -13968,7 +14088,7 @@ function generateCOWSteps() {
|
|
|
13968
14088
|
codeLine: -1,
|
|
13969
14089
|
activeReaders: []
|
|
13970
14090
|
});
|
|
13971
|
-
for (const { thread, op, value } of OPERATIONS$
|
|
14091
|
+
for (const { thread, op, value } of OPERATIONS$4) {
|
|
13972
14092
|
if (op === "read") {
|
|
13973
14093
|
if (!activeReaders.includes(thread)) {
|
|
13974
14094
|
activeReaders.push(thread);
|
|
@@ -14262,7 +14382,7 @@ const CopyOnWriteVisualizerComponent = ({
|
|
|
14262
14382
|
accentColor: "lime"
|
|
14263
14383
|
}
|
|
14264
14384
|
),
|
|
14265
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
14385
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$9 })
|
|
14266
14386
|
] })
|
|
14267
14387
|
]
|
|
14268
14388
|
}
|
|
@@ -14285,7 +14405,7 @@ const IMMUTABLE_CODE = [
|
|
|
14285
14405
|
"var newList = new ArrayList<>(list)",
|
|
14286
14406
|
'newList.add("D") // Works!'
|
|
14287
14407
|
];
|
|
14288
|
-
const LEGEND_ITEMS$
|
|
14408
|
+
const LEGEND_ITEMS$8 = [
|
|
14289
14409
|
{ color: "bg-violet-100", label: "Immutable", border: "#c4b5fd" },
|
|
14290
14410
|
{ color: "bg-green-100", label: "Mutable copy", border: "#86efac" },
|
|
14291
14411
|
{ color: "bg-red-100", label: "Error", border: "#fca5a5" }
|
|
@@ -14563,7 +14683,7 @@ const ImmutableCollectionsVisualizerComponent = ({ showControls = true, showCode
|
|
|
14563
14683
|
accentColor: "violet"
|
|
14564
14684
|
}
|
|
14565
14685
|
),
|
|
14566
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
14686
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$8 })
|
|
14567
14687
|
] })
|
|
14568
14688
|
]
|
|
14569
14689
|
}
|
|
@@ -14594,7 +14714,7 @@ const BLOOM_FILTER_CODE = [
|
|
|
14594
14714
|
" return False # definitely not",
|
|
14595
14715
|
" return True # probably yes"
|
|
14596
14716
|
];
|
|
14597
|
-
const LEGEND_ITEMS$
|
|
14717
|
+
const LEGEND_ITEMS$7 = [
|
|
14598
14718
|
{ color: "bg-gray-200", label: "Bit = 0" },
|
|
14599
14719
|
{ color: "bg-indigo-500", label: "Bit = 1" },
|
|
14600
14720
|
{ color: "bg-yellow-400", label: "Currently checking", border: "#fbbf24" },
|
|
@@ -14973,7 +15093,7 @@ const BloomFilterVisualizerComponent = ({
|
|
|
14973
15093
|
accentColor: "purple"
|
|
14974
15094
|
}
|
|
14975
15095
|
),
|
|
14976
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
15096
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$7 })
|
|
14977
15097
|
] })
|
|
14978
15098
|
]
|
|
14979
15099
|
}
|
|
@@ -14981,7 +15101,7 @@ const BloomFilterVisualizerComponent = ({
|
|
|
14981
15101
|
};
|
|
14982
15102
|
const BloomFilterVisualizer = React.memo(BloomFilterVisualizerComponent);
|
|
14983
15103
|
const ORDER = 3;
|
|
14984
|
-
const OPERATIONS$
|
|
15104
|
+
const OPERATIONS$3 = [
|
|
14985
15105
|
{ op: "insert", key: 10 },
|
|
14986
15106
|
{ op: "insert", key: 20 },
|
|
14987
15107
|
{ op: "insert", key: 5 },
|
|
@@ -15012,7 +15132,7 @@ const BTREE_CODE = [
|
|
|
15012
15132
|
" split root, create new root",
|
|
15013
15133
|
" insertNonFull(root, key)"
|
|
15014
15134
|
];
|
|
15015
|
-
const LEGEND_ITEMS$
|
|
15135
|
+
const LEGEND_ITEMS$6 = [
|
|
15016
15136
|
{ color: "bg-gray-100", label: "Node", border: "#d1d5db" },
|
|
15017
15137
|
{ color: "bg-yellow-200", label: "Current node", border: "#fbbf24" },
|
|
15018
15138
|
{ color: "bg-blue-500", label: "Comparing key" },
|
|
@@ -15020,11 +15140,11 @@ const LEGEND_ITEMS$4 = [
|
|
|
15020
15140
|
{ color: "bg-red-400", label: "Not found" },
|
|
15021
15141
|
{ color: "bg-purple-400", label: "Splitting" }
|
|
15022
15142
|
];
|
|
15023
|
-
let nodeIdCounter = 0;
|
|
15024
|
-
function generateNodeId() {
|
|
15025
|
-
return `node_${nodeIdCounter++}`;
|
|
15143
|
+
let nodeIdCounter$1 = 0;
|
|
15144
|
+
function generateNodeId$1() {
|
|
15145
|
+
return `node_${nodeIdCounter$1++}`;
|
|
15026
15146
|
}
|
|
15027
|
-
function cloneNodes$
|
|
15147
|
+
function cloneNodes$2(nodes) {
|
|
15028
15148
|
const cloned = /* @__PURE__ */ new Map();
|
|
15029
15149
|
nodes.forEach((node, id) => {
|
|
15030
15150
|
cloned.set(id, {
|
|
@@ -15036,11 +15156,11 @@ function cloneNodes$1(nodes) {
|
|
|
15036
15156
|
return cloned;
|
|
15037
15157
|
}
|
|
15038
15158
|
function generateBTreeSteps() {
|
|
15039
|
-
nodeIdCounter = 0;
|
|
15159
|
+
nodeIdCounter$1 = 0;
|
|
15040
15160
|
const steps = [];
|
|
15041
15161
|
let nodes = /* @__PURE__ */ new Map();
|
|
15042
15162
|
let rootId = "";
|
|
15043
|
-
const initialRoot = generateNodeId();
|
|
15163
|
+
const initialRoot = generateNodeId$1();
|
|
15044
15164
|
rootId = initialRoot;
|
|
15045
15165
|
nodes.set(initialRoot, {
|
|
15046
15166
|
id: initialRoot,
|
|
@@ -15050,18 +15170,18 @@ function generateBTreeSteps() {
|
|
|
15050
15170
|
});
|
|
15051
15171
|
steps.push({
|
|
15052
15172
|
operation: "init",
|
|
15053
|
-
nodes: cloneNodes$
|
|
15173
|
+
nodes: cloneNodes$2(nodes),
|
|
15054
15174
|
rootId,
|
|
15055
15175
|
description: `Initialize empty B-Tree of order ${ORDER} (max ${ORDER - 1} keys per node)`,
|
|
15056
15176
|
codeLine: 0,
|
|
15057
15177
|
variables: { order: ORDER, maxKeys: ORDER - 1 }
|
|
15058
15178
|
});
|
|
15059
|
-
for (const { op, key } of OPERATIONS$
|
|
15179
|
+
for (const { op, key } of OPERATIONS$3) {
|
|
15060
15180
|
if (op === "insert") {
|
|
15061
15181
|
const root = nodes.get(rootId);
|
|
15062
15182
|
steps.push({
|
|
15063
15183
|
operation: "insert",
|
|
15064
|
-
nodes: cloneNodes$
|
|
15184
|
+
nodes: cloneNodes$2(nodes),
|
|
15065
15185
|
rootId,
|
|
15066
15186
|
targetKey: key,
|
|
15067
15187
|
currentNodeId: rootId,
|
|
@@ -15078,7 +15198,7 @@ function generateBTreeSteps() {
|
|
|
15078
15198
|
insertNode2.keys.sort((a, b) => a - b);
|
|
15079
15199
|
steps.push({
|
|
15080
15200
|
operation: "insert",
|
|
15081
|
-
nodes: cloneNodes$
|
|
15201
|
+
nodes: cloneNodes$2(nodes),
|
|
15082
15202
|
rootId,
|
|
15083
15203
|
targetKey: key,
|
|
15084
15204
|
currentNodeId: rootId,
|
|
@@ -15094,7 +15214,7 @@ function generateBTreeSteps() {
|
|
|
15094
15214
|
const rightKeys = insertNode2.keys.slice(medianIndex + 1);
|
|
15095
15215
|
steps.push({
|
|
15096
15216
|
operation: "split",
|
|
15097
|
-
nodes: cloneNodes$
|
|
15217
|
+
nodes: cloneNodes$2(nodes),
|
|
15098
15218
|
rootId,
|
|
15099
15219
|
currentNodeId: rootId,
|
|
15100
15220
|
description: `Node full (${insertNode2.keys.length} keys)! Split: median=${medianKey}, left=[${leftKeys.join(",")}], right=[${rightKeys.join(",")}]`,
|
|
@@ -15107,9 +15227,9 @@ function generateBTreeSteps() {
|
|
|
15107
15227
|
rightKeys
|
|
15108
15228
|
}
|
|
15109
15229
|
});
|
|
15110
|
-
const leftId = generateNodeId();
|
|
15111
|
-
const rightId = generateNodeId();
|
|
15112
|
-
const newRootId = generateNodeId();
|
|
15230
|
+
const leftId = generateNodeId$1();
|
|
15231
|
+
const rightId = generateNodeId$1();
|
|
15232
|
+
const newRootId = generateNodeId$1();
|
|
15113
15233
|
nodes.set(leftId, {
|
|
15114
15234
|
id: leftId,
|
|
15115
15235
|
keys: leftKeys,
|
|
@@ -15132,7 +15252,7 @@ function generateBTreeSteps() {
|
|
|
15132
15252
|
rootId = newRootId;
|
|
15133
15253
|
steps.push({
|
|
15134
15254
|
operation: "split",
|
|
15135
|
-
nodes: cloneNodes$
|
|
15255
|
+
nodes: cloneNodes$2(nodes),
|
|
15136
15256
|
rootId,
|
|
15137
15257
|
description: `Split complete! New root with median ${medianKey}`,
|
|
15138
15258
|
codeLine: 17,
|
|
@@ -15142,7 +15262,7 @@ function generateBTreeSteps() {
|
|
|
15142
15262
|
} else {
|
|
15143
15263
|
steps.push({
|
|
15144
15264
|
operation: "search",
|
|
15145
|
-
nodes: cloneNodes$
|
|
15265
|
+
nodes: cloneNodes$2(nodes),
|
|
15146
15266
|
rootId,
|
|
15147
15267
|
targetKey: key,
|
|
15148
15268
|
currentNodeId: rootId,
|
|
@@ -15155,7 +15275,7 @@ function generateBTreeSteps() {
|
|
|
15155
15275
|
for (let i = 0; i < node.keys.length; i++) {
|
|
15156
15276
|
steps.push({
|
|
15157
15277
|
operation: "compare",
|
|
15158
|
-
nodes: cloneNodes$
|
|
15278
|
+
nodes: cloneNodes$2(nodes),
|
|
15159
15279
|
rootId,
|
|
15160
15280
|
targetKey: key,
|
|
15161
15281
|
currentNodeId: nodeId,
|
|
@@ -15167,7 +15287,7 @@ function generateBTreeSteps() {
|
|
|
15167
15287
|
if (key === node.keys[i]) {
|
|
15168
15288
|
steps.push({
|
|
15169
15289
|
operation: "found",
|
|
15170
|
-
nodes: cloneNodes$
|
|
15290
|
+
nodes: cloneNodes$2(nodes),
|
|
15171
15291
|
rootId,
|
|
15172
15292
|
targetKey: key,
|
|
15173
15293
|
currentNodeId: nodeId,
|
|
@@ -15182,7 +15302,7 @@ function generateBTreeSteps() {
|
|
|
15182
15302
|
if (node.isLeaf) {
|
|
15183
15303
|
steps.push({
|
|
15184
15304
|
operation: "notFound",
|
|
15185
|
-
nodes: cloneNodes$
|
|
15305
|
+
nodes: cloneNodes$2(nodes),
|
|
15186
15306
|
rootId,
|
|
15187
15307
|
targetKey: key,
|
|
15188
15308
|
currentNodeId: nodeId,
|
|
@@ -15198,7 +15318,7 @@ function generateBTreeSteps() {
|
|
|
15198
15318
|
if (node.isLeaf) {
|
|
15199
15319
|
steps.push({
|
|
15200
15320
|
operation: "notFound",
|
|
15201
|
-
nodes: cloneNodes$
|
|
15321
|
+
nodes: cloneNodes$2(nodes),
|
|
15202
15322
|
rootId,
|
|
15203
15323
|
targetKey: key,
|
|
15204
15324
|
currentNodeId: nodeId,
|
|
@@ -15217,7 +15337,7 @@ function generateBTreeSteps() {
|
|
|
15217
15337
|
nodes.forEach((node) => allKeys.push(...node.keys));
|
|
15218
15338
|
steps.push({
|
|
15219
15339
|
operation: "done",
|
|
15220
|
-
nodes: cloneNodes$
|
|
15340
|
+
nodes: cloneNodes$2(nodes),
|
|
15221
15341
|
rootId,
|
|
15222
15342
|
description: `✓ Done! B-Tree contains ${allKeys.length} keys across ${nodes.size} nodes.`,
|
|
15223
15343
|
codeLine: -1,
|
|
@@ -15402,7 +15522,7 @@ const BTreeVisualizerComponent = ({
|
|
|
15402
15522
|
] }),
|
|
15403
15523
|
/* @__PURE__ */ jsxs("div", { className: "mb-4 p-2 bg-blue-50 rounded-lg border border-blue-200", children: [
|
|
15404
15524
|
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-blue-800 mb-1", children: "Operations" }),
|
|
15405
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-blue-700 font-mono", children: OPERATIONS$
|
|
15525
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-blue-700 font-mono", children: OPERATIONS$3.map((op, i) => /* @__PURE__ */ jsxs("span", { className: "mr-2", children: [
|
|
15406
15526
|
op.op,
|
|
15407
15527
|
"(",
|
|
15408
15528
|
op.key,
|
|
@@ -15447,40 +15567,926 @@ const BTreeVisualizerComponent = ({
|
|
|
15447
15567
|
accentColor: "green"
|
|
15448
15568
|
}
|
|
15449
15569
|
),
|
|
15450
|
-
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$
|
|
15570
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$6 })
|
|
15451
15571
|
] })
|
|
15452
15572
|
]
|
|
15453
15573
|
}
|
|
15454
15574
|
);
|
|
15455
15575
|
};
|
|
15456
15576
|
const BTreeVisualizer = React.memo(BTreeVisualizerComponent);
|
|
15457
|
-
const
|
|
15458
|
-
|
|
15459
|
-
{ op: "
|
|
15460
|
-
{ op: "
|
|
15461
|
-
{ op: "
|
|
15462
|
-
{ op: "
|
|
15463
|
-
{ op: "
|
|
15464
|
-
{ op: "
|
|
15465
|
-
{ op: "
|
|
15466
|
-
{ op: "removeServer", server: "Server-B" }
|
|
15577
|
+
const OPERATIONS$2 = [
|
|
15578
|
+
{ op: "insert", word: "cat" },
|
|
15579
|
+
{ op: "insert", word: "car" },
|
|
15580
|
+
{ op: "insert", word: "card" },
|
|
15581
|
+
{ op: "insert", word: "care" },
|
|
15582
|
+
{ op: "insert", word: "dog" },
|
|
15583
|
+
{ op: "search", word: "car" },
|
|
15584
|
+
{ op: "search", word: "cab" },
|
|
15585
|
+
{ op: "prefix", word: "car" }
|
|
15467
15586
|
];
|
|
15468
|
-
const
|
|
15469
|
-
"class
|
|
15470
|
-
"
|
|
15471
|
-
"
|
|
15587
|
+
const TRIE_CODE = [
|
|
15588
|
+
"class TrieNode:",
|
|
15589
|
+
" children = {} # char -> node",
|
|
15590
|
+
" isEndOfWord = false",
|
|
15472
15591
|
"",
|
|
15473
|
-
"function
|
|
15474
|
-
"
|
|
15475
|
-
|
|
15476
|
-
"
|
|
15592
|
+
"function insert(word):",
|
|
15593
|
+
" node = root",
|
|
15594
|
+
" for char in word:",
|
|
15595
|
+
" if char not in node.children:",
|
|
15596
|
+
" node.children[char] = TrieNode()",
|
|
15597
|
+
" node = node.children[char]",
|
|
15598
|
+
" node.isEndOfWord = true",
|
|
15477
15599
|
"",
|
|
15478
|
-
"function
|
|
15479
|
-
"
|
|
15480
|
-
"
|
|
15481
|
-
"
|
|
15482
|
-
"
|
|
15483
|
-
"
|
|
15600
|
+
"function search(word):",
|
|
15601
|
+
" node = root",
|
|
15602
|
+
" for char in word:",
|
|
15603
|
+
" if char not in node.children:",
|
|
15604
|
+
" return false",
|
|
15605
|
+
" node = node.children[char]",
|
|
15606
|
+
" return node.isEndOfWord"
|
|
15607
|
+
];
|
|
15608
|
+
const LEGEND_ITEMS$5 = [
|
|
15609
|
+
{ color: "bg-gray-100", label: "Node", border: "#d1d5db" },
|
|
15610
|
+
{ color: "bg-blue-200", label: "Current", border: "#60a5fa" },
|
|
15611
|
+
{ color: "bg-green-400", label: "End of word" },
|
|
15612
|
+
{ color: "bg-yellow-200", label: "Path", border: "#fbbf24" },
|
|
15613
|
+
{ color: "bg-purple-400", label: "Match found" },
|
|
15614
|
+
{ color: "bg-red-400", label: "Not found" }
|
|
15615
|
+
];
|
|
15616
|
+
let nodeIdCounter = 0;
|
|
15617
|
+
function generateNodeId() {
|
|
15618
|
+
return `trie_${nodeIdCounter++}`;
|
|
15619
|
+
}
|
|
15620
|
+
function cloneNodes$1(nodes) {
|
|
15621
|
+
const cloned = /* @__PURE__ */ new Map();
|
|
15622
|
+
nodes.forEach((node, id) => {
|
|
15623
|
+
cloned.set(id, {
|
|
15624
|
+
...node,
|
|
15625
|
+
children: new Map(node.children)
|
|
15626
|
+
});
|
|
15627
|
+
});
|
|
15628
|
+
return cloned;
|
|
15629
|
+
}
|
|
15630
|
+
function generateTrieSteps() {
|
|
15631
|
+
nodeIdCounter = 0;
|
|
15632
|
+
const steps = [];
|
|
15633
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
15634
|
+
const rootId = generateNodeId();
|
|
15635
|
+
nodes.set(rootId, {
|
|
15636
|
+
id: rootId,
|
|
15637
|
+
char: "",
|
|
15638
|
+
children: /* @__PURE__ */ new Map(),
|
|
15639
|
+
isEndOfWord: false
|
|
15640
|
+
});
|
|
15641
|
+
steps.push({
|
|
15642
|
+
operation: "init",
|
|
15643
|
+
nodes: cloneNodes$1(nodes),
|
|
15644
|
+
rootId,
|
|
15645
|
+
description: "Initialize empty Trie with root node. Each node stores a character and links to children.",
|
|
15646
|
+
codeLine: 0
|
|
15647
|
+
});
|
|
15648
|
+
for (const { op, word } of OPERATIONS$2) {
|
|
15649
|
+
if (op === "insert") {
|
|
15650
|
+
steps.push({
|
|
15651
|
+
operation: "insert",
|
|
15652
|
+
nodes: cloneNodes$1(nodes),
|
|
15653
|
+
rootId,
|
|
15654
|
+
word,
|
|
15655
|
+
currentNodeId: rootId,
|
|
15656
|
+
description: `insert("${word}"): Start at root, traverse/create nodes for each character`,
|
|
15657
|
+
codeLine: 4,
|
|
15658
|
+
variables: { word: `"${word}"` }
|
|
15659
|
+
});
|
|
15660
|
+
let currentId = rootId;
|
|
15661
|
+
const path = [rootId];
|
|
15662
|
+
for (let i = 0; i < word.length; i++) {
|
|
15663
|
+
const char = word[i];
|
|
15664
|
+
const currentNode = nodes.get(currentId);
|
|
15665
|
+
if (currentNode.children.has(char)) {
|
|
15666
|
+
const nextId = currentNode.children.get(char);
|
|
15667
|
+
path.push(nextId);
|
|
15668
|
+
steps.push({
|
|
15669
|
+
operation: "traverse",
|
|
15670
|
+
nodes: cloneNodes$1(nodes),
|
|
15671
|
+
rootId,
|
|
15672
|
+
word,
|
|
15673
|
+
currentNodeId: nextId,
|
|
15674
|
+
highlightChar: char,
|
|
15675
|
+
highlightPath: [...path],
|
|
15676
|
+
description: `'${char}' exists → traverse to child node`,
|
|
15677
|
+
codeLine: 9,
|
|
15678
|
+
variables: { char: `'${char}'`, i, word: `"${word}"` }
|
|
15679
|
+
});
|
|
15680
|
+
currentId = nextId;
|
|
15681
|
+
} else {
|
|
15682
|
+
const newId = generateNodeId();
|
|
15683
|
+
nodes.set(newId, {
|
|
15684
|
+
id: newId,
|
|
15685
|
+
char,
|
|
15686
|
+
children: /* @__PURE__ */ new Map(),
|
|
15687
|
+
isEndOfWord: false
|
|
15688
|
+
});
|
|
15689
|
+
currentNode.children.set(char, newId);
|
|
15690
|
+
path.push(newId);
|
|
15691
|
+
steps.push({
|
|
15692
|
+
operation: "create",
|
|
15693
|
+
nodes: cloneNodes$1(nodes),
|
|
15694
|
+
rootId,
|
|
15695
|
+
word,
|
|
15696
|
+
currentNodeId: newId,
|
|
15697
|
+
highlightChar: char,
|
|
15698
|
+
highlightPath: [...path],
|
|
15699
|
+
description: `'${char}' not found → create new node`,
|
|
15700
|
+
codeLine: 8,
|
|
15701
|
+
variables: { char: `'${char}'`, i, word: `"${word}"` }
|
|
15702
|
+
});
|
|
15703
|
+
currentId = newId;
|
|
15704
|
+
}
|
|
15705
|
+
}
|
|
15706
|
+
const endNode = nodes.get(currentId);
|
|
15707
|
+
endNode.isEndOfWord = true;
|
|
15708
|
+
endNode.word = word;
|
|
15709
|
+
steps.push({
|
|
15710
|
+
operation: "markEnd",
|
|
15711
|
+
nodes: cloneNodes$1(nodes),
|
|
15712
|
+
rootId,
|
|
15713
|
+
word,
|
|
15714
|
+
currentNodeId: currentId,
|
|
15715
|
+
highlightPath: path,
|
|
15716
|
+
description: `Mark node as end of word "${word}"`,
|
|
15717
|
+
codeLine: 10,
|
|
15718
|
+
variables: { word: `"${word}"`, isEndOfWord: "true" }
|
|
15719
|
+
});
|
|
15720
|
+
} else if (op === "search") {
|
|
15721
|
+
steps.push({
|
|
15722
|
+
operation: "search",
|
|
15723
|
+
nodes: cloneNodes$1(nodes),
|
|
15724
|
+
rootId,
|
|
15725
|
+
word,
|
|
15726
|
+
currentNodeId: rootId,
|
|
15727
|
+
description: `search("${word}"): Check if word exists in Trie`,
|
|
15728
|
+
codeLine: 12,
|
|
15729
|
+
variables: { word: `"${word}"` }
|
|
15730
|
+
});
|
|
15731
|
+
let currentId = rootId;
|
|
15732
|
+
const path = [rootId];
|
|
15733
|
+
let found = true;
|
|
15734
|
+
for (let i = 0; i < word.length; i++) {
|
|
15735
|
+
const char = word[i];
|
|
15736
|
+
const currentNode = nodes.get(currentId);
|
|
15737
|
+
if (currentNode.children.has(char)) {
|
|
15738
|
+
const nextId = currentNode.children.get(char);
|
|
15739
|
+
path.push(nextId);
|
|
15740
|
+
steps.push({
|
|
15741
|
+
operation: "traverse",
|
|
15742
|
+
nodes: cloneNodes$1(nodes),
|
|
15743
|
+
rootId,
|
|
15744
|
+
word,
|
|
15745
|
+
currentNodeId: nextId,
|
|
15746
|
+
highlightChar: char,
|
|
15747
|
+
highlightPath: [...path],
|
|
15748
|
+
description: `'${char}' found → continue searching`,
|
|
15749
|
+
codeLine: 17,
|
|
15750
|
+
variables: { char: `'${char}'`, i, word: `"${word}"` }
|
|
15751
|
+
});
|
|
15752
|
+
currentId = nextId;
|
|
15753
|
+
} else {
|
|
15754
|
+
found = false;
|
|
15755
|
+
steps.push({
|
|
15756
|
+
operation: "notFound",
|
|
15757
|
+
nodes: cloneNodes$1(nodes),
|
|
15758
|
+
rootId,
|
|
15759
|
+
word,
|
|
15760
|
+
currentNodeId: currentId,
|
|
15761
|
+
highlightChar: char,
|
|
15762
|
+
highlightPath: path,
|
|
15763
|
+
description: `'${char}' not found → word "${word}" does not exist`,
|
|
15764
|
+
codeLine: 16,
|
|
15765
|
+
variables: { char: `'${char}'`, result: "false" }
|
|
15766
|
+
});
|
|
15767
|
+
break;
|
|
15768
|
+
}
|
|
15769
|
+
}
|
|
15770
|
+
if (found) {
|
|
15771
|
+
const endNode = nodes.get(currentId);
|
|
15772
|
+
if (endNode.isEndOfWord) {
|
|
15773
|
+
steps.push({
|
|
15774
|
+
operation: "found",
|
|
15775
|
+
nodes: cloneNodes$1(nodes),
|
|
15776
|
+
rootId,
|
|
15777
|
+
word,
|
|
15778
|
+
currentNodeId: currentId,
|
|
15779
|
+
highlightPath: path,
|
|
15780
|
+
description: `✓ Found! "${word}" exists in Trie`,
|
|
15781
|
+
codeLine: 18,
|
|
15782
|
+
variables: { word: `"${word}"`, result: "true" }
|
|
15783
|
+
});
|
|
15784
|
+
} else {
|
|
15785
|
+
steps.push({
|
|
15786
|
+
operation: "notFound",
|
|
15787
|
+
nodes: cloneNodes$1(nodes),
|
|
15788
|
+
rootId,
|
|
15789
|
+
word,
|
|
15790
|
+
currentNodeId: currentId,
|
|
15791
|
+
highlightPath: path,
|
|
15792
|
+
description: `Path exists but not marked as word end → "${word}" is only a prefix`,
|
|
15793
|
+
codeLine: 18,
|
|
15794
|
+
variables: { word: `"${word}"`, result: "false" }
|
|
15795
|
+
});
|
|
15796
|
+
}
|
|
15797
|
+
}
|
|
15798
|
+
} else if (op === "prefix") {
|
|
15799
|
+
steps.push({
|
|
15800
|
+
operation: "prefix",
|
|
15801
|
+
nodes: cloneNodes$1(nodes),
|
|
15802
|
+
rootId,
|
|
15803
|
+
prefix: word,
|
|
15804
|
+
currentNodeId: rootId,
|
|
15805
|
+
description: `startsWith("${word}"): Find all words with this prefix`,
|
|
15806
|
+
codeLine: 12,
|
|
15807
|
+
variables: { prefix: `"${word}"` }
|
|
15808
|
+
});
|
|
15809
|
+
let currentId = rootId;
|
|
15810
|
+
const path = [rootId];
|
|
15811
|
+
let prefixExists = true;
|
|
15812
|
+
for (let i = 0; i < word.length; i++) {
|
|
15813
|
+
const char = word[i];
|
|
15814
|
+
const currentNode = nodes.get(currentId);
|
|
15815
|
+
if (currentNode.children.has(char)) {
|
|
15816
|
+
const nextId = currentNode.children.get(char);
|
|
15817
|
+
path.push(nextId);
|
|
15818
|
+
currentId = nextId;
|
|
15819
|
+
} else {
|
|
15820
|
+
prefixExists = false;
|
|
15821
|
+
break;
|
|
15822
|
+
}
|
|
15823
|
+
}
|
|
15824
|
+
if (prefixExists) {
|
|
15825
|
+
const matchedWords = [];
|
|
15826
|
+
const collectWords = (nodeId) => {
|
|
15827
|
+
const node = nodes.get(nodeId);
|
|
15828
|
+
if (node.isEndOfWord && node.word) {
|
|
15829
|
+
matchedWords.push(node.word);
|
|
15830
|
+
}
|
|
15831
|
+
node.children.forEach((childId) => collectWords(childId));
|
|
15832
|
+
};
|
|
15833
|
+
collectWords(currentId);
|
|
15834
|
+
steps.push({
|
|
15835
|
+
operation: "found",
|
|
15836
|
+
nodes: cloneNodes$1(nodes),
|
|
15837
|
+
rootId,
|
|
15838
|
+
prefix: word,
|
|
15839
|
+
currentNodeId: currentId,
|
|
15840
|
+
highlightPath: path,
|
|
15841
|
+
matchedWords,
|
|
15842
|
+
description: `Found ${matchedWords.length} word(s) with prefix "${word}": ${matchedWords.join(", ")}`,
|
|
15843
|
+
codeLine: 18,
|
|
15844
|
+
variables: { prefix: `"${word}"`, count: matchedWords.length }
|
|
15845
|
+
});
|
|
15846
|
+
} else {
|
|
15847
|
+
steps.push({
|
|
15848
|
+
operation: "notFound",
|
|
15849
|
+
nodes: cloneNodes$1(nodes),
|
|
15850
|
+
rootId,
|
|
15851
|
+
prefix: word,
|
|
15852
|
+
highlightPath: path,
|
|
15853
|
+
description: `No words found with prefix "${word}"`,
|
|
15854
|
+
codeLine: 16,
|
|
15855
|
+
variables: { prefix: `"${word}"`, count: 0 }
|
|
15856
|
+
});
|
|
15857
|
+
}
|
|
15858
|
+
}
|
|
15859
|
+
}
|
|
15860
|
+
const allWords = [];
|
|
15861
|
+
const collectAllWords = (nodeId) => {
|
|
15862
|
+
const node = nodes.get(nodeId);
|
|
15863
|
+
if (node.isEndOfWord && node.word) {
|
|
15864
|
+
allWords.push(node.word);
|
|
15865
|
+
}
|
|
15866
|
+
node.children.forEach((childId) => collectAllWords(childId));
|
|
15867
|
+
};
|
|
15868
|
+
collectAllWords(rootId);
|
|
15869
|
+
steps.push({
|
|
15870
|
+
operation: "done",
|
|
15871
|
+
nodes: cloneNodes$1(nodes),
|
|
15872
|
+
rootId,
|
|
15873
|
+
matchedWords: allWords,
|
|
15874
|
+
description: `✓ Done! Trie contains ${allWords.length} words: ${allWords.join(", ")}`,
|
|
15875
|
+
codeLine: -1
|
|
15876
|
+
});
|
|
15877
|
+
return steps;
|
|
15878
|
+
}
|
|
15879
|
+
const TrieNodeComponent = ({ nodeId, nodes, currentNodeId, highlightPath, depth }) => {
|
|
15880
|
+
const node = nodes.get(nodeId);
|
|
15881
|
+
if (!node) return null;
|
|
15882
|
+
const isCurrent = currentNodeId === nodeId;
|
|
15883
|
+
const isInPath = highlightPath == null ? void 0 : highlightPath.includes(nodeId);
|
|
15884
|
+
const children = Array.from(node.children.entries());
|
|
15885
|
+
let nodeStyle = "border-gray-300 bg-gray-50";
|
|
15886
|
+
if (isCurrent) {
|
|
15887
|
+
nodeStyle = "border-blue-400 bg-blue-100 ring-2 ring-blue-300";
|
|
15888
|
+
} else if (isInPath) {
|
|
15889
|
+
nodeStyle = "border-yellow-400 bg-yellow-100";
|
|
15890
|
+
}
|
|
15891
|
+
if (node.isEndOfWord) {
|
|
15892
|
+
nodeStyle += " ring-2 ring-green-400";
|
|
15893
|
+
}
|
|
15894
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
15895
|
+
/* @__PURE__ */ jsx(
|
|
15896
|
+
"div",
|
|
15897
|
+
{
|
|
15898
|
+
className: `
|
|
15899
|
+
w-10 h-10 rounded-lg border-2 flex items-center justify-center
|
|
15900
|
+
text-sm font-bold transition-all duration-300
|
|
15901
|
+
${nodeStyle}
|
|
15902
|
+
`,
|
|
15903
|
+
children: node.char || "∅"
|
|
15904
|
+
}
|
|
15905
|
+
),
|
|
15906
|
+
node.isEndOfWord && /* @__PURE__ */ jsx("div", { className: "text-[9px] text-green-600 font-medium mt-0.5", children: node.word }),
|
|
15907
|
+
children.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15908
|
+
/* @__PURE__ */ jsx("div", { className: "w-0.5 h-4 bg-gray-300" }),
|
|
15909
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-2", children: children.map(([char, childId]) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
15910
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] text-gray-500 mb-1", children: char }),
|
|
15911
|
+
/* @__PURE__ */ jsx(
|
|
15912
|
+
TrieNodeComponent,
|
|
15913
|
+
{
|
|
15914
|
+
nodeId: childId,
|
|
15915
|
+
nodes,
|
|
15916
|
+
currentNodeId,
|
|
15917
|
+
highlightPath,
|
|
15918
|
+
depth: depth + 1
|
|
15919
|
+
}
|
|
15920
|
+
)
|
|
15921
|
+
] }, childId)) })
|
|
15922
|
+
] })
|
|
15923
|
+
] });
|
|
15924
|
+
};
|
|
15925
|
+
const TrieVisualizerComponent = ({
|
|
15926
|
+
showControls = true,
|
|
15927
|
+
showCode = true,
|
|
15928
|
+
className = ""
|
|
15929
|
+
}) => {
|
|
15930
|
+
const VISUALIZER_ID = "trie-visualizer";
|
|
15931
|
+
const { copyUrlToClipboard } = useUrlState({ prefix: "trie", scrollToId: VISUALIZER_ID });
|
|
15932
|
+
const generateSteps = useMemo(() => generateTrieSteps, []);
|
|
15933
|
+
const {
|
|
15934
|
+
steps,
|
|
15935
|
+
currentStep,
|
|
15936
|
+
currentStepData,
|
|
15937
|
+
isPlaying,
|
|
15938
|
+
speed,
|
|
15939
|
+
setSpeed,
|
|
15940
|
+
handlePlayPause,
|
|
15941
|
+
handleStep,
|
|
15942
|
+
handleStepBack,
|
|
15943
|
+
handleReset
|
|
15944
|
+
} = useVisualizerPlayback({
|
|
15945
|
+
generateSteps
|
|
15946
|
+
});
|
|
15947
|
+
const stepData = currentStepData || {
|
|
15948
|
+
operation: "init",
|
|
15949
|
+
nodes: /* @__PURE__ */ new Map(),
|
|
15950
|
+
rootId: "",
|
|
15951
|
+
description: ""
|
|
15952
|
+
};
|
|
15953
|
+
const getStatusVariant = () => {
|
|
15954
|
+
if (stepData.operation === "notFound") return "error";
|
|
15955
|
+
if (stepData.operation === "found" || stepData.operation === "markEnd") return "success";
|
|
15956
|
+
if (stepData.operation === "done") return "warning";
|
|
15957
|
+
return "default";
|
|
15958
|
+
};
|
|
15959
|
+
const handleShare = useCallback(async () => {
|
|
15960
|
+
return copyUrlToClipboard({ step: currentStep });
|
|
15961
|
+
}, [copyUrlToClipboard, currentStep]);
|
|
15962
|
+
return /* @__PURE__ */ jsxs(
|
|
15963
|
+
"div",
|
|
15964
|
+
{
|
|
15965
|
+
id: VISUALIZER_ID,
|
|
15966
|
+
className: `bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden ${className}`,
|
|
15967
|
+
children: [
|
|
15968
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 bg-gradient-to-r from-teal-50 to-cyan-50 border-b border-gray-200", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [
|
|
15969
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
15970
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-900", children: "Trie (Prefix Tree)" }),
|
|
15971
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
15972
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 text-xs font-medium bg-teal-100 text-teal-700 rounded", children: "Insert: O(m)" }),
|
|
15973
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 text-xs font-medium bg-cyan-100 text-cyan-700 rounded", children: "Search: O(m)" })
|
|
15974
|
+
] })
|
|
15975
|
+
] }),
|
|
15976
|
+
/* @__PURE__ */ jsx(ShareButton, { onShare: handleShare })
|
|
15977
|
+
] }) }),
|
|
15978
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: `flex gap-4 ${showCode ? "flex-col lg:flex-row" : ""}`, children: [
|
|
15979
|
+
/* @__PURE__ */ jsxs(VisualizationArea, { minHeight: 400, className: showCode ? "flex-1" : "w-full", children: [
|
|
15980
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 p-3 bg-gradient-to-r from-teal-50 to-cyan-50 rounded-lg border border-teal-200", children: [
|
|
15981
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-teal-800 mb-2", children: "🌲 Trie - Prefix Tree" }),
|
|
15982
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-teal-700 space-y-1", children: [
|
|
15983
|
+
/* @__PURE__ */ jsx("div", { children: "• Each node represents a character" }),
|
|
15984
|
+
/* @__PURE__ */ jsx("div", { children: "• Words share common prefixes (space efficient)" }),
|
|
15985
|
+
/* @__PURE__ */ jsx("div", { children: "• Perfect for autocomplete & spell checking" }),
|
|
15986
|
+
/* @__PURE__ */ jsx("div", { children: "• m = word length, n = number of words" })
|
|
15987
|
+
] })
|
|
15988
|
+
] }),
|
|
15989
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-center overflow-x-auto py-4", children: stepData.nodes.size > 0 && /* @__PURE__ */ jsx(
|
|
15990
|
+
TrieNodeComponent,
|
|
15991
|
+
{
|
|
15992
|
+
nodeId: stepData.rootId,
|
|
15993
|
+
nodes: stepData.nodes,
|
|
15994
|
+
currentNodeId: stepData.currentNodeId,
|
|
15995
|
+
highlightPath: stepData.highlightPath,
|
|
15996
|
+
depth: 0
|
|
15997
|
+
}
|
|
15998
|
+
) }),
|
|
15999
|
+
stepData.matchedWords && stepData.matchedWords.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-purple-50 rounded-lg border border-purple-200", children: [
|
|
16000
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-purple-800 mb-2", children: "Words found:" }),
|
|
16001
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: stepData.matchedWords.map((word) => /* @__PURE__ */ jsx(
|
|
16002
|
+
"span",
|
|
16003
|
+
{
|
|
16004
|
+
className: "px-2 py-1 bg-purple-100 text-purple-700 text-sm rounded font-mono",
|
|
16005
|
+
children: word
|
|
16006
|
+
},
|
|
16007
|
+
word
|
|
16008
|
+
)) })
|
|
16009
|
+
] }),
|
|
16010
|
+
/* @__PURE__ */ jsx(
|
|
16011
|
+
StatusPanel,
|
|
16012
|
+
{
|
|
16013
|
+
description: stepData.description,
|
|
16014
|
+
currentStep,
|
|
16015
|
+
totalSteps: steps.length,
|
|
16016
|
+
variant: getStatusVariant()
|
|
16017
|
+
}
|
|
16018
|
+
)
|
|
16019
|
+
] }),
|
|
16020
|
+
showCode && /* @__PURE__ */ jsxs("div", { className: "w-full lg:w-56 flex-shrink-0 space-y-2", children: [
|
|
16021
|
+
/* @__PURE__ */ jsx(
|
|
16022
|
+
CodePanel,
|
|
16023
|
+
{
|
|
16024
|
+
code: TRIE_CODE,
|
|
16025
|
+
activeLine: (currentStepData == null ? void 0 : currentStepData.codeLine) ?? -1,
|
|
16026
|
+
variables: currentStepData == null ? void 0 : currentStepData.variables
|
|
16027
|
+
}
|
|
16028
|
+
),
|
|
16029
|
+
/* @__PURE__ */ jsx(HelpPanel, {})
|
|
16030
|
+
] })
|
|
16031
|
+
] }) }),
|
|
16032
|
+
showControls && /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 bg-gray-50 border-t border-gray-200", children: [
|
|
16033
|
+
/* @__PURE__ */ jsx(
|
|
16034
|
+
ControlPanel,
|
|
16035
|
+
{
|
|
16036
|
+
isPlaying,
|
|
16037
|
+
currentStep,
|
|
16038
|
+
totalSteps: steps.length,
|
|
16039
|
+
speed,
|
|
16040
|
+
onPlayPause: handlePlayPause,
|
|
16041
|
+
onStep: handleStep,
|
|
16042
|
+
onStepBack: handleStepBack,
|
|
16043
|
+
onReset: handleReset,
|
|
16044
|
+
onSpeedChange: setSpeed,
|
|
16045
|
+
accentColor: "teal"
|
|
16046
|
+
}
|
|
16047
|
+
),
|
|
16048
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$5 })
|
|
16049
|
+
] })
|
|
16050
|
+
]
|
|
16051
|
+
}
|
|
16052
|
+
);
|
|
16053
|
+
};
|
|
16054
|
+
const TrieVisualizer = React.memo(TrieVisualizerComponent);
|
|
16055
|
+
const INITIAL_SIZE = 8;
|
|
16056
|
+
const OPERATIONS$1 = [
|
|
16057
|
+
{ op: "union", a: 0, b: 1 },
|
|
16058
|
+
{ op: "union", a: 2, b: 3 },
|
|
16059
|
+
{ op: "union", a: 4, b: 5 },
|
|
16060
|
+
{ op: "union", a: 6, b: 7 },
|
|
16061
|
+
{ op: "union", a: 0, b: 2 },
|
|
16062
|
+
{ op: "union", a: 4, b: 6 },
|
|
16063
|
+
{ op: "find", a: 3 },
|
|
16064
|
+
{ op: "connected", a: 1, b: 3 },
|
|
16065
|
+
{ op: "connected", a: 0, b: 5 },
|
|
16066
|
+
{ op: "union", a: 0, b: 4 },
|
|
16067
|
+
{ op: "connected", a: 3, b: 7 }
|
|
16068
|
+
];
|
|
16069
|
+
const UF_CODE = [
|
|
16070
|
+
"class UnionFind:",
|
|
16071
|
+
" parent[] = [0, 1, ..., n-1]",
|
|
16072
|
+
" rank[] = [0, 0, ..., 0]",
|
|
16073
|
+
"",
|
|
16074
|
+
"function find(x):",
|
|
16075
|
+
" if parent[x] != x:",
|
|
16076
|
+
" parent[x] = find(parent[x])",
|
|
16077
|
+
" # path compression",
|
|
16078
|
+
" return parent[x]",
|
|
16079
|
+
"",
|
|
16080
|
+
"function union(x, y):",
|
|
16081
|
+
" rootX = find(x)",
|
|
16082
|
+
" rootY = find(y)",
|
|
16083
|
+
" if rootX == rootY: return",
|
|
16084
|
+
" # union by rank",
|
|
16085
|
+
" if rank[rootX] < rank[rootY]:",
|
|
16086
|
+
" parent[rootX] = rootY",
|
|
16087
|
+
" else if rank[rootX] > rank[rootY]:",
|
|
16088
|
+
" parent[rootY] = rootX",
|
|
16089
|
+
" else:",
|
|
16090
|
+
" parent[rootY] = rootX",
|
|
16091
|
+
" rank[rootX] += 1"
|
|
16092
|
+
];
|
|
16093
|
+
const LEGEND_ITEMS$4 = [
|
|
16094
|
+
{ color: "bg-gray-100", label: "Element", border: "#d1d5db" },
|
|
16095
|
+
{ color: "bg-blue-200", label: "Current", border: "#60a5fa" },
|
|
16096
|
+
{ color: "bg-yellow-200", label: "Path to root", border: "#fbbf24" },
|
|
16097
|
+
{ color: "bg-green-400", label: "Root / Same set" },
|
|
16098
|
+
{ color: "bg-red-400", label: "Different sets" },
|
|
16099
|
+
{ color: "bg-purple-400", label: "Union edge" }
|
|
16100
|
+
];
|
|
16101
|
+
function cloneElements(elements) {
|
|
16102
|
+
return elements.map((el) => ({ ...el }));
|
|
16103
|
+
}
|
|
16104
|
+
function generateUnionFindSteps() {
|
|
16105
|
+
const steps = [];
|
|
16106
|
+
const elements = Array.from({ length: INITIAL_SIZE }, (_, i) => ({
|
|
16107
|
+
id: i,
|
|
16108
|
+
parent: i,
|
|
16109
|
+
rank: 0
|
|
16110
|
+
}));
|
|
16111
|
+
steps.push({
|
|
16112
|
+
operation: "init",
|
|
16113
|
+
elements: cloneElements(elements),
|
|
16114
|
+
description: `Initialize ${INITIAL_SIZE} elements. Each element is its own parent (self-loop).`,
|
|
16115
|
+
codeLine: 1,
|
|
16116
|
+
variables: { n: INITIAL_SIZE }
|
|
16117
|
+
});
|
|
16118
|
+
const find = (x, trackPath = false) => {
|
|
16119
|
+
const path = [x];
|
|
16120
|
+
let current = x;
|
|
16121
|
+
while (elements[current].parent !== current) {
|
|
16122
|
+
current = elements[current].parent;
|
|
16123
|
+
path.push(current);
|
|
16124
|
+
}
|
|
16125
|
+
if (trackPath && path.length > 2) {
|
|
16126
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
16127
|
+
elements[path[i]].parent = current;
|
|
16128
|
+
}
|
|
16129
|
+
}
|
|
16130
|
+
return { root: current, path };
|
|
16131
|
+
};
|
|
16132
|
+
for (const operation of OPERATIONS$1) {
|
|
16133
|
+
if (operation.op === "find") {
|
|
16134
|
+
const x = operation.a;
|
|
16135
|
+
steps.push({
|
|
16136
|
+
operation: "find",
|
|
16137
|
+
elements: cloneElements(elements),
|
|
16138
|
+
highlightElements: [x],
|
|
16139
|
+
description: `find(${x}): Find the root of element ${x}`,
|
|
16140
|
+
codeLine: 4,
|
|
16141
|
+
variables: { x }
|
|
16142
|
+
});
|
|
16143
|
+
const { root, path } = find(x);
|
|
16144
|
+
steps.push({
|
|
16145
|
+
operation: "find",
|
|
16146
|
+
elements: cloneElements(elements),
|
|
16147
|
+
highlightElements: [root],
|
|
16148
|
+
pathToRoot: path,
|
|
16149
|
+
description: `Path: ${path.join(" → ")}. Root is ${root}`,
|
|
16150
|
+
codeLine: 8,
|
|
16151
|
+
variables: { x, root }
|
|
16152
|
+
});
|
|
16153
|
+
if (path.length > 2) {
|
|
16154
|
+
find(x, true);
|
|
16155
|
+
steps.push({
|
|
16156
|
+
operation: "pathCompress",
|
|
16157
|
+
elements: cloneElements(elements),
|
|
16158
|
+
highlightElements: path.slice(0, -1),
|
|
16159
|
+
pathToRoot: path,
|
|
16160
|
+
description: `Path compression: All nodes on path now point directly to root ${root}`,
|
|
16161
|
+
codeLine: 6,
|
|
16162
|
+
variables: { x, root }
|
|
16163
|
+
});
|
|
16164
|
+
}
|
|
16165
|
+
} else if (operation.op === "union") {
|
|
16166
|
+
const x = operation.a;
|
|
16167
|
+
const y = operation.b;
|
|
16168
|
+
steps.push({
|
|
16169
|
+
operation: "union",
|
|
16170
|
+
elements: cloneElements(elements),
|
|
16171
|
+
highlightElements: [x, y],
|
|
16172
|
+
description: `union(${x}, ${y}): Merge sets containing ${x} and ${y}`,
|
|
16173
|
+
codeLine: 10,
|
|
16174
|
+
variables: { x, y }
|
|
16175
|
+
});
|
|
16176
|
+
const { root: rootX, path: pathX } = find(x);
|
|
16177
|
+
const { root: rootY, path: pathY } = find(y);
|
|
16178
|
+
steps.push({
|
|
16179
|
+
operation: "find",
|
|
16180
|
+
elements: cloneElements(elements),
|
|
16181
|
+
highlightElements: [rootX, rootY],
|
|
16182
|
+
pathToRoot: [...pathX, ...pathY],
|
|
16183
|
+
description: `find(${x}) = ${rootX}, find(${y}) = ${rootY}`,
|
|
16184
|
+
codeLine: 11,
|
|
16185
|
+
variables: { x, y, rootX, rootY }
|
|
16186
|
+
});
|
|
16187
|
+
if (rootX === rootY) {
|
|
16188
|
+
steps.push({
|
|
16189
|
+
operation: "sameSet",
|
|
16190
|
+
elements: cloneElements(elements),
|
|
16191
|
+
highlightElements: [rootX],
|
|
16192
|
+
description: `Already in same set! No union needed.`,
|
|
16193
|
+
codeLine: 13,
|
|
16194
|
+
variables: { rootX, rootY, "same": "true" }
|
|
16195
|
+
});
|
|
16196
|
+
} else {
|
|
16197
|
+
const rankX = elements[rootX].rank;
|
|
16198
|
+
const rankY = elements[rootY].rank;
|
|
16199
|
+
let newRoot;
|
|
16200
|
+
if (rankX < rankY) {
|
|
16201
|
+
elements[rootX].parent = rootY;
|
|
16202
|
+
newRoot = rootY;
|
|
16203
|
+
} else if (rankX > rankY) {
|
|
16204
|
+
elements[rootY].parent = rootX;
|
|
16205
|
+
newRoot = rootX;
|
|
16206
|
+
} else {
|
|
16207
|
+
elements[rootY].parent = rootX;
|
|
16208
|
+
elements[rootX].rank++;
|
|
16209
|
+
newRoot = rootX;
|
|
16210
|
+
}
|
|
16211
|
+
steps.push({
|
|
16212
|
+
operation: "unionByRank",
|
|
16213
|
+
elements: cloneElements(elements),
|
|
16214
|
+
highlightElements: [newRoot],
|
|
16215
|
+
highlightEdge: [rootX, rootY],
|
|
16216
|
+
description: `Union by rank: rank[${rootX}]=${rankX}, rank[${rootY}]=${rankY}. ${newRoot} becomes root.`,
|
|
16217
|
+
codeLine: rankX === rankY ? 20 : rankX < rankY ? 16 : 18,
|
|
16218
|
+
variables: { rootX, rootY, rankX, rankY, newRoot }
|
|
16219
|
+
});
|
|
16220
|
+
}
|
|
16221
|
+
} else if (operation.op === "connected") {
|
|
16222
|
+
const x = operation.a;
|
|
16223
|
+
const y = operation.b;
|
|
16224
|
+
steps.push({
|
|
16225
|
+
operation: "find",
|
|
16226
|
+
elements: cloneElements(elements),
|
|
16227
|
+
highlightElements: [x, y],
|
|
16228
|
+
description: `connected(${x}, ${y}): Check if ${x} and ${y} are in the same set`,
|
|
16229
|
+
codeLine: 4,
|
|
16230
|
+
variables: { x, y }
|
|
16231
|
+
});
|
|
16232
|
+
const { root: rootX, path: pathX } = find(x);
|
|
16233
|
+
const { root: rootY, path: pathY } = find(y);
|
|
16234
|
+
const connected = rootX === rootY;
|
|
16235
|
+
steps.push({
|
|
16236
|
+
operation: "sameSet",
|
|
16237
|
+
elements: cloneElements(elements),
|
|
16238
|
+
highlightElements: connected ? [rootX] : [rootX, rootY],
|
|
16239
|
+
pathToRoot: [...pathX, ...pathY],
|
|
16240
|
+
description: connected ? `✓ Yes! Both ${x} and ${y} have root ${rootX}` : `✗ No! ${x} has root ${rootX}, ${y} has root ${rootY}`,
|
|
16241
|
+
codeLine: 13,
|
|
16242
|
+
variables: { x, y, rootX, rootY, connected: connected ? "true" : "false" },
|
|
16243
|
+
queryResult: connected
|
|
16244
|
+
});
|
|
16245
|
+
}
|
|
16246
|
+
}
|
|
16247
|
+
const roots = /* @__PURE__ */ new Set();
|
|
16248
|
+
for (let i = 0; i < INITIAL_SIZE; i++) {
|
|
16249
|
+
roots.add(find(i).root);
|
|
16250
|
+
}
|
|
16251
|
+
steps.push({
|
|
16252
|
+
operation: "done",
|
|
16253
|
+
elements: cloneElements(elements),
|
|
16254
|
+
description: `✓ Done! ${roots.size} distinct set(s) remain.`,
|
|
16255
|
+
codeLine: -1,
|
|
16256
|
+
variables: { sets: roots.size }
|
|
16257
|
+
});
|
|
16258
|
+
return steps;
|
|
16259
|
+
}
|
|
16260
|
+
const UnionFindVisualizerComponent = ({
|
|
16261
|
+
showControls = true,
|
|
16262
|
+
showCode = true,
|
|
16263
|
+
className = ""
|
|
16264
|
+
}) => {
|
|
16265
|
+
const VISUALIZER_ID = "unionfind-visualizer";
|
|
16266
|
+
const { copyUrlToClipboard } = useUrlState({ prefix: "uf", scrollToId: VISUALIZER_ID });
|
|
16267
|
+
const generateSteps = useMemo(() => generateUnionFindSteps, []);
|
|
16268
|
+
const {
|
|
16269
|
+
steps,
|
|
16270
|
+
currentStep,
|
|
16271
|
+
currentStepData,
|
|
16272
|
+
isPlaying,
|
|
16273
|
+
speed,
|
|
16274
|
+
setSpeed,
|
|
16275
|
+
handlePlayPause,
|
|
16276
|
+
handleStep,
|
|
16277
|
+
handleStepBack,
|
|
16278
|
+
handleReset
|
|
16279
|
+
} = useVisualizerPlayback({
|
|
16280
|
+
generateSteps
|
|
16281
|
+
});
|
|
16282
|
+
const stepData = currentStepData || {
|
|
16283
|
+
operation: "init",
|
|
16284
|
+
elements: [],
|
|
16285
|
+
description: ""
|
|
16286
|
+
};
|
|
16287
|
+
const groups = useMemo(() => {
|
|
16288
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
16289
|
+
for (const el of stepData.elements) {
|
|
16290
|
+
let current = el.id;
|
|
16291
|
+
while (stepData.elements[current].parent !== current) {
|
|
16292
|
+
current = stepData.elements[current].parent;
|
|
16293
|
+
}
|
|
16294
|
+
const root = current;
|
|
16295
|
+
if (!groupMap.has(root)) {
|
|
16296
|
+
groupMap.set(root, []);
|
|
16297
|
+
}
|
|
16298
|
+
groupMap.get(root).push(el.id);
|
|
16299
|
+
}
|
|
16300
|
+
return groupMap;
|
|
16301
|
+
}, [stepData.elements]);
|
|
16302
|
+
const getElementStyle = (id) => {
|
|
16303
|
+
var _a, _b, _c;
|
|
16304
|
+
const isHighlighted = (_a = stepData.highlightElements) == null ? void 0 : _a.includes(id);
|
|
16305
|
+
const isInPath = (_b = stepData.pathToRoot) == null ? void 0 : _b.includes(id);
|
|
16306
|
+
const isRoot = ((_c = stepData.elements[id]) == null ? void 0 : _c.parent) === id;
|
|
16307
|
+
if (isHighlighted && isRoot) return "border-green-500 bg-green-100 ring-2 ring-green-300";
|
|
16308
|
+
if (isHighlighted) return "border-blue-400 bg-blue-100 ring-2 ring-blue-300";
|
|
16309
|
+
if (isInPath) return "border-yellow-400 bg-yellow-100";
|
|
16310
|
+
if (isRoot) return "border-green-300 bg-green-50";
|
|
16311
|
+
return "border-gray-300 bg-gray-50";
|
|
16312
|
+
};
|
|
16313
|
+
const getStatusVariant = () => {
|
|
16314
|
+
if (stepData.queryResult === false) return "error";
|
|
16315
|
+
if (stepData.queryResult === true) return "success";
|
|
16316
|
+
if (stepData.operation === "done") return "warning";
|
|
16317
|
+
if (stepData.operation === "pathCompress" || stepData.operation === "unionByRank") return "success";
|
|
16318
|
+
return "default";
|
|
16319
|
+
};
|
|
16320
|
+
const handleShare = useCallback(async () => {
|
|
16321
|
+
return copyUrlToClipboard({ step: currentStep });
|
|
16322
|
+
}, [copyUrlToClipboard, currentStep]);
|
|
16323
|
+
const groupColors = ["bg-blue-50", "bg-green-50", "bg-yellow-50", "bg-purple-50", "bg-pink-50", "bg-cyan-50", "bg-orange-50", "bg-rose-50"];
|
|
16324
|
+
return /* @__PURE__ */ jsxs(
|
|
16325
|
+
"div",
|
|
16326
|
+
{
|
|
16327
|
+
id: VISUALIZER_ID,
|
|
16328
|
+
className: `bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden ${className}`,
|
|
16329
|
+
children: [
|
|
16330
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 bg-gradient-to-r from-violet-50 to-purple-50 border-b border-gray-200", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [
|
|
16331
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
16332
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-900", children: "Union-Find (Disjoint Set)" }),
|
|
16333
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
16334
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 text-xs font-medium bg-violet-100 text-violet-700 rounded", children: "Find: O(α(n))" }),
|
|
16335
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 text-xs font-medium bg-purple-100 text-purple-700 rounded", children: "Union: O(α(n))" })
|
|
16336
|
+
] })
|
|
16337
|
+
] }),
|
|
16338
|
+
/* @__PURE__ */ jsx(ShareButton, { onShare: handleShare })
|
|
16339
|
+
] }) }),
|
|
16340
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: `flex gap-4 ${showCode ? "flex-col lg:flex-row" : ""}`, children: [
|
|
16341
|
+
/* @__PURE__ */ jsxs(VisualizationArea, { minHeight: 400, className: showCode ? "flex-1" : "w-full", children: [
|
|
16342
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 p-3 bg-gradient-to-r from-violet-50 to-purple-50 rounded-lg border border-violet-200", children: [
|
|
16343
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-violet-800 mb-2", children: "🔗 Union-Find / Disjoint Set Union (DSU)" }),
|
|
16344
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-violet-700 space-y-1", children: [
|
|
16345
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
16346
|
+
"• ",
|
|
16347
|
+
/* @__PURE__ */ jsx("strong", { children: "Path Compression" }),
|
|
16348
|
+
": Flattens tree on find()"
|
|
16349
|
+
] }),
|
|
16350
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
16351
|
+
"• ",
|
|
16352
|
+
/* @__PURE__ */ jsx("strong", { children: "Union by Rank" }),
|
|
16353
|
+
": Attach smaller tree to larger"
|
|
16354
|
+
] }),
|
|
16355
|
+
/* @__PURE__ */ jsx("div", { children: "• α(n) = inverse Ackermann, practically ≤ 4" }),
|
|
16356
|
+
/* @__PURE__ */ jsx("div", { children: "• Used in Kruskal's MST, cycle detection, networks" })
|
|
16357
|
+
] })
|
|
16358
|
+
] }),
|
|
16359
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
16360
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-700 mb-2", children: "Elements (parent pointers shown as arrows)" }),
|
|
16361
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 justify-center", children: stepData.elements.map((el) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
16362
|
+
/* @__PURE__ */ jsxs(
|
|
16363
|
+
"div",
|
|
16364
|
+
{
|
|
16365
|
+
className: `
|
|
16366
|
+
w-12 h-12 rounded-lg border-2 flex flex-col items-center justify-center
|
|
16367
|
+
text-sm font-bold transition-all duration-300
|
|
16368
|
+
${getElementStyle(el.id)}
|
|
16369
|
+
`,
|
|
16370
|
+
children: [
|
|
16371
|
+
/* @__PURE__ */ jsx("span", { children: el.id }),
|
|
16372
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[9px] text-gray-500", children: [
|
|
16373
|
+
"r:",
|
|
16374
|
+
el.rank
|
|
16375
|
+
] })
|
|
16376
|
+
]
|
|
16377
|
+
}
|
|
16378
|
+
),
|
|
16379
|
+
el.parent !== el.id && /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500 mt-1", children: [
|
|
16380
|
+
"↑ ",
|
|
16381
|
+
el.parent
|
|
16382
|
+
] }),
|
|
16383
|
+
el.parent === el.id && /* @__PURE__ */ jsx("div", { className: "text-xs text-green-600 mt-1 font-medium", children: "root" })
|
|
16384
|
+
] }, el.id)) })
|
|
16385
|
+
] }),
|
|
16386
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
16387
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm font-medium text-gray-700 mb-2", children: [
|
|
16388
|
+
"Connected Components (",
|
|
16389
|
+
groups.size,
|
|
16390
|
+
" set",
|
|
16391
|
+
groups.size !== 1 ? "s" : "",
|
|
16392
|
+
")"
|
|
16393
|
+
] }),
|
|
16394
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: Array.from(groups.entries()).map(([root, members], idx) => /* @__PURE__ */ jsxs(
|
|
16395
|
+
"div",
|
|
16396
|
+
{
|
|
16397
|
+
className: `px-3 py-2 rounded-lg border ${groupColors[idx % groupColors.length]} border-gray-300`,
|
|
16398
|
+
children: [
|
|
16399
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-600 mb-1", children: [
|
|
16400
|
+
"Root: ",
|
|
16401
|
+
root
|
|
16402
|
+
] }),
|
|
16403
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-1", children: members.sort((a, b) => a - b).map((m) => /* @__PURE__ */ jsx(
|
|
16404
|
+
"span",
|
|
16405
|
+
{
|
|
16406
|
+
className: `w-6 h-6 rounded flex items-center justify-center text-xs font-medium
|
|
16407
|
+
${m === root ? "bg-green-200 text-green-800" : "bg-white text-gray-700 border border-gray-300"}
|
|
16408
|
+
`,
|
|
16409
|
+
children: m
|
|
16410
|
+
},
|
|
16411
|
+
m
|
|
16412
|
+
)) })
|
|
16413
|
+
]
|
|
16414
|
+
},
|
|
16415
|
+
root
|
|
16416
|
+
)) })
|
|
16417
|
+
] }),
|
|
16418
|
+
/* @__PURE__ */ jsx(
|
|
16419
|
+
StatusPanel,
|
|
16420
|
+
{
|
|
16421
|
+
description: stepData.description,
|
|
16422
|
+
currentStep,
|
|
16423
|
+
totalSteps: steps.length,
|
|
16424
|
+
variant: getStatusVariant()
|
|
16425
|
+
}
|
|
16426
|
+
)
|
|
16427
|
+
] }),
|
|
16428
|
+
showCode && /* @__PURE__ */ jsxs("div", { className: "w-full lg:w-56 flex-shrink-0 space-y-2", children: [
|
|
16429
|
+
/* @__PURE__ */ jsx(
|
|
16430
|
+
CodePanel,
|
|
16431
|
+
{
|
|
16432
|
+
code: UF_CODE,
|
|
16433
|
+
activeLine: (currentStepData == null ? void 0 : currentStepData.codeLine) ?? -1,
|
|
16434
|
+
variables: currentStepData == null ? void 0 : currentStepData.variables
|
|
16435
|
+
}
|
|
16436
|
+
),
|
|
16437
|
+
/* @__PURE__ */ jsx(HelpPanel, {})
|
|
16438
|
+
] })
|
|
16439
|
+
] }) }),
|
|
16440
|
+
showControls && /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 bg-gray-50 border-t border-gray-200", children: [
|
|
16441
|
+
/* @__PURE__ */ jsx(
|
|
16442
|
+
ControlPanel,
|
|
16443
|
+
{
|
|
16444
|
+
isPlaying,
|
|
16445
|
+
currentStep,
|
|
16446
|
+
totalSteps: steps.length,
|
|
16447
|
+
speed,
|
|
16448
|
+
onPlayPause: handlePlayPause,
|
|
16449
|
+
onStep: handleStep,
|
|
16450
|
+
onStepBack: handleStepBack,
|
|
16451
|
+
onReset: handleReset,
|
|
16452
|
+
onSpeedChange: setSpeed,
|
|
16453
|
+
accentColor: "violet"
|
|
16454
|
+
}
|
|
16455
|
+
),
|
|
16456
|
+
/* @__PURE__ */ jsx(Legend, { items: LEGEND_ITEMS$4 })
|
|
16457
|
+
] })
|
|
16458
|
+
]
|
|
16459
|
+
}
|
|
16460
|
+
);
|
|
16461
|
+
};
|
|
16462
|
+
const UnionFindVisualizer = React.memo(UnionFindVisualizerComponent);
|
|
16463
|
+
const VIRTUAL_NODES_PER_SERVER = 3;
|
|
16464
|
+
const OPERATIONS = [
|
|
16465
|
+
{ op: "addServer", server: "Server-A" },
|
|
16466
|
+
{ op: "addServer", server: "Server-B" },
|
|
16467
|
+
{ op: "addServer", server: "Server-C" },
|
|
16468
|
+
{ op: "addKey", key: "user:1001" },
|
|
16469
|
+
{ op: "addKey", key: "user:1002" },
|
|
16470
|
+
{ op: "addKey", key: "session:abc" },
|
|
16471
|
+
{ op: "addKey", key: "cache:page1" },
|
|
16472
|
+
{ op: "removeServer", server: "Server-B" }
|
|
16473
|
+
];
|
|
16474
|
+
const CONSISTENT_HASHING_CODE = [
|
|
16475
|
+
"class ConsistentHash:",
|
|
16476
|
+
" ring = SortedMap() # position → server",
|
|
16477
|
+
" virtualNodes = 3 # replicas per server",
|
|
16478
|
+
"",
|
|
16479
|
+
"function addServer(server):",
|
|
16480
|
+
" for i in range(virtualNodes):",
|
|
16481
|
+
' pos = hash(server + "#" + i) % 360',
|
|
16482
|
+
" ring[pos] = server",
|
|
16483
|
+
"",
|
|
16484
|
+
"function getServer(key):",
|
|
16485
|
+
" pos = hash(key) % 360",
|
|
16486
|
+
" # Find first server with pos >= key pos",
|
|
16487
|
+
" server = ring.ceiling(pos)",
|
|
16488
|
+
" if server is null:",
|
|
16489
|
+
" server = ring.first() # wrap around",
|
|
15484
16490
|
" return server",
|
|
15485
16491
|
"",
|
|
15486
16492
|
"function removeServer(server):",
|
|
@@ -17458,15 +18464,75 @@ const SQLJoinVisualizerComponent = ({
|
|
|
17458
18464
|
}) : /* @__PURE__ */ jsx("div", { className: "text-[10px] text-gray-400 text-center py-2", children: "No results yet" })
|
|
17459
18465
|
] })
|
|
17460
18466
|
] }),
|
|
17461
|
-
/* @__PURE__ */ jsx("div", { className: "mb-4 p-3 bg-blue-50 rounded-lg", children: /* @__PURE__ */ jsxs("div", { className: "
|
|
17462
|
-
/* @__PURE__ */ jsxs("
|
|
17463
|
-
|
|
17464
|
-
|
|
18467
|
+
/* @__PURE__ */ jsx("div", { className: "mb-4 p-3 bg-gradient-to-r from-cyan-50 to-blue-50 rounded-lg border border-cyan-200", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
18468
|
+
/* @__PURE__ */ jsxs("svg", { viewBox: "0 0 100 60", className: "w-24 h-14 flex-shrink-0", children: [
|
|
18469
|
+
/* @__PURE__ */ jsx(
|
|
18470
|
+
"circle",
|
|
18471
|
+
{
|
|
18472
|
+
cx: "35",
|
|
18473
|
+
cy: "30",
|
|
18474
|
+
r: "22",
|
|
18475
|
+
fill: joinType === "left" || joinType === "full" ? "#06b6d4" : joinType === "inner" ? "transparent" : "#e5e7eb",
|
|
18476
|
+
fillOpacity: joinType === "left" || joinType === "full" ? 0.6 : joinType === "inner" ? 0 : 0.5,
|
|
18477
|
+
stroke: "#0891b2",
|
|
18478
|
+
strokeWidth: "2"
|
|
18479
|
+
}
|
|
18480
|
+
),
|
|
18481
|
+
/* @__PURE__ */ jsx(
|
|
18482
|
+
"circle",
|
|
18483
|
+
{
|
|
18484
|
+
cx: "65",
|
|
18485
|
+
cy: "30",
|
|
18486
|
+
r: "22",
|
|
18487
|
+
fill: joinType === "right" || joinType === "full" ? "#06b6d4" : joinType === "inner" ? "transparent" : "#e5e7eb",
|
|
18488
|
+
fillOpacity: joinType === "right" || joinType === "full" ? 0.6 : joinType === "inner" ? 0 : 0.5,
|
|
18489
|
+
stroke: "#0891b2",
|
|
18490
|
+
strokeWidth: "2"
|
|
18491
|
+
}
|
|
18492
|
+
),
|
|
18493
|
+
/* @__PURE__ */ jsx("clipPath", { id: "leftClip", children: /* @__PURE__ */ jsx("circle", { cx: "35", cy: "30", r: "22" }) }),
|
|
18494
|
+
/* @__PURE__ */ jsx(
|
|
18495
|
+
"circle",
|
|
18496
|
+
{
|
|
18497
|
+
cx: "65",
|
|
18498
|
+
cy: "30",
|
|
18499
|
+
r: "22",
|
|
18500
|
+
fill: "#22c55e",
|
|
18501
|
+
fillOpacity: "0.7",
|
|
18502
|
+
clipPath: "url(#leftClip)"
|
|
18503
|
+
}
|
|
18504
|
+
),
|
|
18505
|
+
/* @__PURE__ */ jsx("text", { x: "22", y: "33", fontSize: "8", fill: "#0e7490", fontWeight: "bold", children: "L" }),
|
|
18506
|
+
/* @__PURE__ */ jsx("text", { x: "74", y: "33", fontSize: "8", fill: "#0e7490", fontWeight: "bold", children: "R" })
|
|
17465
18507
|
] }),
|
|
17466
|
-
|
|
17467
|
-
|
|
17468
|
-
|
|
17469
|
-
|
|
18508
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
18509
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm font-semibold text-cyan-800 mb-1", children: [
|
|
18510
|
+
joinType.toUpperCase(),
|
|
18511
|
+
" JOIN"
|
|
18512
|
+
] }),
|
|
18513
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-cyan-700", children: [
|
|
18514
|
+
joinType === "inner" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18515
|
+
"Returns only rows with matches in ",
|
|
18516
|
+
/* @__PURE__ */ jsx("strong", { children: "both" }),
|
|
18517
|
+
" tables (green intersection)."
|
|
18518
|
+
] }),
|
|
18519
|
+
joinType === "left" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18520
|
+
"Returns ",
|
|
18521
|
+
/* @__PURE__ */ jsx("strong", { children: "all" }),
|
|
18522
|
+
" rows from left table + matching rows from right. NULL if no match."
|
|
18523
|
+
] }),
|
|
18524
|
+
joinType === "right" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18525
|
+
"Returns ",
|
|
18526
|
+
/* @__PURE__ */ jsx("strong", { children: "all" }),
|
|
18527
|
+
" rows from right table + matching rows from left. NULL if no match."
|
|
18528
|
+
] }),
|
|
18529
|
+
joinType === "full" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18530
|
+
"Returns ",
|
|
18531
|
+
/* @__PURE__ */ jsx("strong", { children: "all" }),
|
|
18532
|
+
" rows from both tables. NULL where no match exists."
|
|
18533
|
+
] })
|
|
18534
|
+
] })
|
|
18535
|
+
] })
|
|
17470
18536
|
] }) }),
|
|
17471
18537
|
/* @__PURE__ */ jsx(
|
|
17472
18538
|
StatusPanel,
|
|
@@ -17558,6 +18624,8 @@ export {
|
|
|
17558
18624
|
StepHistory,
|
|
17559
18625
|
TreeSetInterviewVisualizer,
|
|
17560
18626
|
TreeSetVisualizer,
|
|
18627
|
+
TrieVisualizer,
|
|
18628
|
+
UnionFindVisualizer,
|
|
17561
18629
|
VisualizationArea,
|
|
17562
18630
|
useInterviewMode,
|
|
17563
18631
|
useUrlState,
|