Shuffle tree (recursion) - c#

I have tree constructed recursively from the following class:
public class Node
{
public byte Symbol { get; set; }
public int Frequency { get; set; }
public Node Right { get; set; }
public Node Left { get; set; }
}
How to shuffle that tree?

This is probably not the most efficient way, but you can do it as follows:
Flatten the tree into a list of nodes.
Shuffle the data contents of the nodes in that list without changing the Left or Right references.
So, to flatten the tree:
static IEnumerable<Node> FlattenTree(Node root)
{
if (root != null)
{
yield return root;
foreach (var node in FlattenTree(root.Left))
yield return node;
foreach (var node in FlattenTree(root.Right))
yield return node;
}
}
Then write a Fisher-Yates shuffler to shuffle the contents of the nodes in a list:
static void Shuffle(List<Node> nodes, Random rng)
{
// Fisher-Yates shuffle.
for (int n = nodes.Count; n > 1; )
{
int k = rng.Next(n);
--n;
Swap(nodes[n], nodes[k]);
}
}
static void Swap(Node a, Node b)
{
byte tempSymbol = a.Symbol;
a.Symbol = b.Symbol;
b.Symbol = tempSymbol;
int tempFrequency = a.Frequency;
a.Frequency = b.Frequency;
b.Frequency = tempFrequency;
}
Finally flatten the tree into a list and then shuffle the contents of the nodes in that list:
static void ShuffleTree(Node root, Random rng)
{
var allNodes = FlattenTree(root).ToList();
Shuffle(allNodes, rng);
}
This requires enough space to make a copy of all the node references in the tree, and it has O(N) complexity when flattening the tree and O(N) when shuffling (so it is O(N) overall).
Note that you need to pass a Random into ShuffleTree(). If you are calling it multiple times, create just one Random object and pass the same one to each call to avoid problems with creating a new Random so frequently that multiple instances use the same seed.

If it is just a tree and nothing else. I would traverse the tree and add every node to a dictionary with a random value as key. Then order it and build up the new tree from by adding values in order.
Obviously you will possibly also have to generate a random int between x and y that specifies how many children nodes a node can have and attach that also to a node if it is not a binary tree but by you code example I presume it is.
//Traverse the tree and put it in input
Random random = new Random((int)DateTime.Now.Millisecond);
List<Node> sortedList = input.OrderBy(x => random.Next()).ToList();
Get first item from sortedList and put it in working list
loop through working list
Get the next 2 items from sorted list. (if there is any left)
Add it to the working list item
Remove the current working list item.
Add the 2 children nodes to the working list
We continue until the working list is empty.
This will obviously create a tree with all branches more or less the same length

Related

Sort specific Node in TreeView?

I would like to know if there is any method to sort (A-Z) a specific node of a TreeView.
The node I want to order is the node "Node1 \ z"
To display it like this:
H
N
Y
Z
Thank you
Your question is how to apply an alpha sort (A-Z) to a specific single node in a TreeView.
There are many ways to do this and the comments mention some good ones. Here is a solution that efficiently locates the target node using its fully-qualified path in the tree hierarchy. If found, it applies an individualized sort method (specified at runtime) to its children. But first, it must ensure that the TreeView will permit such reordering by setting its Sorted property to false. An advantage of this approach is that it avoids making a call the Sort method for the entire TreeView because that would add an unnecessary layer of complexity.
Find the target node
Given a rule for the TreeView that the fully-qualified path to any node (for example, #"Node1\z") is unique, the target can be obtained very efficiently by making an extension for TreeView that returns the specified node (or null if not found).
public static TreeNode Find(this TreeView treeView, string path)
{
var parse = path.Split('\\');
var nodes = treeView.Nodes;
TreeNode node = null;
foreach (var text in parse)
{
node = nodes.Cast<TreeNode>().FirstOrDefault(node => node.Text == text);
if (node == null) break;
nodes = node.Nodes;
}
return node;
}
Sort children of target node
This extension for TreeNode sorts its children according to the comparer Func passed in as an argument.
public static void Sort(
this TreeNode node,
Func<TreeNode, TreeNode, int> sorter)
{
// Make sure the TreeView will allow reordering
if (node.TreeView != null)
{
node.TreeView.Sorted = false;
}
// Copy the nodes to a list
var list = node.Nodes.Cast<TreeNode>().ToList();
// Sort the list however the `Sorter` says to.
list.Sort((a, b) => sorter(a, b));
// Clear the 'old' order
node.Nodes.Clear();
// Install the 'new' order
foreach (var sorted in list)
{
node.Nodes.Add(sorted);
}
}
Complete method to sort (A-Z) a specific node of a TreeView.
So, to answer the question Is there any method to sort a specific node of a TreeView from A-Z let's say we manufacture such a method by making an extension for TreeView that does just that. For the path argument specify the entire hierarchal path like #"Node1" or #"Node1\z".
public static bool SortIfNodeFound(
this TreeView treeView,
string path,
Func<TreeNode, TreeNode, int> sorter)
{
var node = treeView.Find(path);
node?.Sort(sorter);
return node != null;
}
Once you call the TreeView.Sort method, you actually apply the sorted TREEVIEWSTATE through the setter of the hidden Sorted property. The control by that sorts all the nodes using the default sorter, the ascending alphabetical sort. Any attempts afterwards to sort the nodes in a different way fail. You'll note that nothing happens when you remove, sort, and reinsert child nodes of a specific node because once you insert them, the default sorter will interfere and revert your different sort. Again, all the mentioned is when you call the .Sort method before any other sorting routines.
To override this behavior, you need to provide a custom node sorter for the TreeView.TreeViewNodeSorter property. An example that allows you to sort the tree or children of node in ascending or descending orders.
public class TreeNodeComparer : IComparer
{
public TreeNodeComparer(SortOrder sortOrder = SortOrder.Ascending) : base()
{
SortOrder = sortOrder;
}
public int Compare(object x, object y)
{
var xn = x as TreeNode;
var yn = y as TreeNode;
switch (SortOrder)
{
case SortOrder.Descending:
return string.Compare(xn.Text, yn.Text) * -1;
case SortOrder.Ascending:
return string.Compare(xn.Text, yn.Text);
default:
return 1;
}
}
public SortOrder SortOrder { get; set; } = SortOrder.Ascending;
}
Note return 1; here in case SortOrder.None is necessary to not revert sorting the child nodes of a specific node.
A couple of extension methods for the TreeView and TreeNode types.
public static class TreeViewExtensions
{
public static void Sort(this TreeView self, SortOrder order = SortOrder.Ascending)
{
self.TreeViewNodeSorter = new TreeNodeComparer(order);
self.Sort();
}
public static void Sort(this TreeNode self, SortOrder order = SortOrder.Ascending)
{
List<TreeNode> tmp;
TreeView tv = self.TreeView;
if (order == SortOrder.Descending)
tmp = self.Nodes.Cast<TreeNode>().OrderByDescending(n => n.Text).ToList();
else
tmp = self.Nodes.Cast<TreeNode>().OrderBy(n => n.Text).ToList();
var sorter = tv.TreeViewNodeSorter as TreeNodeComparer ?? new TreeNodeComparer();
sorter.SortOrder = SortOrder.None;
tv.TreeViewNodeSorter = sorter;
tv.BeginUpdate();
self.Nodes.Clear();
self.Nodes.AddRange(tmp.ToArray());
tv.EndUpdate();
}
}
You can call them as follows:
// To sort the whole thing...
YourTreeView.Sort(SortOrder.Descending);
// Or the children of the selected node for example...
YourTreeView.SelectedNode.Sort(SortOrder.Ascending);

Writing a tree structure to disk using C# and recursion

I'm fairly new to C# and I'm attempting to take the tree structure I've created from a list, and write that to the file system. (I've used this answer).
That is, I want to create the directories and subdirectories in the proper depth. However, I'm getting stuck on depth and cannot think of how to loop through each iteration of the depth, then back out to start writing again, without just writing all the 0-depth directories, then all the 1-depth directories, etc., in the same location.
I'm thinking there's another recursive routine/method/function, but I just can't wrap my head around it. I'd like to get to the next level (ha) in my understanding of programming.
static void Test(IEnumerable<TreeItem<category>> categories, int deep = 0)
{
foreach (var c in categories)
{
for (int i = 0; i < deep; ++i) {
System.IO.Directory.CreateDirectory(c.Item.Name);
}
Test(c.Children, deep + 1);
}
}
Because Directory.CreateDirectory creates all the parent directories for you, assuming you have the full path stored for each node, you only need to pass leaf nodes (nodes with no children) to it.
You can write a recursive search to retrieve leaf nodes, then pass that list to CreateDirectory.
static IEnumerable<TreeItem<category>> GetLeafs(IEnumerable<TreeItem<category>> tree)
{
foreach (var item in tree)
{
if (item.Children.Any())
{
// this is not a leaf, so find the leaves in its descendants
foreach (var leaf in GetLeafs(item.Children))
yield return leaf;
}
else
{
// no children, so this is a leaf
yield item;
}
}
}
static void CreateDirectories(IEnumerable<TreeItem<category>> categories)
{
foreach (var leaf in GetLeafs(categories))
{
System.IO.Directory.CreateDirectory(leaf.Item.Name);
}
}
If you don't have the full path against each node, then you can use the same structure as GetLeafs (although it turns out much simpler, because you don't need to return anything back up the call-chain) to recursively walk the tree, creating directories as you go deeper:
static void CreateDirectories(IEnumerable<TreeItem<category>> tree)
{
foreach (var item in tree)
{
Directory.Create(c.Item.Name);
CreateDirectories(item.Children);
}
}
This method is simpler, but will result in more calls to Directory.Create, which could conceivably have a performance impact.

For Each statement with a constructor list?

I am writing a pathfinding script in Unity, and I have been trying to figure out IEnumerables, and I feel I am not wording my internet searches correct, because it is not at all what I want.
I have 3 scripts, 1 find nodes and it adds to the OpenNodes list which is it's own script with constructor. I have An IEnumerable and it is still saying it can't access, or it needs to be static if just public. So my codes as follows:
public class OpenNodes: IEnumerator, IEnumerable {
public static Vector3 node;
public static int g;
public static IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
public OpenNodes(Vector3 newNode, int newGscore)
{
node = newNode;
g = newGscore;
}
so what I am trying to do in a different "FinderScript" is along these lines:
foreach(Vector3 node in OpenNodes)
I have been trying my hardest to figure it out, but I have never worked in constructor lists like this. This is new to me, so any help, would be SO greatly appreciated.. Thanks
EDIT:
This for each needs to take node in as a vector3 as it is using .x,.y, and .z values for comparison and changes..
As you need to store a score per node you could simply use a Dictionary<Vector3, int> to store the values.
e.g.
var nodes = new Dictionary<Vector3, int>();
nodes.add(node, gScore);
And then either access them directly
nodes[node] = ...
Or loop through them
foreach (var node in nodes.Keys) {
...
}
Alternatively, perhaps you can create an object that maps the score and the node together (or simply use a Pair and then just use a list?
var nodes = new List<Vector3>();
var map = new Pair(node, gScore);
nodes.add(map);
Then loop through them as per usual:
foreach (var node in nodes) {
...
}
Not sure if i have understood you correctly, and i haven't run this code. HTH.
The problem I was facing was actually more simple that I realized. Below is the code of my constructor list:
public class OpenNodes {
public Vector3 node;
public int g;
public OpenNodes(Vector3 newNode, int newGscore)
{
node = newNode;
g = newGscore;
}
}
The code for the foreach is as follow:
foreach(OpenNodes list in OpenNode)
to populate the list looks like:
OpenNode.Add(new OpenNodes(nodeLocation, 0 ));
to remove an item looks like:
OpenNode.RemoveAll(OpenNodes => nodeLocation == OpenNodes.node && 0 == OpenNodes.g);
and to access my node it is simply:
list.node.x
list.node
list.node.z
ect.
This is iterating through each item in the list as list, and then you call upon each variable after that. I hope this code will help someone in the future!

C# Adding Visible Nodes to Node Array

I'm trying to create a function that will add each visible node in a tree to a node array and then return it.
This is the code I have so far, but struggling to figure out how to add them.
Note: The tree has a maximum of 8 nodes.
private Node[] activeClients(AdvTree tree)
{
Node[] activeClients = new Node[8];
foreach (Node client in tree.Nodes)
{
if (client.IsVisible)
{
//Add Visible Node to activeClients Node Array
}
}
return activeClients;
}
May be something like:
var visibleNodes = tree.Nodes.Where(client=>client.IsVisible)
especially if you are talking about small numbers (8 elements) and not compute intensive function, dynamic array (or vector) like List<T>, IEnumerable<T> is a right choice.
And in this way, your code also scales better in the future.
I actually figured out I didn't need a Node Array, but thanks for the help guys.
I used NodeCollection instead and it worked perfect for my needs.
private NodeCollection activeClients(AdvTree tree)
{
NodeCollection activeClients = new NodeCollection();
foreach (Node client in tree.Nodes)
{
if (client.IsVisible)
{
//Add Visible Node to activeClients Node Array
activeClients.Add(client, eTreeAction.Code);
}
}
return activeClients;
}

C# How to find a Class' non created objects?

I have this class
class Node
{
public bool is_end;
public int prefix_count;
public Node[] child = new Node[26];
}
My problem is, the class only creates Nodes if it is necessary, but later in the program, i need to check all the created Nodes, though since i don't know which ones are created, i can't use a cycle for it.
Is there a way for me to know which Nodes are created, is there a code to check if this Node exists or not.
Try using a List<Node> instead of a fixed length array. Then you can use methods such as
var nodeList = new List<Node>();
nodeList.Add(someRandomNode);
if (nodeList.Contains(someRandomNode))
{
// your logic
}
You may also iterate over your Node collection.
foreach(var node in nodeList) { }
In this case, your child array is pre-created, but each individual node is not allocated. You can check for null to see if a Node has been created:
bool ChildCreated(Node parent, int childIndex)
{
return parent.child[childIndex] != null;
}
I have to find out which child nodes are created, for example a cycle from 0 to 25, and it has to give a message like node[2] and node[11] are created, others aren't.
Using this method, you could easily do:
var created = Enumerable.Range(0, node.child.Length).Where(i => ChildCreated(node, i)).ToList();
if (!created.Any())
{
Console.WriteLine("No children created.");
}
else
{
Console.WriteLine("Children {0} created, all others aren't.", string.Join(", ", created));
}
All you need to do is to check if Node[] element is null:
int nodeIndex = 0;
if(child[nodeIndex] == null)
{
// node doesn't exist
}
else
{
// node exists
}

Categories

Resources