Untitled
unknown
plain_text
2 years ago
8.7 kB
11
Indexable
#pragma once
#include "cstring"
#include "sstream"
#include "string"
#include "exception"
#include "vector"
#include "queue"
namespace cs251
{
typedef int handle;
class invalid_handle : public std::runtime_error {
public: invalid_handle() : std::runtime_error("Invalid handle!") {} };
class recycled_node : public std::runtime_error {
public: recycled_node() : std::runtime_error("Node is recycled!") {} };
template<typename tree_node_data>
class tree_node {
//Friend class grant private access to another class.
template<typename tnd>
friend class tree;
//TODO: You may add private members/methods here.
/**
* The handle of current node, should be the index of current node within the vector array in tree.
*/
handle m_handle = -1;
/**
* Whether the node is recycled.
*/
bool m_recycled = true;
/**
* The content of the node.
*/
tree_node_data m_data = {};
/**
* The handle of the parent node.
*/
handle m_parentHandle = -1;
/**
* List of handles to all children.
*/
std::vector<handle> m_childrenHandles{};
public:
/**
* \brief Retrieve the data for this node.
* \return The modifiable reference to the node's data.
*/
tree_node_data& ref_data();
/**
* \brief Check if the node is recycled.
* \return Whether this node is recycled or not.
*/
bool is_recycled() const;
/**
* \brief Get the handle of this node.
* \return The handle of this node.
*/
handle get_handle() const;
/**
* \brief Get the handle of this node's parent.
* \return The handle of this node's parent.
*/
handle get_parent_handle() const;
/**
* \brief Get the list of handles of this node's children.
* \return The list of handles of this node's children.
*/
const std::vector<handle>& peek_children_handles() const;
};
template<typename tree_node_data>
class tree
{
public:
/**
* \brief The constructor of the tree class. You should allocate the root node here.
*/
tree();
/**
* \brief Allocate a new node as root from pool or creating a new one.
* \return The handle of the new node.
*/
handle allocate(handle parentHandle);
/**
* \brief Remove (recycle) a node. Remove all descendent nodes.
* \param handle The handle of the target node to be removed.
*/
void remove(handle handle);
/**
* \brief Attach a node to another node as its child.
* \param targetHandle The handle of the target node as child.
* \param parentHandle The handle of the parent node.
*/
void set_parent(handle targetHandle, handle parentHandle);
/**
* \brief Return the constant reference to the list of nodes.
* \return Constant reference to the list of nodes.
*/
const std::vector<tree_node<tree_node_data>>& peek_nodes() const;
/**
* \brief Retrieve the node with its handle.
* \param handle The handle of the target node.
* \return The reference to the node.
*/
tree_node<tree_node_data>& ref_node(handle handle);
private:
//TODO: You may add private members/methods here.
/**
* The storage for all nodes.
*/
std::vector<tree_node<tree_node_data>> m_nodes {};
/**
* The pool that keep track of the recycled nodes.
*/
std::queue<handle> m_node_pool {};
};
template <typename tree_node_data>
tree_node_data& tree_node<tree_node_data>::ref_data()
{
//TODO: Remove following line and add your implementation here.
if (m_recycled) {
throw recycled_node();
}
return m_data;
}
template <typename tree_node_data>
bool tree_node<tree_node_data>::is_recycled() const
{
//TODO: Remove following line and add your implementation here.
return m_recycled;
}
template <typename tree_node_data>
handle tree_node<tree_node_data>::get_handle() const
{
//TODO: Remove following line and add your implementation here.
return m_handle;
}
template <typename tree_node_data>
handle tree_node<tree_node_data>::get_parent_handle() const
{
//TODO: Remove following line and add your implementation here.
if (m_recycled)
throw recycled_node();
return m_parentHandle;
}
template <typename tree_node_data>
const std::vector<handle>& tree_node<tree_node_data>::peek_children_handles() const
{
//TODO: Remove following line and add your implementation here.
if (m_recycled)
throw recycled_node();
return m_childrenHandles;
}
template <typename tree_node_data>
tree<tree_node_data>::tree()
{
//TODO: Remove following line and add your implementation here.
tree_node<tree_node_data> root_node;
root_node.m_handle = 0;
root_node.m_recycled = false;
root_node.m_parentHandle = -1;
m_nodes.emplace_back(root_node);
}
template <typename tree_node_data>
handle tree<tree_node_data>::allocate(handle parentHandle)
{
//TODO: Remove following line and add your implementation here.
if (parentHandle >= m_nodes.size() ) {
throw invalid_handle();
}
if (m_nodes[parentHandle].m_recycled) {
throw recycled_node();
}
handle newNodeHandle;
if (!m_node_pool.empty()) {
newNodeHandle = m_node_pool.front();
m_node_pool.pop();
m_nodes[newNodeHandle].m_recycled = false;
} else {
newNodeHandle = m_nodes.size();
tree_node<tree_node_data> node_new;
node_new.m_handle = newNodeHandle;
node_new.m_recycled = false;
node_new.m_parentHandle = parentHandle;
m_nodes.emplace_back(node_new);
}
auto& newNode = m_nodes[newNodeHandle];
newNode.m_handle = newNodeHandle;
newNode.m_parentHandle = parentHandle;
m_nodes[parentHandle].m_childrenHandles.emplace_back(newNodeHandle);
return newNodeHandle;
}
template <typename tree_node_data>
void tree<tree_node_data>::remove(const handle handle)
{
//TODO: Remove following line and add your implementation here.
if (handle < 0 || handle >= m_nodes.size())
throw invalid_handle();
if (m_nodes[handle].m_recycled)
throw recycled_node();
auto child_handle = m_nodes[handle].m_childrenHandles;
for (int i=0; i < child_handle.size(); i++) {
remove(m_nodes[handle].m_childrenHandles[0]);
}
if (m_nodes[handle].m_parentHandle >= 0 || m_nodes[handle].m_parentHandle < m_nodes.size()) { // Check if not root
auto& parent = m_nodes[m_nodes[handle].m_parentHandle];
auto& children = parent.m_childrenHandles;
if(parent.m_recycled) {
throw recycled_node();
}
// Find and remove the handle from parent's children array
for (size_t i = 0; i < children.size(); i++) {
if (children[i] == handle) {
children.erase(children.begin() + i);
break; // Stop searching once handle is found and removed
}
}
}
m_nodes[handle].m_recycled = true;
m_node_pool.push(handle);
m_nodes[handle].m_parentHandle = -1; // No parent
}
template <typename tree_node_data>
void tree<tree_node_data>::set_parent(const handle targetHandle, const handle parentHandle)
{
//TODO: Remove following line and add your implementation here.
if (targetHandle >= m_nodes.size() || parentHandle >= m_nodes.size()) {
throw invalid_handle();
}
if (m_nodes[targetHandle].m_recycled || m_nodes[parentHandle].m_recycled) {
throw recycled_node();
}
if (m_nodes[targetHandle].m_parentHandle == parentHandle) {
return;
}
auto& parentChildren = m_nodes[m_nodes[targetHandle].m_parentHandle].m_childrenHandles;
bool found = false;
if (m_nodes[targetHandle].m_parentHandle != -1) {
for (size_t i = 0; i < parentChildren.size(); ++i) {
if (parentChildren[i] == targetHandle) {
parentChildren.erase(parentChildren.begin() + i);
found = true;
break;
}
}
}
if (!found) {
m_nodes[parentHandle].m_childrenHandles.push_back(targetHandle);
}
m_nodes[targetHandle].m_parentHandle = parentHandle;
//check if parentHandle has targetHandle as kid, if not, then push targethandle to children array of parentHandle
}
template <typename tree_node_data>
const std::vector<tree_node<tree_node_data>>& tree<tree_node_data>::peek_nodes() const
{
//TODO: Remove following line and add your implementation here.
return m_nodes;
}
template <typename tree_node_data>
tree_node<tree_node_data>& tree<tree_node_data>::ref_node(handle handle)
{
//TODO: Remove following line and add your implementation here.
if (handle >= m_nodes.size() || m_nodes[handle].m_recycled)
throw invalid_handle();
return m_nodes[handle];
}
}
Editor is loading...
Leave a Comment