-
Notifications
You must be signed in to change notification settings - Fork 0
Implement Phase 1: Core Foundation - Data Structure Visualizer #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#pragma once | ||
|
||
#include "Operation.h" | ||
#include <nlohmann/json.hpp> | ||
#include <vector> | ||
#include <string> | ||
#include <algorithm> | ||
|
||
class DataStructure { | ||
public: | ||
virtual ~DataStructure() = default; | ||
virtual std::string getType() const = 0; | ||
virtual size_t size() const = 0; | ||
virtual bool empty() const = 0; | ||
virtual void clear() = 0; | ||
virtual nlohmann::json serialize() const = 0; | ||
virtual void deserialize(const nlohmann::json& j) = 0; | ||
virtual std::vector<Operation> getOperationHistory() const = 0; | ||
virtual void clearOperationHistory() = 0; | ||
|
||
// New methods for operation support | ||
virtual std::vector<int> getSupportedOperations() const = 0; // Returns supported operation types | ||
virtual bool supportsOperation(int operationType) const = 0; // Check if operation is supported | ||
virtual std::string getOperationName(int operationType) const = 0; // Get human-readable name | ||
|
||
// Initialize with data set (required by all structures) | ||
virtual bool initialize(const std::vector<int>& data) = 0; | ||
|
||
protected: | ||
std::vector<Operation> operationHistory; | ||
|
||
// Helper method to record operations | ||
void recordOperation(BaseOperationType baseType, int specificType, | ||
const std::vector<int>& indices, const std::vector<int>& values, | ||
const std::string& description, bool success = true) { | ||
operationHistory.emplace_back(baseType, specificType, getType(), | ||
indices, values, description, success); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
#pragma once | ||
|
||
#include "DataStructure.h" | ||
#include <vector> | ||
|
||
class DynamicArray : public DataStructure { | ||
private: | ||
std::vector<int> elements; | ||
|
||
public: | ||
DynamicArray() = default; | ||
virtual ~DynamicArray() = default; | ||
|
||
// DataStructure interface implementation | ||
std::string getType() const override { | ||
return "DynamicArray"; | ||
} | ||
|
||
size_t size() const override { | ||
return elements.size(); | ||
} | ||
|
||
bool empty() const override { | ||
return elements.empty(); | ||
} | ||
|
||
void clear() override { | ||
elements.clear(); | ||
recordOperation(BaseOperationType::CUSTOM, static_cast<int>(LinearOps::Type::DELETE), | ||
{}, {}, "Clear all elements"); | ||
} | ||
|
||
std::vector<int> getSupportedOperations() const override { | ||
return { | ||
static_cast<int>(LinearOps::Type::INIT), | ||
static_cast<int>(LinearOps::Type::INSERT), | ||
static_cast<int>(LinearOps::Type::DELETE) | ||
}; | ||
} | ||
|
||
bool supportsOperation(int operationType) const override { | ||
auto supported = getSupportedOperations(); | ||
return std::find(supported.begin(), supported.end(), operationType) != supported.end(); | ||
} | ||
|
||
std::string getOperationName(int operationType) const override { | ||
switch(static_cast<LinearOps::Type>(operationType)) { | ||
case LinearOps::Type::INIT: return "Initialize"; | ||
case LinearOps::Type::INSERT: return "Insert"; | ||
case LinearOps::Type::DELETE: return "Delete"; | ||
default: return "Unknown"; | ||
} | ||
} | ||
|
||
bool initialize(const std::vector<int>& data) override { | ||
elements = data; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot we want to initialize the array element by element, so we can visualize them |
||
recordOperation(BaseOperationType::INIT, static_cast<int>(LinearOps::Type::INIT), | ||
{}, data, "Initialize array with data"); | ||
return true; | ||
} | ||
|
||
std::vector<Operation> getOperationHistory() const override { | ||
return operationHistory; | ||
} | ||
|
||
void clearOperationHistory() override { | ||
operationHistory.clear(); | ||
} | ||
|
||
// Array-specific operations | ||
bool insert(size_t index, int value) { | ||
if (index > elements.size()) { | ||
recordOperation(BaseOperationType::INSERT, static_cast<int>(LinearOps::Type::INSERT), | ||
{static_cast<int>(index)}, {value}, | ||
"Insert failed: index out of bounds", false); | ||
return false; | ||
} | ||
|
||
elements.insert(elements.begin() + index, value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot please write a insert function that moves elements, as we want to visualise these operations as well. |
||
recordOperation(BaseOperationType::INSERT, static_cast<int>(LinearOps::Type::INSERT), | ||
{static_cast<int>(index)}, {value}, | ||
"Insert " + std::to_string(value) + " at position " + std::to_string(index)); | ||
return true; | ||
} | ||
|
||
bool deleteAt(size_t index) { | ||
if (index >= elements.size()) { | ||
recordOperation(BaseOperationType::DELETE, static_cast<int>(LinearOps::Type::DELETE), | ||
{static_cast<int>(index)}, {}, | ||
"Delete failed: index out of bounds", false); | ||
return false; | ||
} | ||
|
||
int deletedValue = elements[index]; | ||
elements.erase(elements.begin() + index); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot just like the insert function, we want to write the erase function that moves element for visualization, not the provided one in cpp vector |
||
recordOperation(BaseOperationType::DELETE, static_cast<int>(LinearOps::Type::DELETE), | ||
{static_cast<int>(index)}, {deletedValue}, | ||
"Delete element at position " + std::to_string(index)); | ||
return true; | ||
} | ||
|
||
void pushBack(int value) { | ||
insert(elements.size(), value); | ||
} | ||
|
||
// Getters for visualization | ||
const std::vector<int>& getElements() const { | ||
return elements; | ||
} | ||
|
||
int at(size_t index) const { | ||
if (index >= elements.size()) { | ||
throw std::out_of_range("Index out of bounds"); | ||
} | ||
return elements[index]; | ||
} | ||
|
||
// Serialization | ||
nlohmann::json serialize() const override { | ||
nlohmann::json j; | ||
j["metadata"]["type"] = getType(); | ||
j["metadata"]["version"] = "1.0"; | ||
j["data"]["elements"] = elements; | ||
j["data"]["size"] = elements.size(); | ||
|
||
// Serialize operations | ||
j["operations"] = nlohmann::json::array(); | ||
for (const auto& op : operationHistory) { | ||
nlohmann::json opJson; | ||
opJson["baseType"] = static_cast<int>(op.baseType); | ||
opJson["specificType"] = op.specificType; | ||
opJson["dataStructureType"] = op.dataStructureType; | ||
opJson["indices"] = op.indices; | ||
opJson["values"] = op.values; | ||
opJson["description"] = op.description; | ||
opJson["success"] = op.success; | ||
j["operations"].push_back(opJson); | ||
} | ||
|
||
return j; | ||
} | ||
|
||
void deserialize(const nlohmann::json& j) override { | ||
if (j["metadata"]["type"] != getType()) { | ||
throw std::invalid_argument("Invalid data structure type for deserialization"); | ||
} | ||
|
||
elements = j["data"]["elements"].get<std::vector<int>>(); | ||
|
||
// Deserialize operations if present | ||
if (j.contains("operations")) { | ||
operationHistory.clear(); | ||
for (const auto& opJson : j["operations"]) { | ||
operationHistory.emplace_back( | ||
static_cast<BaseOperationType>(opJson["baseType"].get<int>()), | ||
opJson["specificType"].get<int>(), | ||
opJson["dataStructureType"].get<std::string>(), | ||
opJson["indices"].get<std::vector<int>>(), | ||
opJson["values"].get<std::vector<int>>(), | ||
opJson["description"].get<std::string>(), | ||
opJson["success"].get<bool>() | ||
); | ||
} | ||
} | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#pragma once | ||
|
||
#include <vector> | ||
#include <string> | ||
#include <chrono> | ||
|
||
// Base operation types - extensible design | ||
enum class BaseOperationType { | ||
INIT, // Initialize with data set | ||
INSERT, // Generic insertion | ||
DELETE, // Generic deletion | ||
SEARCH, // Search operation | ||
CUSTOM // Custom operation (defined by subclass) | ||
}; | ||
|
||
// Data structure specific operations | ||
namespace LinearOps { | ||
enum class Type { | ||
INIT = static_cast<int>(BaseOperationType::INIT), | ||
INSERT = static_cast<int>(BaseOperationType::INSERT), | ||
DELETE = static_cast<int>(BaseOperationType::DELETE), | ||
// List-specific operations can be added here | ||
}; | ||
} | ||
|
||
namespace StackOps { | ||
enum class Type { | ||
INIT = static_cast<int>(BaseOperationType::INIT), | ||
PUSH = static_cast<int>(BaseOperationType::INSERT), // Push maps to insert | ||
POP = static_cast<int>(BaseOperationType::DELETE), // Pop maps to delete | ||
}; | ||
} | ||
|
||
namespace TreeOps { | ||
enum class Type { | ||
INIT = static_cast<int>(BaseOperationType::INIT), | ||
// Basic trees only support initialization | ||
}; | ||
} | ||
|
||
namespace BSTOps { | ||
enum class Type { | ||
INIT = static_cast<int>(BaseOperationType::INIT), | ||
SEARCH = static_cast<int>(BaseOperationType::SEARCH), | ||
INSERT = static_cast<int>(BaseOperationType::INSERT), | ||
DELETE = static_cast<int>(BaseOperationType::DELETE), | ||
}; | ||
} | ||
|
||
struct Operation { | ||
BaseOperationType baseType; // Base operation type | ||
int specificType; // Data structure specific type | ||
std::string dataStructureType; // Which data structure this applies to | ||
std::vector<int> indices; // Affected positions | ||
std::vector<int> values; // Values involved | ||
std::string description; // Human-readable description | ||
std::chrono::steady_clock::time_point time; // When operation occurred | ||
bool success; // Whether operation succeeded | ||
|
||
// Constructor for convenience | ||
Operation(BaseOperationType base, int specific, const std::string& dsType, | ||
const std::vector<int>& idx, const std::vector<int>& vals, | ||
const std::string& desc, bool succeeded = true) | ||
: baseType(base), specificType(specific), dataStructureType(dsType), | ||
indices(idx), values(vals), description(desc), | ||
time(std::chrono::steady_clock::now()), success(succeeded) {} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot add a variable to store the element index of the last operation, and render them in a different color