Data Structure-Unordered Tree

Keywords: C++

Basic terminology:

Node Degree: The number of children a node has in the book.

Degree of a number: The maximum degree of all nodes in the tree.

Leaf node (terminal node): node with zero degree.

Branch node (non-terminal node): node with non-zero degree.

Root node (start node): The first node in the tree.

Internal nodes: Nodes in the tree other than root nodes.

The number of layers of nodes: if the number of layers of root node is 1, the number of layers of the nth generation of sub-nodes of root node is n.

Tree Height: The maximum number of layers of nodes in a book.

Ordered tree and disordered tree: If the sub-nodes of a node in the tree are disordered, the tree is disordered, otherwise it is ordered tree.

Forests: n trees obtained by removing the root node of a tree.

Tree characteristics:

1. Tree is a very basic and important non-linear structure.

2. Except for the header (tree root) and the tail (leaf node), there is only one direct precursor for any node, but there are many direct successors.

3. Trees are finite sets of data. Trees are divided into empty and non-empty trees.  

Non-empty tree: There is and only one root node. If the sub-node of the root node is larger than 1, it can be understood that the non-empty tree consists of m independent non-empty trees.

4. Recursive properties of trees (): A non-empty tree consists of several sub-trees, each of which consists of smaller sub-trees.

 

C++ implementation:

[MyTree.h]: Unordered Tree Type Template Header File

#pragma once

template<class T>
class MyTree
{
private:
    struct TreeNode  //Define Private, Not Users to Use
    {
        T data;  //Data domain, which can have more than one data
        //Pointer domain
        TreeNode *parent;   //Parent pointer of node
        TreeNode *child;    //Sub pointer
        TreeNode *brother;    //Brothers'Pointer Brothers' Gradual Management
    };
    TreeNode *pRoot;   //root node

public:
    MyTree();
    ~MyTree();
    void clear();
    void insertNode(const T& parentData, const T& insertData, bool insertChild = true); //Insert as child node by default
    //bool isFind(const T& findData);
    void preOrderPrint(TreeNode *root /*= pRoot*/);  //Preorder (anterior root) traversal
    void posOrderPrint(TreeNode *root /*= pRoot*/);  //Preorder (posterior root) traversal
    void inOrderPrint(TreeNode *root  /*= pRoot*/);   //Mid-order (mid-root) traversal    
    TreeNode* getTreeRoot();
private:
    void _clear(TreeNode *root);        //Be used for clear()Function implementation, no interface
    TreeNode* _find(TreeNode *root, const T& findData);
};

template<class T>
typename MyTree<T>::TreeNode* MyTree<T>::getTreeRoot()
{
    return pRoot;
}

template<class T>
void MyTree<T>::inOrderPrint(TreeNode *root /*= pRoot*/)
{
    if (!root)
        return;
    inOrderPrint(root->child);
    std::cout << root->data << " ";
    inOrderPrint(root->brother);
}

template<class T>
void MyTree<T>::posOrderPrint(TreeNode *root /*= pRoot*/)
{
    if (!root)
        return;
    posOrderPrint(root->child);
    posOrderPrint(root->brother);
    std::cout << root->data << " ";
}

template<class T>
void MyTree<T>::preOrderPrint(TreeNode *root /*= pRoot*/)
{
    if (!root)
        return;
    std::cout << root->data << " ";
    preOrderPrint(root->child);
    preOrderPrint(root->brother);
}

template<class T>
void MyTree<T>::insertNode(const T& parentData, const T& insertData, bool insertChild /*= true*/)
{
    TreeNode *tempInsertNode = new TreeNode;    //Generate a node to be inserted
    tempInsertNode->data = insertData;
    tempInsertNode->parent = NULL;
    tempInsertNode->child = NULL;
    tempInsertNode->brother = NULL;

    if (pRoot)  //Judging whether the tree is empty
    {
        TreeNode *findNode = _find(pRoot, parentData);    //Find the insertion position
        if (findNode)
        {//Location of insertion found
            if (insertChild)
            {//Insert in child node
                TreeNode *temp = findNode->child;
                if (temp)
                {
                    while (temp->brother)
                        temp = temp->brother;
                    temp->brother = tempInsertNode;
                    tempInsertNode->parent = findNode;
                }
                else
                {
                    findNode->child = tempInsertNode;
                    tempInsertNode->parent = findNode;
                }
            }
            else
            {//Insert in sibling node
                if (findNode->brother)
                {
                    TreeNode *tempNode = findNode->brother;
                    while (tempNode->brother)
                        tempNode = tempNode->brother;
                    tempNode->brother = tempInsertNode;
                    tempInsertNode->parent = tempNode->parent;
                }
                else
                {
                    //No sibling node
                    findNode->brother = tempInsertNode;
                    tempInsertNode->parent = findNode->parent;
                }
            }
        }
        else
        {//If no insertion position is found, the insertion is designed at the end.
            std::cout << "can not find the parent,insert the data in the end" << std::endl;
            TreeNode *temp = pRoot;
            while (temp->child)
                temp = temp->child;
            temp->child = tempInsertNode;
            tempInsertNode->parent = temp;
        }
    }
    else
    {//The tree is empty
        //         TreeNode *temp = new TreeNode;
        //         temp->data = insertData;
        //         temp->parent = NULL;
        //         inNode->child = inNode->brother = NULL;
        pRoot = tempInsertNode;
    }
}

template<class T>
typename MyTree<T>::TreeNode * MyTree<T>::_find(TreeNode *root, const T& findData)
{
    if (root)    /*Recursive termination conditions pass in empty pointers, such as judging that a leaf node is a child of a leaf node that is passed into a recursive function.
        Return to empty without satisfying conditions*/
    {
        //First judge the node in judging the sub-node and finally judge the sibling node to find direct return and not continue to find.
        if (root->data == findData)        //Determine whether the current node is the node to be found
            return root;
        TreeNode * temp = _find(root->child, findData);
        if (temp)
            return temp;
        if (temp = _find(root->brother, findData))
            return temp;
    }
    return NULL;    //If no return is found, it is empty
}

template<class T>
void MyTree<T>::_clear(TreeNode *root)
{
    //Recursive property of deleting all node trees recursively
    if (root)
    {
        _clear(root->child);
        _clear(root->brother);  //To delete a brother first is the same as to delete a son first.
        delete[]root;        //You have to delete your brothers and sons before you can delete yourself.
        root = nullptr;        //When all memory is released, the pointer is empty
    }
}

template<class T>
void MyTree<T>::clear()
{
    _clear(pRoot);  //There is no need to make any more empty judgments._clear()Judgement in China
}

template<class T>
MyTree<T>::~MyTree()
{
    clear();
}

template<class T>
MyTree<T>::MyTree()
{
    pRoot = nullptr;
}

Code testing:

 

// Unordered tree.cpp : Define the entry point for the console application.
//
#include "stdafx.h"
#include "MyTree.h"
#include<iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    MyTree<int> tree;
    std::cout << "tree:" << endl;;

    tree.insertNode(1, 1);
    cout << 1 << '\n' << '|' << endl;;

     tree.insertNode(1, 2, 1);
    tree.insertNode(2, 5, 0);
     tree.insertNode(2, 9, 0);
    cout << 2 << "" << 5<<"— —"<<9<<endl;
    cout << '|' << "  " << "|" <<"     "<<"|"<< endl;

    tree.insertNode(2, 3, 1);
     tree.insertNode(5, 6, 1);
     tree.insertNode(6, 7, 0);
     tree.insertNode(9, 10, 1);
    cout << 3 << "  " << 6 << "" << 7 <<" "<< 10 << endl;
    cout << "|" << "     " << "|" << endl;

     tree.insertNode(3, 4, 1);
    tree.insertNode(7, 8, 1);
    cout << 4 << "     " << 8 << "\n\n"<<endl;

    

    std::cout << "Preorder traversal:";
    tree.preOrderPrint(tree.getTreeRoot());
    std::cout << std::endl;

    std::cout << "Post-order traversal:";
    tree.posOrderPrint(tree.getTreeRoot());
    std::cout << std::endl;

    std::cout << "Intermediate traversal:";
    tree.inOrderPrint(tree.getTreeRoot());
    std::cout << std::endl;

    std::cin.get();
    return 0;
}

 

Test results:

 

Posted by jfarthing on Thu, 16 May 2019 12:17:10 -0700