2011-03-21 6 views
37

NULL üzerinde sentinel lenf nodu yararları olduğunu belirtir: operasyonBir sentinel düğümü NULL üzerinden nasıl fayda sağlar? <a href="http://en.wikipedia.org/wiki/Sentinel_node">Sentinel Node wikipedia page</a> üzerinde

  • Artış hızı
  • Azaltılmış algoritmik kod boyutu
  • Artan veri yapısı sağlamlığı (belki).

Gerçekten sentinel düğümü karşı denetler hızlı olacaktır anlamıyorum (veya düzgün bir bağlantılı liste veya ağaç nasıl uygulanacağı), bu yüzden bu iki kısım soru daha olduğunu varsayalım:

  1. Gönderilen düğümün NULL'den daha iyi bir tasarıma neden olan nedir?
  2. Bir sentinel düğümünü (örneğin) bir listede nasıl uygularsınız?

cevap

22

. Ancak, "bul" tipi algoritmalar için kullanıldığında bazı gerçek kazanç var. Örneğin, x belirli bir değer bulmak istediğiniz bağlantılı bir liste listesi std::list düşünün.

Ne gözcüler olmadan yapardın geçerli:

for (iterator i=list.begin(); i!=list.end(); ++i) // first branch here 
{ 
    if (*i == x) // second branch here 
    return i; 
} 
return list.end(); 

Ama Gözcü ile

(tabii ki, son aslında bu gerçek bir düğüm olmak zorunda ...):

Ek şube listenin sonuna test etmek için gerek yoktur bakınız
iterator i=list.begin(); 
*list.end() = x; 

while (*i != x) // just this branch! 
    ++i; 

return i; 

- değeri her zaman orada olması sağlanır, böylece otomatik olarak end() dönecektir x "size bulunabilir edilemezse geçerli "öğeler.

Başka bir harika ve gerçekten yararlı olan sentinel uygulamaları için, en çok std::sort uygulamalarında kullanılan sıralama algoritması olan "intro-sort" konusuna bakın. Birkaç dalı kaldırmak için sentinel kullanan bölüm algoritmasının harika bir çeşidine sahiptir.

+0

sayesinde. Sadece yineleme açısından düşünüyordum, bu yüzden gerçekten fayda görmedim. – spbots

+0

Bir şey değil - nöbetçi gerçekten istismar edebilirsiniz algoritmalar için değişmezleri ayarı sadece akıllı bir yoldur! – ltjax

+3

'find()' veri yapısını değiştirmesi gerektiği fikrinden hoşlanmıyorum; Örneğin, hepsi sadece öğeleri arıyor olsa bile, birden fazla iş parçacığı tarafından 'bul 'kullanarak kural dışı bırakılır. – 6502

8

Sorunuzun cevabı (1) bağlantılı Vikipedi girişe son cümlesinde bağlıdır: (kendisi nil dahil) nil "normalde şimdi NULL olarak bağlantı bağlayacak düğümler olarak '', bu kaldırır NULL'u kontrol etmek için pahalı bir şube operasyonuna ihtiyaç var. "

Normalde erişmeden önce NULL için bir düğümü test etmeniz gerekir. Bunun yerine, geçerli bir nil düğümüne sahipseniz, ilk testi yapmanıza gerek yoktur, bir karşılaştırma ve bir koşullu dalı kaydetmeniz gerekmez; bu durum, eğer şube yanlış tahmin edildiğinde modern süperşarjlı CPU'larda pahalıya mal olabilir.

0

Ben standart şablon kütüphanesi bağlamında cevaplamaya çalışacağız: Görüşme olarak

1) "Bir sonraki()" BOŞ mutlaka-sonuna-listesinde göstermez için. Bir bellek hatası oluştuysa ne olur? Bir sentinel düğümün döndürülmesi, listenin sonunun ortaya çıktığını ve başka bir sonucun olmadığını belirtmenin kesin bir yoludur. Başka bir deyişle, NULL, sadece listenin sonunu değil, çeşitli şeyleri gösterebilir.

2) Bu yalnızca olası bir yöntemdir: listenizi oluştururken, sınıfın dışında paylaşılmayan özel bir düğüm oluşturun (örneğin "lastNode"). Listenin sonuna kadar yinelediğinizi saptadıktan sonra, "next()" değerini "lastNode" a geri döndürün. Ayrıca "end()" adlı bir yöntem var "lastNode" için bir başvuru döndürün. Son olarak, sınıfınızı nasıl uyguladığınıza bağlı olarak, düzgün çalışması için karşılaştırma operatörünü geçersiz kılmanız gerekebilir.

Örnek:

sadece basit iterasyon yapıyor ve elementler verilere bakarak değilseniz gözcüler ile hiçbir avantajı yoktur
class MyNode{ 

}; 

class MyList{ 

public: 
    MyList() : lastNode(); 

    MyNode * next(){ 

     if (isLastNode) return &lastNode; 
     else return //whatever comes next 
    } 

    MyNode * end() { 

     return &lastNode; 
    } 

    //comparison operator 
    friend bool operator == (MyNode &n1, MyNode &n2){ 

     return (&n1 == &n2); //check that both operands point to same memory 
    } 


private: 
    MyNode lastNode; 
}; 


int main(){ 

    MyList list; 
    MyNode * node = list.next(); 

    while (node != list.end()){ 

    //do stuff! 

    node = list.next(); 
    } 

    return 0; 
} 
52

Biraz kod örneği teorik tartışma daha iyi bir açıklama olacağını düşünüyoruz. Aşağıdaki

NULL iki işaretçiler first ve last ilk ve son noktasının adresini tutmak için kullanılır listesinin sonunu ve işaretlemek için kullanılır düğümlerin bir çift bağlı bir listede düğüm silme kodudur:

// Using NULL and pointers for first and last 
if (n->prev) n->prev->next = n->next; 
     else first = n->next; 
if (n->next) n->next->prev = n->prev; 
     else last = n->prev; 

ve bu yerine listedeki ilk düğümün adresi özel düğüm ve next alanında depolanan özel kukla listesinin sonunu işaretlemek için düğüm ve orada aynı koddur listedeki son düğüm özel kukla düğümün prev alanında depolanır:

// Using the dummy node 
n->prev->next = n->next; 
n->next->prev = n->prev; 

basitleştirme daha da açık düğüm sokulması için mevcuttur; Örnek düğüm x önce düğümü n eklemek için kodu olacaktır (son pozisyonda yerleştirilmesini anlamına x == NULL veya x == &dummy sahiptir):

// Using NULL and pointers for first and last 
n->next = x; 
n->prev = x ? x->prev : last; 
if (n->prev) n->prev->next = n; 
     else first = n; 
if (n->next) n->next->prev = n; 
     else last = n; 

ve

// Using the dummy node 
n->next = x; 
n->prev = x->prev; 
n->next->prev = n; 
n->prev->next = n; 

için uzaklaştırıldı kukla düğüm yaklaşımı görüldüğü gibi iki bağlantılı bir liste tüm özel durumlar ve şartlar. şimdi çok daha mantıklı

aşağıdaki resim hafızasında aynı liste için iki yaklaşımı temsil ... örneğin

NULL/dummy node alternatives for a doubly-linked list

+1

+1 başka iyi bir örnek. – ltjax

İlgili konular