Neden SortedSet<T>.DeÄŸil't O(log N) GetViewBetween?
.NET 4.0 , SortedSet<T> yöntemi vardır sınıf bir ağaç parçası ikisi arasındaki tüm değerleri belirtilen içeren bir arayüz görünüm verir GetViewBetween(l, r) denir. SortedSet<T> kırmızı-siyah ağaç olarak uygulandığı göz önüne alındığında, ben doğal olarak O(log N) zaman çalıştırmak için bekliyoruz. C benzer bir yöntem Java TreeSet.headSet/tailSet ve logaritmik std::set::lower_bound/upper_bound.
Ancak, bu doğru değil. Aşağıdaki kodu GetViewBetween O(log N) sürüm bu kod 1-2 sn içinde kestirecek eşdeğer ise 32 saniye çalışır.
var s = new SortedSet<int>();
int n = 100000;
var rand = new Random(1000000007);
int sum = 0;
for (int i = 0; i < n; i) {
s.Add(rand.Next());
if (rand.Next() % 2 == 0) {
int l = rand.Next(int.MaxValue / 2 - 10);
int r = l rand.Next(int.MaxValue / 2 - 10);
var t = s.GetViewBetween(l, r);
sum = t.Min;
}
}
Console.WriteLine(sum);
System.dll dotPeek ve burada var ve ne derlenmiş halini açtım:
public TreeSubSet(SortedSet<T> Underlying, T Min, T Max, bool lowerBoundActive, bool upperBoundActive)
: base(Underlying.Comparer)
{
this.underlying = Underlying;
this.min = Min;
this.max = Max;
this.lBoundActive = lowerBoundActive;
this.uBoundActive = upperBoundActive;
this.root = this.underlying.FindRange(this.min, this.max, this.lBoundActive, this.uBoundActive);
this.count = 0;
this.version = -1;
this.VersionCheckImpl();
}
internal SortedSet<T>.Node FindRange(T from, T to, bool lowerBoundActive, bool upperBoundActive)
{
SortedSet<T>.Node node = this.root;
while (node != null)
{
if (lowerBoundActive && this.comparer.Compare(from, node.Item) > 0)
{
node = node.Right;
}
else
{
if (!upperBoundActive || this.comparer.Compare(to, node.Item) >= 0)
return node;
node = node.Left;
}
}
return (SortedSet<T>.Node) null;
}
private void VersionCheckImpl()
{
if (this.version == this.underlying.version)
return;
this.root = this.underlying.FindRange(this.min, this.max, this.lBoundActive, this.uBoundActive);
this.version = this.underlying.version;
this.count = 0;
base.InOrderTreeWalk((TreeWalkPredicate<T>) (n =>
{
SortedSet<T>.TreeSubSet temp_31 = this;
int temp_34 = temp_31.count 1;
temp_31.count = temp_34;
return true;
}));
}
Yani, FindRange belli ki ** 16 yaşında, ama bundan sonra düğümlerini anlatırken sadece bulundu alt doğrusal zamanlı bir geçiş yapar VersionCheckImpl... diyoruz!
- Neden bu geçişi her zaman yapmak zorunda mısın?
- Neden .NET anahtar gibi C ya da Java tabanlı bölme
O(log N)bir yöntem bir ağaç içermiyor?gerçektendurumlar çok yararlı.
CEVAP
version alanla ilgili
UPDATE1:
Hafızam, bir sürü(belki?) KÜÇÜK koleksiyonlar 20* *alan var.
Önce foreach hakkında:
msdn link buna göre
Foreach deyimi bir dizi ya da bir nesne koleksiyonundaki her öğe için gömülü bir grup ifadeleri tekrarlar. Foreach deyimi koleksiyonu istenen bilgileri almak için yinelemek kullanılır, ama koleksiyon içeriğini öngörülemeyen yan etkileri önlemek için değiştirmek için kullanılmamalıdır.
Diğer birçok koleksiyonları korunmaktadır verileri foreach sırasında değiştirilmez
Örneğin, HashTable25**:
public virtual bool MoveNext()
{
if (this.version != this.hashtable.version)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
}
..........
}
Ama SortedSet<T>'MoveNext() yöntem:
public bool MoveNext()
{
this.tree.VersionCheck();
if (this.version != this.tree.version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
....
}
UPDATE2: bir
Ama O(N) belki de sadece Count özelliği version için değil, aynı zamanda döngü.
MSDN of GetViewBetween dediği için:
Bu yöntem karşılaştırıcısı tarafından tanımlanan lowerValue ve upperValue arasında kalan elemanları aralığının bir görünüm verir, ....Görünümü ve temel SortedSet(T) hem de değişiklik yapabilirsiniz.
Her güncelleştirme için eşitleme olmalı count alanı (anahtar ve değer zaten aynı). Emin Count yapmak doğru değildir
Hedefe ulaşmak için iki ilke vardı:
- Microsoft
- Mono
İlk.MS,kendi kodu, GetViewBetween()'nın performansı ve Count Tesisin performansını kazanmak. kurban
VersionCheckImpl() Count özelliği senkronize etmek için tek yoldur.
İkinci Olarak,Mono. GetCount()kendi yöntemi mono,GetViewBetween() kodu daha Hızlı, ama:
internal override int GetCount ()
{
int count = 0;
using (var e = set.tree.GetSuffixEnumerator (lower)) {
while (e.MoveNext () && set.helper.Compare (upper, e.Current) >= 0)
count;
}
return count;
}
Her zaman(N) iÅŸlemi!

Neden't GCC*****a (**)*(**) optim...
Neden' ◎ܫ◎ ve fonksiyonu t JavaSc...
Neden boyutu(x ) x artım değil mi?...
Neden Java statik olarak bir sınıf bil...
Neden't JUnit assertNotEquals yön...