Start paying off the debt because there are at least two important topics to write about that are dependent on this series and it's hard to move on without solving it.
We have now covered five different cache implementations, respectively:
Simplekeycache: Constructs a string as a key, using a dictionary as a store.
Prefixtreecache: Use the prefix tree for storage.
Sortedlistcache: Use sorted lists or binary search trees for storage.
Hashedlistcache: Hash The expression tree first, and then remove the two-fork search tree from the dictionary.
Dictionarycache: The comparison method of hash value and expression tree is implemented, and the dictionary is used to store it directly.
If you want to get from a store that already contains n expression trees, looking for an expression tree with m nodes, according to the analysis of several articles, in theory, in addition to Hashedlistcache time complexity is O (M * log (n)), the other implementations of the time complexity is O (m). But is the theoretical result exactly the same as the actual use? If exactly, then why do we continue to design the remainder of the program when we build the first Simplekeycache, which is both simple and intuitive and "efficient" (to achieve the best theoretical time complexity O (m))? If you have not thought of the article after reading it, this shows you. NET programming "common sense" also needs to strengthen.
So let's write a program to let the data speak.
This is a console application that accepts user parameters and generates test data or performs performance comparisons.
Generate test data
Need to test, naturally prepare test data, and the test data required here is naturally a large number of expression trees.
The variety of expression trees is very numerous, and if you want to construct various types of trees, the cost is very expensive. So here, we only construct the so-called "integer arithmetic" expression to experiment. For such an expression, each operator occupies one node, each number occupies another, so the number of nodes m is the number of operators p, and the number of numbers Q sum. And because each tuple is a two-dollar operator, P equals q-1. So we can draw the relationship between M and P:
m = 2p + 1
Knowing the relationship, we can obtain a certain scale of experimental data. So we write a simple applet to randomly output an expression:
private static void WriteSingleExpression(
TextWriter writer, Random random, int opCount)
{
string ops = "+-*/";
writer.Write(random.Next(100));
while (opCount-- > 0)
{
writer.Write(" ");
writer.Write(ops[random.Next(4)]);
writer.Write(" ");
writer.Write(random.Next(100));
}
writer.WriteLine();
}