Classes to help generate an n-Tree (k-Tree) structure, and a demo console app.
The project is a Visual Studio Solution, so simply open the .snl file and run the project. You can get Visual Studio here
I've provided 2 examples of how to use the tree. You can find the examples in the Program.cs file.
The first example generates a random tree. Meaning that the tree will have a random number of nodes every one of them with a random number as the data and with a random number of children. You can change the way the tree is generated by changing some of the parameters passed to the method MakeRandomTree()
.
In the example you can see that they are set like this:
MakeRandomIntTree(1, 10, 8, 4, 2)
The parameters are as follows:
MakeRandomIntTree(MinDepth, MaxDepth, MaxDigits, MaxChildren, Spaces)
MinDepth
The minumum depth of the tree, so in other words the least amount of layers(levels) the tree should have.MaxDepth
The maximum depth of the tree, so in other words the most amount of layers(levels) the tree should have.MaxDigits
The maximum lenght of the randomly generated integers.MaxChildren
The maximum amount of children a node can have.Spaces
The minimum amount of spaces between two brother nodes
Every time you run the program it will be a new tree. I recomend maximizing the console window, note that even with the window maximized the tree may not display correctly, it really depends on how big the tree is and how big your screen is. So I recomend to make a Windows Form/WPF/UWP with a scrollable rich text box or somethign similar, or saving the string in a file as .txt.
The second example shows how to manually create a tree. This tree:
K
|
|¯¯¯¯¯¯|
J F
| |
|¯¯| |¯¯¯|
H G E X
| |
| |¯¯|
D M P
We specify a root for the tree (K)
stnRoot = new CStringTreeNode("K");
then the left child (J) which in this case its the first child, so we reference the root (K) as the parent and we specify that this will be the first child of the referenced parent
stnChild = new CStringTreeNode("J", stnRoot, CTreeNode.ENodeCreate.ENODE_FIRST_CHILD);
the we create the children (H and G) for the parent node (J), notice that since this nodes will be childless we can simply create the new nodes without assigning them to a new instance of the class. Visual Studio will show a warning but it is totally valid code
new CStringTreeNode("H", stnChild, CTreeNode.ENodeCreate.ENODE_FIRST_CHILD);
new CStringTreeNode("G", stnChild, CTreeNode.ENodeCreate.ENODE_LAST_CHILD);
then we move to the next child of the root (K), so we create node (F) and set it as the last child of the root (K). Since node (F) will have children (E and X) we assign this to the instance stnChild
, we can safely reuse the same stnChild
object, since we no longer need to reference (J).
stnChild = new CStringTreeNode("F", stnRoot, CTreeNode.ENodeCreate.ENODE_LAST_CHILD);
now we create the first child of node (F), since the child node (E) will have a child (D) we asign this new node to a new instance stnGrandChild
so that we can reference it later on and still have stnChild
to be referenced in order to add the next child (X) of node (F).
stnGrandChild = new CStringTreeNode("E", stnChild, CTreeNode.ENodeCreate.ENODE_FIRST_CHILD);
now the child (D) of node (E)
new CStringTreeNode("D", stnGrandChild, CTreeNode.ENodeCreate.ENODE_FIRST_CHILD);
and now we move to node (X), we now reference stnChild
since node (X) is a child of node (F), and again we set this to an instance so that we can add children (M and P) to node (X)
stnGrandChild = new CStringTreeNode("X", stnChild, CTreeNode.ENodeCreate.ENODE_LAST_CHILD);
then we create nodes (M and P), and again since they're childless we can simpy create them and leave them unasigned.
stnGrandChild = new CStringTreeNode(stk_sLetters.Pop(), stnChild, CTreeNode.ENodeCreate.ENODE_LAST_CHILD);
and finally just convert the whole tree into a string.
return stnRoot.WriteTreeToString(2); // 2 is the minimum amount of spaces between two brother nodes
It's a simple tree structure in which each node keeps track of 4 other nodes, its parent, its child, its right brother and its left brother.
Even tho a node can have n number of children (where n is any number >= 0) it only keeps track of the child that was first introduced to it, the rest of the children will reference the node as the parent and can be found using the links m_pRightBrother
or m_pLeftBrother
(for the closests to the current node), so in a way it works kinda like a doubly linked list.
A second class inherits from the base one, keeping track of how many spaces, the start position of the cursor, how many forks and the length of the data. A queue is implemented to keep track of the current carracter to be printed in the current position. The printing method works by analyzing the whole structure first through a depth first search. It analyses how many layers the tree has, how many nodes are in each layer and the lenght every of these nodes and adapts acordingly.
This is the main class, it creates the nodes, each node has 4 properties, these are references to other nodes.
m_pRightBrother
A link to the node's right brotherm_pLeftBrother
A link to the node's left brotherm_pChild
A link to the node's childm_pParent
A link to the node's parent
Nodes also have 4 ways in wich they can be created:
ENODE_FIRST_CHILD
Add the node as the first child of the referenced nodeENODE_LAST_CHILD
Add the node as the last child of the referenced nodeENODE_RIGHT_BROTHER
Add the node as the right brother of the referenced nodeENODE_LEFT_BROTHER
Add the node as the left brother of the referenced node
This class the the one that is responsable to write the tree into a string. It inherits from CTreeNode and bassicaly just adds 5 new properties to the node.
m_sWidth
The width required for the treem_sStart
The starting point for writingm_sFork
Number of forks requiredm_sLength
The length of the datam_eCommand
The command to follow (To write either empty space, a fork a, the data or a branch) The methodInitWrite
is where the depth first magic happens.
These classes are simple, they inherit from CTreeNodeWriteable and add the data property to the node. If you plan to use this node for anyother type of data I recomend that you modify any of the two classes to deal with Generics.
So the TODO for this project is:
- Add a class that implements Generics and remove CIntTreeNode and CStringTreeNode
- Add a method to self balance the tree if balancing the tree is necesary.
- Add a search method, to search through the data of the tree.
- Make a prettier and flashier demo. Maybe something with graphics instead of just text.
- Comment the code (even tho I always try my best to have the code self comment)