Compare commits

...

8 Commits

Author SHA1 Message Date
fc42369e54 Ref: #04 Simplify topic 2026-08-03 15:12:10 -04:00
7a329c639e Closes #4 2026-08-03 15:07:39 -04:00
360d2c3d21 Ref #11 fixed iteration file name 2026-07-27 23:33:00 -04:00
063f3277bb Ref #11 added some UML 2026-07-27 20:09:01 -04:00
4cb625ab9c Closes #11 2026-07-27 19:44:41 -04:00
eda3bf691a simplify template 2026-06-23 18:12:44 -04:00
233c53fb9d Closes #2 Added idea for nex one 2026-06-23 18:02:40 -04:00
cae7127193 clean up 2026-06-23 12:56:46 -04:00
17 changed files with 1384 additions and 283 deletions

View File

@@ -1,4 +1,4 @@
# Analysis #04 — Reverse Linked List: Academic Exercise # #04 — Reverse Linked List: Academic Exercise
## Problem ## Problem
@@ -253,3 +253,8 @@ It remains one of the most common classic coding interview questions.
The exercise is valuable for learning pointer manipulation. The exercise is valuable for learning pointer manipulation.
Its usefulness as a predictor of engineering ability is far less obvious. Its usefulness as a predictor of engineering ability is far less obvious.
## A More Engineering-Oriented Alternatives
If the goal is to eveluate pointer manipulation, linked-list traversal and in-place node relocation, a message queue partitioning task may provide a more realistic engineering scenario. This is idea for #05

View File

@@ -1,282 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 9.0.2, 2026-06-18T21:29:58. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{b2bd4c5a-81ed-4a10-b603-28664c066c48}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="qlonglong">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">2</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
<value type="QDateTime" key="GitLab.LastRequest"></value>
<value type="QString" key="GitLab.LinkedId"></value>
<value type="QString" key="GitLab.Project"></value>
<value type="QString" key="GitLab.Server"></value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{f6fcd567-e933-4810-b758-788e32d93b83}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/tmp/build-reverse-linked-list-Desktop-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/tmp/build-reverse-linked-list-Desktop-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/tmp/build-reverse-linked-list-Desktop-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/tmp/build-reverse-linked-list-Desktop-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/tmp/build-reverse-linked-list-Desktop-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/tmp/build-reverse-linked-list-Desktop-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="int" key="SeparateDebugInfo">0</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="QString">0</value>
<value type="QString">1</value>
<value type="QString">2</value>
<value type="QString">3</value>
<value type="QString">4</value>
<value type="QString">5</value>
<value type="QString">6</value>
<value type="QString">7</value>
<value type="QString">8</value>
<value type="QString">9</value>
<value type="QString">10</value>
<value type="QString">11</value>
<value type="QString">12</value>
<value type="QString">13</value>
<value type="QString">14</value>
</valuelist>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/deeaitch/work/3.projects/git.himro.ca/library/beyond-interviews/analysis/04-reverse-linked-list/exapmle/reverse-linked-list/reverse-linked-list.pro</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/deeaitch/work/3.projects/git.himro.ca/library/beyond-interviews/analysis/04-reverse-linked-list/exapmle/reverse-linked-list/reverse-linked-list.pro</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/tmp/build-reverse-linked-list-Desktop-Debug</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="qlonglong">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@@ -0,0 +1,74 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

View File

@@ -0,0 +1,165 @@
#include <cassert>
#include <cstdint>
#include <iostream>
struct Message {
std::uint32_t id;
bool retry;
Message *next;
};
struct MessageQueue {
Message *head;
Message *tail;
};
struct PartitionResult {
MessageQueue ready;
MessageQueue retry;
};
static void append (MessageQueue &queue, Message *message) {
assert (message != nullptr);
assert (message->next == nullptr);
if (queue.tail == nullptr) {
queue.head = message;
queue.tail = message;
return;
}
queue.tail->next = message;
queue.tail = message;
}
PartitionResult partition_messages (MessageQueue &source) {
PartitionResult result{
{nullptr, nullptr},
{nullptr, nullptr}
};
Message *current = source.head;
/*
* The source queue is consumed by this operation.
*
* Clearing it before traversal makes the ownership transfer explicit:
* every node taken from the original queue must be appended to exactly
* one of the two result queues.
*/
source.head = nullptr;
source.tail = nullptr;
while (current != nullptr) {
/*
* Save the traversal link before modifying current->next.
* The same intrusive link is reused by the destination queue.
*/
Message *next = current->next;
current->next = nullptr;
if (current->retry)
append (result.retry, current);
else
append (result.ready, current);
current = next;
}
return result;
}
static void print_queue (const char *name, const MessageQueue &queue) {
std::cout << name << ": ";
const Message *current = queue.head;
if (current == nullptr) {
std::cout << "<empty>\n";
return;
}
while (current != nullptr) {
std::cout << current->id;
if (current->next != nullptr)
std::cout << " -> ";
current = current->next;
}
std::cout << '\n';
}
static std::size_t queue_size (const MessageQueue &queue) {
std::size_t size = 0;
const Message *current = queue.head;
while (current != nullptr) {
++size;
current = current->next;
}
return size;
}
static void verify_queue (const MessageQueue &queue) {
if (queue.head == nullptr) {
assert (queue.tail == nullptr);
return;
}
assert (queue.tail != nullptr);
assert (queue.tail->next == nullptr);
const Message *current = queue.head;
while (current->next != nullptr)
current = current->next;
assert (current == queue.tail);
}
int main() {
Message a{1U, false, nullptr};
Message b{2U, true, nullptr};
Message c{3U, false, nullptr};
Message d{4U, true, nullptr};
a.next = &b;
b.next = &c;
c.next = &d;
MessageQueue outgoing{&a, &d};
std::cout << "Before partition\n";
print_queue ("Outgoing", outgoing);
const PartitionResult result = partition_messages (outgoing);
std::cout << "\nAfter partition\n";
print_queue ("Outgoing", outgoing);
print_queue ("Ready", result.ready);
print_queue ("Retry", result.retry);
verify_queue (outgoing);
verify_queue (result.ready);
verify_queue (result.retry);
assert (outgoing.head == nullptr);
assert (outgoing.tail == nullptr);
assert (result.ready.head == &a);
assert (result.ready.tail == &c);
assert (a.next == &c);
assert (c.next == nullptr);
assert (result.retry.head == &b);
assert (result.retry.tail == &d);
assert (b.next == &d);
assert (d.next == nullptr);
assert (queue_size (result.ready) + queue_size (result.retry) == 4U);
return 0;
}

View File

@@ -0,0 +1,7 @@
TEMPLATE = app
CONFIG += console c++17
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.cpp

View File

@@ -0,0 +1,25 @@
@startuml
rectangle "Traversal"
() previous
() current
() next
previous --> current
current --> next
note right
save next
detach current
append to
destination queue
continue with next
end note
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,13 @@
@startuml
[*] --> Outgoing
Outgoing --> Sent : success
Outgoing --> Retry : retry == true
Retry --> Outgoing : rescheduled
Sent --> [*]
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,17 @@
@startuml
rectangle "Outgoing Queue" as Q1
rectangle "Ready Queue" as Q2
rectangle "Retry Queue" as Q3
Q1 --> Q2 : move node
Q1 --> Q3 : move node
note bottom
Every message belongs
to exactly one queue.
end note
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,39 @@
@startuml
left to right direction
skinparam linetype ortho
skinparam shadowing false
package "Before Partition" {
rectangle "A\nretry = false" as A
rectangle "B\nretry = true" as B
rectangle "C\nretry = false" as C
rectangle "D\nretry = true" as D
A --> B : next
B --> C : next
C --> D : next
}
package "After Partition" {
package "Ready Queue" {
rectangle "A" as ReadyA
rectangle "C" as ReadyC
ReadyA --> ReadyC : next
}
package "Retry Queue" {
rectangle "B" as RetryB
rectangle "D" as RetryD
RetryB --> RetryD : next
}
}
A ..> ReadyA : move
B ..> RetryB : move
C ..> ReadyC : move
D ..> RetryD : move
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1,20 @@
@startuml
participant Queue
participant Algorithm
participant Ready
participant Retry
Queue -> Algorithm : get next node
alt retry == false
Algorithm -> Ready : append(node)
else retry == true
Algorithm -> Retry : append(node)
end
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,276 @@
# #05 — Message Queue Partitioning
## Problem
A communication subsystem maintains a singly linked intrusive queue of outgoing messages.
Each message contains a transmission identifier, a retry flag, and a pointer to the next message:
```cpp
struct Message {
uint32_t id;
bool retry;
Message* next;
};
```
After a transmission attempt, some messages may need to be retried.
Partition the original queue into two separate queues:
- the ready queue, containing messages that do not require another transmission attempt;
- the retry queue, containing messages marked for retry.
The relative order of messages must be preserved in both queues.
### Requirements
- no dynamic memory allocation;
- no copying of messages;
- reuse the existing list nodes;
- preserve the original order in both resulting queues;
- process the queue in `O(n)` time.
## Example
### Input
```text
A -> B -> C -> D
```
```text
A: retry = false
B: retry = true
C: retry = false
D: retry = true
```
### Result
Ready queue
```text
A -> C
```
Retry queue
```text
B -> D
```
The original queue is consumed during the operation, and every message must belong to exactly one of the two resulting queues.
---
# Analysis
At first glance, this looks like another linked list interview problem.
Traverse the list.
Check a flag.
Split the nodes into two lists.
Complexity: **O(n)**.
Simple.
Except this is one of those rare cases where the interview version is surprisingly close to a real engineering task.
The interesting part is not the algorithm.
The interesting part is what the algorithm is actually modifying.
---
## This Is Not About Two Lists
Each node already exists.
```cpp
struct Message {
uint32_t id;
bool retry;
Message* next;
};
```
No objects are created.
No objects are destroyed.
No messages are copied.
Only ownership changes.
The original outgoing queue disappears and every message becomes part of exactly one new queue.
That small detail changes the entire nature of the problem.
---
## The Real Challenge
The boolean itself is trivial.
```cpp
retry == true
```
is simply a classification.
The difficult part is maintaining the integrity of two intrusive queues while consuming a third one.
Every processed node must satisfy one invariant:
- belong to exactly one queue;
- never be lost;
- never appear twice;
- never keep stale links into the original list.
Most bugs are not caused by the condition.
They are caused by pointer manipulation.
---
## Why Saving `next` Matters
The same pointer is used for two completely different purposes.
During traversal:
```text
current -> next
```
is how we reach the remaining nodes.
After insertion into a new queue:
```text
current -> next
```
becomes part of another list.
If the original `next` pointer is overwritten before it is saved, the remainder of the queue is simply lost.
This is one of the classic pitfalls of intrusive containers.
---
## Stable Partition
The requirements also say:
> preserve order
That sounds minor.
It isn't.
Appending to the head would produce:
```text
D -> B
```
instead of
```text
B -> D
```
The algorithm therefore performs a **stable partition**, preserving FIFO order in both resulting queues.
In a communication subsystem this is often essential because later messages may depend on earlier ones.
---
## Why No Allocation?
The requirement
```text
no allocation
```
isn't there to make the problem harder.
It reflects reality.
Communication stacks, embedded systems and real-time software often avoid dynamic allocation while processing packets or messages.
The messages already exist.
Only their position inside processing queues changes.
---
## Hidden Engineering Questions
The implementation itself is small.
The engineering questions are not.
For example:
- Who owns the original queue after partitioning?
- Can another thread append messages during the operation?
- Can an interrupt modify the queue?
- What happens if the queue is already corrupted?
- Can a message belong to multiple intrusive containers?
- Should retry count also be updated?
- Is there exponential backoff before retrying?
None of these appear in the problem statement.
All of them appear in production systems.
---
## What This Problem Actually Tests
Unlike many linked list exercises, this one evaluates something genuinely useful.
It tests whether a developer can safely manipulate ownership using pointers while preserving structural invariants.
The algorithm itself is almost secondary.
Correctness is everything.
---
## Key Takeaway
This is one of the few interview-style linked list problems that has a direct equivalent in production software.
Not because splitting a list is inherently interesting.
But because communication stacks, schedulers, networking software and embedded systems continuously reorganize intrusive queues exactly like this.
The interview version removes most of the surrounding system.
The engineering version adds ownership, invariants, concurrency and failure handling.
The pointer operations remain almost identical.
The responsibility does not.
---
## Project Perspective
> Exists in real engineering?
**Yes. Frequently.**
> Exists in interview form?
**Yes.**
One of the rare cases where the interview problem remains close to its real-world counterpart.

View File

@@ -0,0 +1,742 @@
# #06 — The Myth of Clean Input
## Problem
Most algorithmic problems begin in roughly the same way:
> Given an array.
> Given a linked list.
> Given a vector of temperatures.
For example:
```cpp
std::vector<float> temperatures;
```
The task may then ask us to find the maximum value, calculate an average, remove duplicates, or perform some other operation.
The input is assumed to:
- already exist;
- have the expected type;
- use the expected representation;
- be free from corruption;
- contain values within valid ranges;
- be ready for use.
This assumption feels so natural that it is rarely noticed.
In real engineering, however, a clean object is rarely the starting point.
More often, it is the final result of a long processing chain.
---
## Typical Interview Thinking
Consider a simple problem:
> Find the maximum temperature.
The candidate receives a ready-to-use container:
```cpp
std::vector<float> temperatures;
```
The solution may be almost trivial:
```cpp
const auto max_temperature =
std::max_element(temperatures.begin(), temperatures.end());
```
From there, the discussion may cover:
- computational complexity;
- memory usage;
- empty input handling;
- use of the standard library;
- possible optimizations.
All attention is focused on the algorithm.
But one question is almost never asked:
> Where did this `std::vector<float>` come from?
Who received the original data?
Who verified the frame?
Who determined the format?
Who converted the raw sensor value into degrees?
Who decided that the resulting number could be trusted?
The interview starts with an already prepared object.
A real system must first create that object.
---
## Clean Input Is Not a Starting Condition
Consider a temperature received from a remote sensor.
At the business-logic level, it may look like this:
```text
23.7 °C
```
But the system may have originally received nothing more than a sequence of bytes:
```text
02 03 00 1A FF 7C 91 4D
```
Before those bytes can become a temperature, the data must pass through several stages:
```text
UART / CAN / TCP
Receive raw bytes
Extract a complete frame
Validate frame length
Verify checksum
Check protocol version
Deserialize the payload
Identify the data source
Convert byte order
Apply scale and offset
Check the physical range
Normalized temperature
Append to std::vector<float>
Find the maximum value
```
The maximum-value algorithm is the final step and may be the simplest step in the entire chain.
---
## The Cost of Clean Input
This declaration looks simple:
```cpp
std::vector<float> temperatures;
```
But that simplicity was not free.
Before business logic can receive such a container, the system may already have had to:
- receive data from an external source;
- identify message boundaries;
- detect corruption;
- check protocol-version compatibility;
- parse a binary representation;
- handle byte order;
- apply scaling;
- recognize reserved or unavailable values;
- verify physical plausibility;
- convert the result into an internal representation.
The algorithm may require one line of code.
The infrastructure that makes that line meaningful may require thousands.
This is why business logic is often simpler than the code surrounding it.
The formula may already be known.
The algorithm may already exist in the standard library.
The real work is ensuring that the transition from the external world to the object expected by that algorithm is correct.
---
## Normalization: Valid Data Can Still Be Incomparable
Not every input problem is caused by corruption.
Sometimes each value is individually valid, but several values represent the same entity in different forms.
Consider a task that searches for duplicate vehicle identifiers.
An interview problem may provide this input:
```text
ABC123
ABC123
ABC123
```
The result is obvious.
A real system may receive:
```text
ABC123
abc123
ABC-123
ABC123
ABC123
```
At the string level, these values are different.
A duplicate-search algorithm will correctly report that they do not match.
At the domain level, however, they may represent the same object.
Before searching for duplicates, the system must define a canonical representation:
- Is character case significant?
- Are separators meaningful?
- Should surrounding whitespace be removed?
- Which characters are permitted?
- Is there a canonical format?
- What should happen when the input is ambiguous?
After normalization, the values may become:
```text
ABC123
ABC123
ABC123
ABC123
ABC123
```
Only now is the duplicate-search algorithm solving the correct problem.
Before normalization, it was comparing representations rather than entities.
---
## Normalization Is Part of the System Model
Normalization can look like little more than string cleanup.
In reality, it expresses domain rules.
For example:
- letter case may be irrelevant for one identifier and essential for another;
- two file paths may refer to the same object while remaining different strings;
- phone numbers may contain different country prefixes and formatting;
- MAC addresses may use different separators;
- timestamps may use different time zones;
- measurements may use different units;
- sensor values may require calibration.
Normalization does not merely answer:
> How should this string be modified?
It answers:
> What does this system consider to be the same value?
There is no universal normalization procedure.
It depends on the protocol, the contract, and the meaning of the data.
---
## Not All Well-Formed Data Is Usable
Successfully parsing a message does not mean that its contents are safe to use.
Consider these temperatures:
```text
23.7
-40.0
65535
NaN
-273.15
```
Every one of these values may be successfully represented as a number.
Their meanings, however, are very different.
`23.7` may be a normal measurement.
`-40.0` may be valid, or it may be the lower limit of the sensor.
`65535` may represent unavailable data.
`NaN` may have appeared after an invalid calculation.
`-273.15` is numerically valid, but for a particular device it almost certainly indicates a problem.
This reveals several different levels of correctness.
### Structural Correctness
Can the message be parsed?
### Protocol Correctness
Does it conform to the expected protocol format and version?
### Numeric Correctness
Can the value be represented using the required type?
### Semantic Correctness
Does the value make sense within the domain?
Syntactic validity does not guarantee meaningful data.
---
## From Raw Data to a Trusted Object
It is useful to view input handling not as one large validation step, but as a sequence of state transitions.
```text
Raw bytes
Framed data
Integrity-checked frame
Parsed message
Normalized values
Semantically valid object
Trusted domain object
Business algorithm
```
At every stage, the system gains stronger guarantees.
Raw bytes promise almost nothing.
After framing, the message boundaries are known.
After integrity checks, there is evidence that the data was not accidentally corrupted.
After parsing, typed fields exist.
After normalization, values use a consistent representation.
After semantic checks, the object is known to be acceptable within the domain.
Only then can the data be treated as trusted by a particular layer of the system.
---
## Trust Must Be Local
This leads to an important architectural principle:
> Data is not simply trusted or untrusted.
It is trusted only relative to a particular contract.
A transport layer may guarantee that:
- the complete frame was received;
- the checksum matches;
- the length is valid.
It cannot guarantee that a temperature is physically meaningful.
A parser may guarantee that:
- message fields were extracted successfully;
- their sizes and types match the protocol.
It cannot determine whether the value is acceptable for a specific device model.
That responsibility belongs to another layer.
Each layer checks its own invariants and passes a stronger representation to the next one.
---
## Every Layer Earns Trust for the Next One
A clean object at an algorithm boundary is not a magical property of the data.
It is the result of fulfilled contracts.
One layer says:
> I verified the integrity of the frame.
The next says:
> I parsed the message according to a supported protocol version.
The next says:
> I converted the values into the system's internal units.
The next says:
> I confirmed that the object is valid within this domain.
Only then may the business logic assume:
> This is a valid temperature.
That assumption is not justified because the external world is reliable.
It is justified because the previous layers did their work.
---
## Why Not Validate Everything Everywhere?
Distrusting input can lead to another bad conclusion:
> Every function should repeat every validation step.
That creates different problems:
- duplicated logic;
- contradictory checks;
- unclear ownership of responsibilities;
- more complex code;
- uncertainty about which guarantees already exist.
A function that accepts raw bytes must not assume that they are safe.
A function that accepts an object which can only be created after successful verification does not need to repeat the entire process.
Good architecture does not eliminate trust.
It makes the origin of trust explicit.
---
## Types as Evidence of the Path Already Taken
One practical way to express this is to use different types for different processing stages.
Instead of passing the same generic object through the entire system, the stages can be represented explicitly:
```cpp
struct RawFrame;
struct VerifiedFrame;
struct ParsedTemperatureMessage;
struct NormalizedTemperature;
```
The interfaces can then reflect the available guarantees:
```cpp
std::optional<VerifiedFrame>
verify_frame(const RawFrame& frame);
std::optional<ParsedTemperatureMessage>
parse_message(const VerifiedFrame& frame);
std::optional<NormalizedTemperature>
normalize_temperature(const ParsedTemperatureMessage& message);
```
Business logic can accept only the normalized value:
```cpp
void process_temperature(const NormalizedTemperature& temperature);
```
This does not make the data absolutely true.
It makes the stages already completed explicit.
It also prevents raw input from being passed accidentally into code that expects a verified object.
---
## What Happens When Processing Fails?
Data evolution does not always end with a valid business object.
Every stage may reject the input:
```text
Raw bytes
├── incomplete frame
├── unsupported version
├── invalid checksum
├── malformed payload
├── unknown sensor
├── invalid scaling
├── out-of-range value
└── valid temperature
```
This introduces another major part of real engineering that is usually absent from algorithmic problems:
- the message may need to be discarded;
- the failure may need to be logged;
- a diagnostic counter may need to be incremented;
- the source may need to be reconnected;
- the system may need to use the last known valid value;
- a component may enter a degraded mode;
- the failure may affect safety-related behavior.
In an interview problem, an invalid value is often just an edge case.
In a real system, it may trigger an entirely different operating scenario.
---
## The Algorithm Still Matters
None of this means that algorithms are unimportant.
Once data has been converted into a correct internal model, the algorithm still needs to be:
- correct;
- efficient;
- understandable;
- appropriate for the system constraints.
The problem begins when solving a task over a clean array is treated as a complete model of engineering ability.
An algorithm solves a problem under a set of assumptions.
An engineer must also:
- discover those assumptions;
- determine whether they are valid;
- assign responsibility for enforcing them;
- express the resulting guarantees in interfaces and architecture.
---
## What This Actually Tests
A problem over a ready-made container can test:
- knowledge of data structures;
- algorithmic reasoning;
- complexity analysis;
- recognition of known patterns;
- implementation accuracy.
It says much less about a candidate's ability to:
- work with external data sources;
- design trust boundaries;
- parse protocols;
- normalize representations;
- define semantic validity;
- design diagnostics;
- handle partial failures;
- create reliable contracts between layers.
This does not make the algorithmic task useless.
It only limits what can reasonably be concluded from it.
---
## Where the Interview Ends and Engineering Begins
An interview problem often presents this model:
```text
Clean input
Algorithm
Result
```
A real system often looks more like this:
```text
Physical world
Electrical signal
Raw bytes
Transport framing
Integrity checks
Protocol parsing
Version handling
Normalization
Semantic validation
Domain object
Algorithm
System decision
```
The interview begins near the end of this chain.
Engineering is responsible for the entire chain.
---
## The Evolution of Data
We can now return to the temperature example.
Initially, the system does not have a temperature.
It has a signal.
Then it has bytes.
Then a frame.
Then a message.
Then a raw sensor value.
Then a value expressed in physical units.
Then a normalized and semantically valid measurement.
Only after all of that does a number appear that can safely be stored in a container and passed to an algorithm.
```text
Signal
Bytes
Frame
Verified frame
Parsed message
Raw sensor value
Calibrated value
Normalized temperature
Trusted domain object
std::vector<float>
std::max_element
```
The maximum-search algorithm does not create the meaning of the data.
It consumes meaning that was established by the previous layers.
---
## Key Takeaway
Clean input is not a starting point.
It is an engineering result.
It exists only after the system has:
- identified the structure of the data;
- verified its integrity;
- understood its format;
- converted it into a canonical representation;
- checked its meaning;
- established a contract of trust.
The engineer's first question is therefore not:
> How do I process this array?
It is:
> Why can this array be trusted?
And then:
> Which layer guarantees that?
---
## Project Perspective
> Exists in real engineering?
> Yes. Almost constantly.
> Exists in interview form?
> Usually not. Most of the data journey is hidden by the problem statement.
Algorithmic tasks are useful for evaluating work on already prepared structures.
But they usually begin with a result that a real system still has to produce.
That is the myth of clean input:
> Data does not arrive ready for the algorithm.
> Engineering makes it ready.