I am trying to generate a decision tree, that will be displayed in a TreeView. This is for a football game developer interface. It will allow the user to add events to particular nodes. The problem I have is generating all of the nodes. When using a linked list one can share nodes, where paths cross, but this cant be utilised in a TreeView, as the nodes get confused. I have an image here:
As you know football is a goal event game, and once a goal is scored, I move into the next node in the tree. So a score of 0 - 0 is the starting point. That node then splits into 2 nodes (1 - 0) and (0 - 1). Once on a path the tree needs to cater for travelling down that path but also cater for 2 - 2, 3 - 2, 3 - 3, etc
So each node in the tree needs to contain all possible solutions from the previous score. I'm sure you get the idea.
The maximum score, or exit point for the recursion is defined as:
(Home + Away) < 8
I call the recursion routine with:
Recurse(rootNode, 0, 0);
The function CreateNodeFromScore does the fancy node creation and works great.
My recursion code is here:
private void Recurse(TreeNode node, int iHome, int iAway) {
if ((iHome + iAway) == 8 ) {
return;
}
node.Nodes.Add( CreateNodeFromScore(iHome, iAway) );
TreeNode nextNode = node.Nodes[0];
Recurse(nextNode, ++iHome, iAway);
Recurse(nextNode, iHome, ++iAway);
}
private void CreateNodeFromScore(int iHome, int iAway) {
return new TreeNode(iHome.ToString() + " - " + iAway.ToString());
}
I have tried many ways to get this working, but the solution eludes me.
This is an algorithm problem rather than a gui, treeview, or C#, C++ problem. The code can be pretty much directly translated between the 2 languages.
Can any help me ?
I'm going to answer my own question here, as I have figured out the answer. Interestingly, posting here has helped me re-think the problem as I think I was getting confused. My thanks to #dbc for his advice and pointers.
private void Recurse(TreeNode node, int iHome, int iAway) {
if ((iHome + iAway)> 7)
return;
var homeNode = CreateNodeFromScore(iHome +1, iAway);
var awayNode = CreateNodeFromScore(iHome, iAway + 1);
node.Nodes.Add(homeNode);
node.Nodes.Add(awayNode);
Recurse(homeNode, iHome +1, iAway);
Recurse(awayNode, iHome, iAway +1);
}
Produces this result:
https://i.imgur.com/ztnbRDA.png
I hope this might be useful for others
Andrea
Related
I have a problem making this task: An n-vertex graph is a scorpion if it has a vertex 1(the sting) connected to a vertex two (the tail) connected a vertex 3 (the body) connected to the other vertexes (the feet). Some of the feet may be connected to other feet. Design an algorithm that decides whether a given drawing represents a scorpion and tell in which line is sting,tail , body and feets.
This is my data file to read from:
(+) is where is edge and (-) where are no edges
I'm trying to find the sting first but how basically i could search for connections with tail and body? also i have to use recursion
EDIT:
Ok now i habe found how much "+" there are in each line:
int[] B = new int[100];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
int HowMuch = Regex.Matches(A[i,j], #"\+").Count;
Saving[i] += HowMuch;
}
if(Saving[i]>=3)
{
Console.WriteLine("It's a scorpion!");
Console.WriteLine("The body is in: " + i + " part");
}
}
And with recursion i'm trying to find path connections... How i should continue?
static void Find(string[,] A, int n, int j)
{
for (int i = 0; i < n; i++)
{
if(A[i,j]=="+")
{
j = i;
Find(A, n, j);
}
}
}
So, I'm giving you an idea on how to solve this. I took help from this. You should take a look there. There is a hint on that site.
My approach is slightly different from theirs.
From abstract point of view, you are asking, from an adjacency matrix, determine whether the given points are like this image(aka the scorpion). (taken from that site)
Now, how the adjacency matrix convert to scorpion? Let's look at your example.
I drawn the adjacency matrix and the graph by hand. I hope its not too difficult to understand.
Now how to solve it? You compute the degree for each node here. You can compute it from the adjacency matrix here. (The degree means the number of nodes one node is connected to, For example, for the graph i drawn there, the degree of 1 is 1, degree of 0 is 2 and so on...)
At first you find degree of all the nodes here(nodes means vertex and vice versa).
So, the sting should be the one with degree one. Now there is a problem with this, i'll get back to it. But for now lets not consider it.
The tail would be with degree 2. And it would be connected with the sting. So, you find the one node connected with sting and you are done. That is the tail.
The node that is connected with tail(apart from sting) is the body.
The body would be with degree >= 2. So if there is a vertex with that much degree, then that's the body for sure. And the nodes connected with it are the feets.
Now you may say, the feets are with degree 2 so why are not tail? Because they are not connected to sting.(which you have computed earlier)
You may also say, the feets are with degree 1 so why not sting? because its connected to some node that has degree > 2, which cannot be(as the tail has degree of 2)
Now thats all well and good, but consider a problem, If the graph is like this,
1-0-3-4
then what would be the sting and the what would be the feet? My answer is both. Both 1 and 4 can be leg or sting.
I hope you understand what i have said.
Clarification on the image if needed:
You said, where there is a + there is an edge. Notice the + on 1 and 3 on row 0. So, 0 is connected to 1 and 4. I've connected them just like that. And the connections are bidirectional. You can see that from adjacency matrix.
I have a part in my application which needs to do do something (=> add padding 0 in front of other numbers) when a specified number gets an additional digit, meaning it gets 10, 100, 1000 or so on...
At the moment I use the following logic for that:
public static bool IsNewDigit(this int number)
{
var numberString = number.ToString();
return numberString.StartsWith("1")
&& numberString.Substring(1).All(c => c == '0');
}
The I can do:
if (number.IsNewDigit()) { /* add padding 0 to other numbers */ }
This seems like a "hack" to me using the string conversion.
Is there something something better (maybe even "built-in") to do this?
UPDATE:
One example where I need this:
I have an item with the following (simplified) structure:
public class Item
{
public int Id { get; set; }
public int ParentId { get; set; }
public int Position { get; set; }
public string HierarchicPosition { get; set; }
}
HierarchicPosition is the own position (with the padding) and the parents HierarchicPositon. E.g. an item, which is the 3rd child of 12 from an item at position 2 has 2.03 as its HierarchicPosition. This can as well be something more complicated like 011.7.003.2.02.
This value is then used for sorting the items very easily in a "tree-view" like structure.
Now I have an IQueryable<Item> and want to add one item as the last child of another item. To avoid needing to recreate all HierarchicalPosition I would like to detect (with the logic in question) if the new position adds a new digit:
Item newItem = GetNewItem();
IQueryable<Item> items = db.Items;
var maxPosition = items.Where(i => i.ParentId == newItem.ParentId)
.Max(i => i.Position);
newItem.Position = maxPosition + 1;
if (newItem.Position.IsNewDigit())
UpdateAllPositions(items.Where(i => i.ParentId == newItem.ParentId));
else
newItem.HierarchicPosition = GetHierarchicPosition(newItem);
UPDATE #2:
I query this position string from the DB like:
var items = db.Items.Where(...)
.OrderBy(i => i.HierarchicPosition)
.Skip(pageSize * pageNumber).Take(pageSize);
Because of this I can not use an IComperator (or something else wich sorts "via code").
This will return items with HierarchicPosition like (pageSize = 10):
03.04
03.05
04
04.01
04.01.01
04.01.02
04.02
04.02.01
04.03
05
UPDATE #3:
I like the alternative solution with the double values, but I have some "more complicated cases" like the following I am not shure I can solve with that:
I am building (on part of many) an image gallery, which has Categories and Images. There a category can have a parent and multiple children and each image belongs to a category (I called them Holder and Asstes in my logic - so each image has a holder and each category can have multiple assets). These images are sorted first be the categories position and then by its own position. This I do by combining the HierarchicPosition like HolderHierarchicPosition#ItemHierarchicPosition. So in a category which has 02.04 as its position and 120 images the 3rd image would get 02.04#003.
I have even some cases with "three levels" (or maybe more in the future) like 03.1#02#04.
Can I adapt the "double solution" to suport such scenarios?
P.S.: I am also open to other solution for my base problem.
You could check if base-10 logarithm of the number is an integer. (10 -> 1, 100 -> 2, 1000 -> 3, ...)
This could also simplify your algorithm a bit in general. Instead of adding one 0 of padding every time you find something bigger, simply keep track of the maximum number you see, then take length = floor(log10(number))+1 and make sure everything is padded to length. This part does not suffer from the floating point arithmetic issues like the comparison to integer does.
From What you describe, it looks like your HierarchicPosition position should maintain an order of items and you run into the problem, that when you have the ids 1..9 and add a 10, you'll get the order 1,10,2,3,4,5,6... somewhere and therefore want to pad-left to 01,02,03...,10 - correct?
If I'm right, please have a look at this first: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem
Because what you try to do is a workarround to solve the problem in a certain way. - But there might be more efficent ways to actually really solve it. (therefore you should have better asked about your actual problem rather than the solution you try to implement)
See here for a solution, using a custom IComparator to sort strings (that are actually numbers) in a native way: http://www.codeproject.com/Articles/11016/Numeric-String-Sort-in-C
Update regarding your update:
With providing a sorting "String" like you do, you could insert a element "somewhere" without having ALL subsequent items reindexed, as it would be for a integer value. (This seems to be the purpose)
Instead of building up a complex "String", you could use a Double-Value to achieve the very same result real quick:
If you insert an item somewhere between 2 existing items, all you have to do is : this.sortingValue = (prior.sortingValue + next.sortingValue) / 2 and handle the case when you are inserting at the end of the list.
Let's assume you add Elements in the following order:
1 First Element // pick a double value for sorting - 100.00 for example. -> 100.00
2 Next Element // this is the list end - lets just add another 100.00 -> 200.00
1.1 Child // this should go "in between": (100+200)/2 = 150.00
1.2 Another // between 1.1 and 2 : (150+200)/2 = 175
When you now simple sort depending on that double field, the order would be:
100.00 -> 1
150.00 -> 1.1
175.00 -> 1.2
200.00 -> 2
Wanna Add 1.1.1? Great: positon = (150.00 + 175.00)/2;;
you could simple multiply all by 10, whenever your NEW value hits x.5* to ensure you are not running out of decimal places (but you dont have to - having .5 .25 .125 ... does not hurt the sorting):
So, after adding the 1.1.1 which would be 162,5, multiply all by 10:
1000.00 -> 1
1500.00 -> 1.1
1625.00 -> 1.1.1
1750.00 -> 1.2
2000.00 -> 2
So, whenever you move an item arround, you only need to recalculate the position of n by looking at n-1 and n+1
Depending on the expected childs per entry, you could start with "1000.00", "10.000" or whatever matches best.
What I didn't take into account: When you want to move "2" to the top, you would need to recalculate all childs of "2" to have a value somewhere between the sorting value of "2" and the now "next" item... Could serve some headache :)
The solution with "double" values has some limitations, but will work for smaller sets of groups. However you are talking about "Groups, subgroups, and pictures with counts of 100" - so another solution would be preferable:
First, you should refactor your database: Currently you are trying to "squeeze" a Tree into a list (datatables are basically lists)
To really reflect the complex layout of a tree with an infinite depth, you should use 2 tables and implement the composite pattern.
Then you can use a recursive approach to get a category, its subcategory, [...] and finally the elements of that category.
With that, you only need to provide a position of each leaf within it's current node.
Rearanging leafs will not affect any leaf of another node or any node.
Rearanging nodes will not affect any subnode or leaf of that node.
You could check sum of square of all digits for the input, 10,100,1000 has something in common that, if you do the sum of square of all digits, it should converge to one;
10
1^2 + 0^2 = 1
100
1^2 + 0^2 + 0^2 = 1
so on so forth.
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 1 year ago.
I am creating a little BlackJack application in C#. I am able to deal an intial hand to both the dealer and the player and then hit for the player. However once I do this, the dealer is supposed to draw a card from the deck when the dealer handvalue is less than 17.
This is the get a single card from the deck in the deck class:
public Card GetCard()
{
int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
cardsInDeck_.RemoveAt(r0);
return cardsInDeck_[r0];
}
when I hit "stay" and the dealer activates I get this error on the last line
Index was out of range. Must be non-negative and less than the size of the collection
This is my "stay" method on the form
private void buttonStay_Click(object sender, EventArgs e)
{
while (dealer.GetValue() < 17)
{
dealer.CardsInDealerHand.Add(deck.GetCard());
}
dealerHandValue_ = dealer.GetValue();
if (dealerHandValue_ > 21)
{
Win();
}
else
{
WinCondition();
}
}
I am new to programming in general but I think that something is wrong with either my deck or dealer.
I would appreciate any help on this.
First thing that I notice: you're removing the card from the deck before you access it to return it, causing your indices to get out of whack. In some situations this may "work" in that it won't throw, but you won't get back the right card. In other situations you can end up overrunning your list's bounds.
Consider: You have 6 items in your "deck", and you pick the last one. Your current logic would be:
cardsInDeck_.RemoveAt(r0); # Remove the item at index 5; now we have 5 items (0-based indexing)
return cardsInDeck_[r0]; # Try to get the item at index 5, but it's no longer there!
Even if you don't pick the last index, you're actually going to get the wrong card. For example, if you had:
{ A, J, 5, 10, 2 }
...in your deck, and you picked index 2, you should get the 5 back. Since you're removing the card first then accessing the list index, you'd actually get back the 10.
You'll need to get a reference to the card first, then remove it from the deck and return the reference:
public Card GetCard()
{
int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
var chosenCard = cardsInDeck_[r0];
cardsInDeck_.RemoveAt(r0);
return chosenCard;
}
It would probably be a good idea to check cardsInDeck_.Count for a zero value before trying to get another card as well, either in GetCard() or in the while loop, perhaps. If you're only dealing out two hands (one to the player, one to the dealer) then this is mathematically not a situation you'll hit, of course. Otherwise, with multiple players, you'd need to handle that situation somehow (e.g. you could add a second deck to the hand by repopulating cardsInDeck).
r0 is being set to a value that is either negative or larger then the size of cardsInDeck_ by the function rndCard.Next
int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
Problem : You are trying to remove the items from the cardsInDeck_ without checking for its Count . if you keep on Removing items from the cardsInDeck_ at certain point it's Count becomes
zero and no items can not be removed if the Count is Zero.
Solution : before removing items from cardsInDeck_ ,you need to check for its Count, you should remove items only if its Count is greater than zero.
Replace This:
cardsInDeck_.RemoveAt(r0);
With This:
if(cardsInDeck_.Count>0)
{
cardsInDeck_.RemoveAt(r0);
}
The exception message:
"Index was out of range. Must be non-negative and less than the size of the collection"
is the problem here because if the deck is empty then
int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
the second argument to Next is an exclusive upper bound.
thus if Count is 0 then you are asking for an int >= 0 && < -1
if count is 1 you are asking for an int >= 0 && < 0
Also, I recommend that you follow standard C# naming conventions. Microsoft's recommendations are a good place to start
msdn C# style guide
Please help I've been trying to generate a random binary search tree of size 1024 and the elements needs to be random sortedset ... I'm able to write a code to create a binary search tree manually by adding elements manually but I'm unablele yo write a code that would generate a random balanced binary tree of size 1024 then use try to find a key in that tree ... please please and thank u ahead ....
Edit added code from comments
ya it is homework... and this is what i got so far as code:
using System;
namespace bst {
public class Node {
public int value;
public Node Right = null;
public Node Left = null;
public Node(int value)
{
this.value = value;
}
}
public class BST {
public Node Root = null;
public BST() { }
public void Add(int new_value)
{
if(Search(new_value))
{
Console.WriteLine("value (" + new_value + ") already");
}
else
{
AddNode(this.Root,new_value);
}
}
}
}
Use recursion.
Each branch generates a new branch, select the middle item in the unsorted set, the median. Put it in the current item in the tree. Copy all items less than the median to another array, send that new array to the call of the same method. Copy all items greater than the median to another array, send that new array to the call of the same method.\
Balanced trees have to have an odd number of items, unless the main parent node is not filled in. You need to decide if there are two values that are the Median, whether the duplicate belongs on the lower branch or upper branch. I put duplicates on the upper branch in my example.
The median will be the number where an equal amount of numbers is less than and greater than the number. 1,2,3,3,4,18,29,105,123
In this case, the median is 4, even though the mean (or average) is much higher.
I didn't include code that determines the median.
BuildTreeItem(TreeItem Item, Array Set)
{
Array Smalls;
Array Larges;
Median = DetermineMedian(Set);
Item.Value = Median;
if(Set.Count() == 1)
return;
for (int i = 0; int i < Set.Count(); i++)
{
if(Set[i] < Median)
{
Smalls.new(Set[i]);
}
else
{
Larges.new(Set[i]);
}
}
Item.Lower = new TreeItem;
Item.Upper = new TreeItem;
BuildTreeItem(TreeItem.Lower, Smalls);
BuildTreeItem(TreeItem.Upper, Larges);
}
Unless it is homework the easiest solution would be to sort data first and then build a tree by using middle item as root and descending down each half. Method proposed by Xaade is similar , but much slower due to DetermineMedian complexity.
The other option is to actually look at algorithms that build balanced trees (like http://en.wikipedia.org/wiki/Red-black_tree ) to see if it fits your requirements.
EDIT: removing incorrect statement about speed of Xaade algorithm - it is actually as fast as quick sort (n log n - check each element on every level of recursion with log n levels of recursion), not sure why I estimated it slower.
Is there a method to build a balanced binary search tree?
Example:
1 2 3 4 5 6 7 8 9
5
/ \
3 etc
/ \
2 4
/
1
I'm thinking there is a method to do this, without using the more complex self-balancing trees. Otherwise I can do it on my own, but someone probably have done this already :)
Thanks for the answers! This is the final python code:
def _buildTree(self, keys):
if not keys:
return None
middle = len(keys) // 2
return Node(
key=keys[middle],
left=self._buildTree(keys[:middle]),
right=self._buildTree(keys[middle + 1:])
)
For each subtree:
Find the middle element of the subtree and put that at the top of the tree.
Find all the elements before the middle element and use this algorithm recursively to get the left subtree.
Find all the elements after the middle element and use this algorithm recursively to get the right subtree.
If you sort your elements first (as in your example) finding the middle element of a subtree can be done in constant time.
This is a simple algorithm for constructing a one-off balanced tree. It is not an algorithm for a self-balancing tree.
Here is some source code in C# that you can try for yourself:
public class Program
{
class TreeNode
{
public int Value;
public TreeNode Left;
public TreeNode Right;
}
TreeNode constructBalancedTree(List<int> values, int min, int max)
{
if (min == max)
return null;
int median = min + (max - min) / 2;
return new TreeNode
{
Value = values[median],
Left = constructBalancedTree(values, min, median),
Right = constructBalancedTree(values, median + 1, max)
};
}
TreeNode constructBalancedTree(IEnumerable<int> values)
{
return constructBalancedTree(
values.OrderBy(x => x).ToList(), 0, values.Count());
}
void Run()
{
TreeNode balancedTree = constructBalancedTree(Enumerable.Range(1, 9));
// displayTree(balancedTree); // TODO: implement this!
}
static void Main(string[] args)
{
new Program().Run();
}
}
This paper explains in detail:
Tree Rebalancing in Optimal Time and Space
http://www.eecs.umich.edu/~qstout/abs/CACM86.html
Also here:
One-Time Binary Search Tree Balancing:
The Day/Stout/Warren (DSW) Algorithm
http://penguin.ewu.edu/~trolfe/DSWpaper/
If you really want to do it on-the-fly, you need a self-balancing tree.
If you just want to build a simple tree, without having to go to the trouble of balancing it, just randomize the elements before inserting them into the tree.
Make the median of your data (or more precisely, the nearest element in your array to the median) the root of the tree. And so on recursively.