Untitled

mail@pastecode.io avatar
unknown
plain_text
8 months ago
8.7 kB
4
Indexable
Never
#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];
	}


}
Leave a Comment