### Introduction #### 1. Basic Concepts - **Definition**: A tree is a non-linear data structure composed of n (n ≥ 0) nodes. Each node can have zero or more child nodes, but only one parent node (except for the root node). This structure is similar to a tree in nature and has obvious hierarchy[^1^][^2^][^3^]. - **Characteristics**: - A tree has a root node and leaf nodes. The root node is the node without a parent node, while leaf nodes are nodes without child nodes[^1^][^2^][^3^]. - Except for the root node, each node has exactly one parent node[^1^][^2^][^3^]. - The degree of a tree refers to the maximum degree of all nodes in the tree, that is, the maximum number of child nodes a node has[^2^][^3^]. - The height or depth of a tree refers to the number of edges on the longest path from the root node to the farthest leaf node[^2^][^3^]. #### 2. Basic Terminology - The degree of a node: The number of child nodes a node has is called the degree of the node[^2^][^3^]. - Leaf node: A node with a degree of 0 is called a leaf node[^2^][^3^]. - Non-terminal node or branch node: A node with a degree not equal to 0 is called a branch node[^2^][^3^]. - Parent node: If a node contains child nodes, then this node is called the parent node of its child nodes[^2^][^3^]. - Child node: The root node of the subtree contained by a node is called the child node of this node[^2^][^3^]. - Sibling nodes: Nodes that have the same parent node are called sibling nodes[^2^][^3^]. - Ancestor nodes: All nodes on the branches from the root to a certain node are the ancestor nodes of this node[^2^][^3^]. - Descendants: Any node in the subtree with a certain node as the root is called a descendant of this node[^2^][^3^]. - Forest: A collection of m (m > 0) mutually disjoint trees is called a forest[^2^][^3^]. #### 3. Representation Methods There are multiple ways to represent a tree, including the parent representation method, the child representation method, and the child-sibling representation method. Among them, the child-sibling representation method is the most commonly used one. It stores the whole tree using a binary linked list, where the left pointer points to its first child and the right pointer points to its adjacent sibling[^1^][^2^][^3^]. #### 4. Special Types - Binary tree: A binary tree is a special type of tree. Each node of it has at most two child nodes, usually called the left child node and the right child node[^5^]. - Balanced tree: A balanced tree is a special binary tree whose height difference between the left and right subtrees does not exceed 1. Common balanced trees include AVL trees, red-black trees, etc.[^5^]. #### 5. Traversal Methods The main traversal methods of a tree include preorder traversal, inorder traversal, postorder traversal, and level-order traversal. These traversal methods can help us visit each node in the tree and perform processing as needed[^5^]. #### 6. Practical Applications Trees have a wide range of applications in practice, such as in file systems, database indexes, and compiler design. In a file system, the tree structure is used to organize and manage files. In a database, the tree structure is used to build efficient indexes. In compiler design, the tree structure is used to represent the syntax structure of a program[^5^]. ### Interfaces #### 1. Creation and Deletion of `tree` Objects ```c tree_t tree_create(void); void tree_delete(tree_t tree, void (*func)(tree_t tree)); ``` **Creation Method**: It is used to create an empty tree, that is, to initialize an instance of the tree structure, preparing for subsequent operations such as adding nodes to the tree and setting data. If the creation is successful, it will return the handle of the tree (of type `tree_t`). Subsequent operations on this tree can be performed through this handle. If problems such as memory allocation failure occur during the creation process and lead to creation failure, it will return `NULL`. This function has no input parameters and can be directly called to attempt to create a new empty tree structure. **Deletion Method**: It is responsible for deleting the specified tree structure, releasing the memory resources occupied by the tree and all its nodes. Meanwhile, an additional execution function can be passed in to perform some custom cleanup operations (such as releasing specific resources in nodes) for each node during the tree deletion process, ensuring that all resources related to the tree can be properly handled and avoiding problems like memory leaks. This function has no return value and finishes its task after performing the corresponding deletion and resource release operations. - `tree`: The handle of the tree to be deleted. The specific tree to be deleted is specified through the tree handle obtained by the `tree_create` function or other means, ensuring that the corresponding tree and all its associated resources are accurately cleaned up. - `func`: A pointer to a function. This function takes the tree handle as a parameter and is used to perform additional custom operations when deleting each node of the tree. If no additional operations are needed, `NULL` can be passed as this parameter. ```c static void test_create(void) { tree_t tree = tree_create(); if (tree) { printf("tree create success!!!\r\n"); } else { printf("[ERROR] tree create fail!!!\r\n"); } tree_delete(tree, NULL); } ``` #### 2. Setting and Getting Data of `tree` ```c int tree_set_data(tree_t tree, void* data, int size); int tree_get_data(tree_t tree, void* data, int size); const void* tree_data(tree_t tree); ``` **Setting**: It is used to set the given data into the specified tree node, overwriting the original data content. If the size of the passed-in data is 0, the original data will be deleted. If the data setting operation is successful, the function returns 1. If the tree node does not exist or the passed-in parameters are illegal and other situations lead to setting failure, it returns 0. - `tree`: The handle of the tree. Through this handle, the target tree node where the data is to be set is located, ensuring that the data can be accurately set into the corresponding node. - `data`: A pointer to the data to be set. The data content pointed to by this pointer will be copied into the tree node, replacing the original data. Its data type and size should meet the requirements of the tree node for data. - `size`: The size of the data to be set, in bytes. If this value is 0, the operation of deleting the original data will be executed; otherwise, the new data will be copied into the tree node according to this size. **Getting**: It retrieves data from the specified tree node and copies the retrieved data into the memory space pointed to by the passed-in pointer. If the retrieval operation is successful, the function returns 1. If the tree node does not have data or the passed-in parameters are illegal (such as the passed-in memory space being insufficient to store the data) and other situations lead to retrieval failure, it returns 0. - `tree`: The handle of the tree. Based on this handle, the corresponding tree node is found, and data is retrieved from this node, ensuring that the data of the target node is accurately retrieved. - `data`: A pointer to the memory space used to store the retrieved data. The memory space pointed to by this pointer needs to have sufficient capacity to store the data retrieved from the tree node, and its data type should also match that of the tree node's data. - `size`: The expected size of the data to be retrieved, in bytes. It needs to match the actual size of the data stored in the tree node, otherwise retrieval failure may occur. ```c static void test_set(void) { tree_t tree = tree_create(); int set = 100; int get = 0; tree_set_data(tree, &set, sizeof(set)); tree_get_data(tree, &get, sizeof(get)); printf("get %d\r\n", get); printf("data %d\r\n", *(int *)tree_data(tree)); tree_delete(tree, NULL); } ``` #### 3. Insertion and Erasure of Child Nodes of `tree` ```c int tree_insert(tree_t tree, int index); int tree_erase(tree_t tree, int index); ``` **`tree_insert`**: It inserts an empty child space at the specified index position of the specified tree for subsequent operations such as adding a subtree to this position. If the insertion operation is successful, the function returns 1. If the index is out of range, the tree does not exist, or other situations lead to insertion failure, it returns 0. - `tree`: The handle of the tree. It is used to locate the target tree where the insertion operation is to be performed. Only with the correct corresponding tree can the insertion position be accurately found and the insertion operation be executed. - `index`: The index position where the empty child space is to be inserted. This index represents the position number of the node in the tree, starting from 0. Through this index, the position in the tree where the new child space is inserted is determined. However, it is necessary to ensure that the passed-in index value is within the valid range of the tree (less than the current number of nodes and within other reasonable ranges). **`tree_erase`**: It is used to erase the empty child space at the specified index position of the specified tree. If the erasure operation is successful, the function returns 1. If the index is illegal, there is no empty child space at the corresponding position, or the tree itself has problems and other situations lead to erasure failure, it returns 0. - `tree`: The handle of the tree. Through this handle, the target tree where the erasure operation is to be performed is determined. Based on the tree structure, the corresponding index position is found to execute the operation of erasing the empty child space. - `index`: The index position where the empty child space to be erased is located. Similar to the index in `tree_insert`, it needs to be within the valid index range of the tree to accurately locate the target position to be processed. ```c static void test_insert(void) { tree_t tree = tree_create(); tree_insert(tree, 0); tree_insert(tree, 1); tree_insert(tree, 2); tree_insert(tree, 3); printf("tree child size %d\r\n", tree_csize(tree)); tree_erase(tree, 2); printf("tree child size %d\r\n", tree_csize(tree)); tree_delete(tree, NULL); } ``` #### 4. Attachment and Detachment of Child Nodes of `tree` ```c int tree_attach(tree_t tree, int index, tree_t attach); tree_t tree_detach(tree_t tree, int index); ``` **`tree_attach`**: It attaches an independent tree to the specified index position of another tree, realizing the combination and expansion of the tree structure and building a more complex tree-like hierarchical structure. If the attachment operation is successful, the function returns 1. If the index is illegal, there are problems with the target tree or the tree to be attached (such as an invalid handle), and other situations lead to attachment failure, it returns 0. - `tree`: The handle of the target tree, that is, the handle of the tree to which other trees are to be attached. Through it, the main tree structure where the attachment target position is located is determined. - `index`: The index position in the target tree. It is used to specify at which position node of the target tree the independent tree is to be attached. It is also necessary to ensure that the index value is within the valid range of the target tree. - `attach`: The handle of the independent tree to be attached. It points to another already created tree structure, and this tree will be added to the specified position of the target tree and become a part of the target tree. **`tree_detach`**: It detaches a subtree from the specified index position of the specified tree and returns the handle of the detached subtree. If the detachment operation is successful, subsequent operations can be performed on the detached subtree through the returned handle. If the index is illegal, there is no subtree at the corresponding position, or the tree itself has problems and other situations lead to detachment failure, it returns `NULL`. - `tree`: The handle of the tree. It is used to locate the original tree where the detachment operation is to be performed. A subtree is attempted to be detached from the specified index position of this tree. - `index`: The index position where the subtree to be detached is located. Through this index, the target subtree's position in the original tree is accurately found for the detachment operation. It is necessary to ensure that the index is valid. ```c static void test_attach(void) { tree_t tree = tree_create(); tree_t node = NULL; int data = 0; tree_insert(tree, 0); tree_insert(tree, 1); tree_insert(tree, 2); tree_insert(tree, 3); for (int i = 0; i < tree_csize(tree); i++) { node = tree_create(); data = 1000 + i; tree_attach(tree, i, node); tree_set_data(node, &data, sizeof(data)); } tree_print(tree, 0, print_int); node = tree_detach(tree, 1); tree_delete(node, NULL); tree_print(tree, 0, print_int); tree_delete(tree, NULL); } ``` #### 5. Getting Related Nodes of `tree` ```c tree_t tree_parent(tree_t tree); tree_t tree_child(tree_t tree, int index); ``` **`tree_parent`**: It is used to get the handle of the parent tree of the specified tree. If the tree has a parent tree, it returns the handle of the parent tree. Through this handle, further operations on the parent tree can be performed. If the tree has no parent tree (such as when it is the tree where the root node is located or it is an independent tree), it returns `NULL`. - `tree`: The handle of the tree. Through it, the target tree whose parent tree is to be found is located, and the corresponding parent tree is found according to the hierarchical structure of the tree and its handle is returned. **`tree_child`**: It gets the handle of the subtree at the specified index position of the specified tree. If there is a subtree at the index position, it returns the corresponding subtree handle, facilitating subsequent operations on the subtree. If the index is illegal or there is no subtree at the corresponding position, it returns `NULL`. - `tree`: The handle of the tree. It is used to determine the target tree where the subtree is to be found. In the structure of this tree, the corresponding subtree handle is located and obtained according to the index. - `index`: The index position of the subtree in the target tree, starting from 0. Through this index, the corresponding subtree is searched for in the target tree. It is necessary to ensure that the index is within the valid range. ```c static void test_parent(void) { tree_t tree = tree_create(); tree_t node = NULL; tree_t parent, child; tree_insert(tree, 0); tree_insert(tree, 1); tree_insert(tree, 2); tree_insert(tree, 3); tree_set_data(tree, "Parent", 7); node = tree_create(); tree_set_data(node, "Child0", 7); tree_attach(tree, 0, node); node = tree_create(); tree_set_data(node, "Child1", 7); tree_attach(tree, 1, node); node = tree_create(); tree_set_data(node, "Child2", 7); tree_attach(tree, 2, node); node = tree_create(); tree_set_data(node, "Child3", 7); tree_attach(tree, 3, node); tree_print(tree, 0, print_string); parent = tree_parent(node); print_string(parent); printf("\r\n"); child = tree_child(tree, 0); print_string(child); printf("\r\n"); child = tree_child(tree, 1); print_string(child); printf("\r\n"); child = tree_child(tree, 2); print_string(child); printf("\r\n"); child = tree_child(tree, 3); print_string(child); printf("\r\n"); tree_delete(tree, NULL); } ``` ### Setting and Retrieving Attributes of `tree` ```c int tree_set_attribute(tree_t tree, void* attribute, int size); int tree_get_attribute(tree_t tree, void* attribute, int size); const void* tree_attribute(tree_t tree); ``` #### `tree_set_attribute` This function is used to set the given attribute data into the specified tree node. It will overwrite the original attribute content. If the size of the passed-in attribute data is 0, the original attribute data will be deleted. If the attribute setting operation is successful, the function returns 1. If the tree node does not exist or the parameters are illegal and other situations lead to setting failure, it returns 0. - **`tree`**: The handle of the tree. Through this handle, the target tree node where the attribute is to be set can be located to ensure that the attribute can be accurately set into the corresponding node. - **`attribute`**: A pointer to the attribute data to be set. The data content pointed to by this pointer will be copied into the tree node, replacing the original attribute data. Its data type and size should meet the requirements of the tree node for attributes. - **`size`**: The size of the attribute data to be set, in bytes. If this value is 0, the operation of deleting the original attribute data will be executed; otherwise, the new attribute data will be copied into the tree node according to this size. #### `tree_get_attribute` It retrieves the attribute data from the specified tree node and copies the retrieved data into the memory space pointed to by the passed-in pointer. If the retrieval operation is successful, the function returns 1. If the tree node does not have attribute data or the passed-in parameters are illegal (such as the passed-in memory space being insufficient to store the attribute data) and other situations lead to retrieval failure, it returns 0. - **`tree`**: The handle of the tree. Based on this handle, the corresponding tree node is found to retrieve the attribute data content from this node, ensuring the accurate retrieval of the target node's attribute data. - **`attribute`**: A pointer to the memory space used to store the retrieved attribute data. The memory space pointed to by this pointer needs to have sufficient capacity to store the attribute data retrieved from the tree node, and its data type should also match that of the tree node's attribute data. - **`size`**: The expected size of the attribute data to be retrieved, in bytes. It needs to match the actual size of the attribute data stored in the tree node, otherwise retrieval failure may occur. #### `tree_attribute` It gets the address of the attribute information of the specified tree node. If the node has valid attribute data, it returns its address pointer, which is convenient for subsequent access and operation on the attribute data. If the node has no attribute or does not exist and other situations, it returns `NULL`. - **`tree`**: The handle of the tree. By using this handle, the specific tree node is located to obtain its associated attribute information address. Different tree nodes may have different attribute situations, and through the handle, the attribute data address of the corresponding node can be accurately obtained. ```c static void test_attr(void) { tree_t tree = tree_create(); char attr[20]; tree_set_attribute(tree, "This attribute!!!", 18); tree_get_attribute(tree, attr, sizeof(attr)); printf("attr %s\r\n", attr); tree_delete(tree, NULL); } ``` ### Depth of `tree` ```c int tree_depth(tree_t tree); ``` This function is used to obtain the depth of the specified tree. The depth calculation includes the level where the tree itself is located. The returned integer value represents the number of levels from the root node to the farthest leaf node, which can be used to understand the complexity of the tree's hierarchical structure and other situations. - **`tree`**: The handle of the tree. Through this handle, the corresponding tree structure is located, and then its depth information is calculated and returned. Different trees have different depths due to their different structures, and through the handle, the depth situation of the corresponding tree can be accurately obtained. ```c static void test_depth(void) { tree_t root = tree_create(); tree_t node, temp; tree_insert(root, 0); tree_insert(root, 1); tree_insert(root, 2); tree_attach(root, 0, tree_create()); tree_attach(root, 1, tree_create()); node = tree_child(root, 0); tree_insert(node, 0); tree_insert(node, 1); node = tree_child(root, 1); tree_insert(node, 0); tree_insert(node, 1); tree_attach(node, 0, tree_create()); tree_attach(node, 1, tree_create()); tree_print(root, 0, NULL); printf("depth %d\r\n", tree_depth(root)); tree_delete(root, NULL); } ``` ### Continuously Retrieving Subtrees of `tree` ```c tree_t tree_to_valist(tree_t tree, int index,...); #define tree_to(tree, i,...) ``` It retrieves subtrees in the tree through continuous index values. Starting from the specified tree, it searches for subtrees in the order of the passed-in indexes one by one until a negative index is encountered to stop the search. If the corresponding subtrees can be successfully found, it returns the handle of the final subtree. If during the search process, situations such as illegal indexes or no subtrees at the corresponding positions lead to the failure to find the target subtrees, it returns `NULL`. The `tree_to` is a simpler macro definition version, with a negative number added by default at the end of the parameters. - **`tree`**: The handle of the tree. It is used to determine the starting tree structure for the search. Subsequent index searches are all based on this tree, which is the basic starting point of the entire search operation. - **`index`**: The first index value. Starting from this index position, the search for subtrees in the tree begins. More index values can be passed in later (implemented through variable parameters). However, it is necessary to ensure that each index is legal and valid and within the range of the corresponding tree structure. - **`...`**: The variable parameter part, representing the subsequent other index values. These index values are used continuously to continue searching for the next level of subtrees in the found subtrees until a negative index is encountered to stop the search process. ```c static void test_to(void) { tree_t root = tree_create(); tree_t node, temp; tree_insert(root, 0); tree_insert(root, 1); tree_insert(root, 2); tree_attach(root, 0, tree_create()); tree_attach(root, 1, tree_create()); node = tree_child(root, 0); tree_insert(node, 0); tree_insert(node, 1); node = tree_child(root, 1); tree_insert(node, 0); tree_insert(node, 1); tree_attach(node, 0, tree_create()); tree_attach(node, 1, tree_create()); temp = tree_to(root, 1, 1); tree_set_data(temp, "To function!!!", 15); tree_print(root, 0, print_string); tree_delete(root, NULL); } ``` ### Size of `tree` ```c int tree_csize(tree_t tree); int tree_dsize(tree_t tree); int tree_asize(tree_t tree); int tree_size(tree_t tree); ``` #### `tree_csize` It is used to obtain the number of subtrees of the specified tree, that is, the number of child nodes the tree has. The returned integer value can help developers understand the branching situation of the tree, for example, to judge whether a certain node of the tree has child nodes. #### `tree_dsize` It gets the size of the data stored in the specified tree node. The returned integer value represents the number of bytes occupied by the corresponding node's data, which is helpful for understanding the scale of the data and making judgments in some operations related to the data size. #### `tree_asize` It obtains the size of the attribute data of the specified tree node. The returned integer value represents the number of bytes occupied by the corresponding node's attribute information, which can be used to understand the scale of the attribute data and as a judgment basis in related operations. #### `tree_size` It gets the total number of nodes of the specified tree. The returned integer value represents the number of all nodes contained in the whole tree, which can intuitively reflect the size of the tree and is convenient for developers to refer to the overall scale of the tree when performing some traversal, statistics and other operations. ### Printing `tree` ```c void tree_print(tree_t tree, int depth, void (*print)(tree_t tree)); ``` This function is used to perform an extended print display of the tree structure according to the specified depth. Through the passed-in print function (the developer customizes the specific print logic), relevant information of the tree, such as node data and hierarchical relationships, is output. If the `depth` parameter is 0, the entire information of the whole tree will be printed. If a specific depth value is passed in, the corresponding levels of the tree structure will be printed according to that depth. This function has no return value and is mainly used for visualizing the structure of the tree. - **`tree`**: The handle of the tree. Through this handle, the target tree structure to be printed and displayed is determined. Different trees have their own independent structures and data, and through the handle, the corresponding tree information can be accurately distinguished and printed. - **`depth`**: The depth to be printed, represented by the number of levels. A value of 0 means printing all the level information of the whole tree. If an integer greater than 0 is passed in, the corresponding layers of the tree structure will be printed starting from the root node according to that number of levels. - **`print`**: A pointer to a custom print function. This function takes the tree handle as a parameter. The developer needs to implement the specific print logic inside this function, such as in what format to output node data and how to reflect hierarchical relationships, so as to achieve a personalized print display effect of the tree structure.