Silme işlemi, çoğu veri yapısına eklemekten çok neden daha zordur?


33

Silme işleminin birçok (çoğu?) Veri yapısının yerleştirilmesinden çok daha zor olmasının nedeninin belirli bir nedeni olduğunu düşünebiliyor musunuz?

Hızlı örnek: bağlantılı listeler. Ekleme önemsiz olmakla birlikte, silme işleminin önemli ölçüde zorlaştıran birkaç özel durumu vardır. AVL ve Red-black gibi kendiliğinden dengelenen ikili arama ağaçları, ağrılı silme uygulamasının klasik örnekleridir.

Çoğu insanın düşündüğü gibi yapması gerektiğini söylemek isterim: Yapıcı olarak tanımlamak bizim için daha kolaydır, bu da kolay yerleştirmelere iyi gelir.


4
Ne hakkında pop, extract-min?
coredump

5
"Uygulaması zor", programlamadan (veri yapılarının ve algoritmaların özellikleri) ziyade psikoloji (biliş ve insan zihninin güçlü ve zayıf yönleri) meselesidir.
outis

1
Coredump'un aldattığını düşündüğüm gibi, yığınların en az ekleme kadar kolay olması gerekir (dizi destekli bir yığın için, haşhaş sadece bir işaretçi azaltmadır [1]; dizi). Ayrıca, yerleştirmelerin sık olduğu ve silme işlemlerinin daha az olduğu varsayıldığı bazı kullanım durumları vardır, ancak silme sayısının girmeleri aştığı çok sihirli bir veri yapısı olacaktır. [1] Muhtemelen de Liskov ders kitabı yoktu çünkü hatırladığım önlemek bellek sızıntıları, için popped nesnesine artık görünmez başvuru boş olmalıdır
Foon

43
“Garson, lütfen bu sandviçe daha fazla mayo ekler misin?” "Elbette, sorun değil efendim." "Hardalın hepsini de çıkarabilir misin?" "Uh ......"
kobaltduck 27:15

3
Çıkarma neden toplama işleminden daha karmaşık? Bölünme (veya asal çarpanlara ayırma) çarpmadan daha mı karmaşık? Kökler üstelleşmeden daha mı karmaşık?
mu çok kısa

Yanıtlar:


69

Bu sadece bir zihinsel durumdan daha fazlasıdır; Silme işleminin zor olmasının fiziksel (yani dijital) nedenleri vardır.

Sildiğinizde eskiden bir şeyin olduğu bir delik bırakırsınız. Ortaya çıkan entropinin teknik terimi "parçalanma" dır . Bağlantılı bir listede bu, kaldırılan düğümün etrafına "yama atmanızı" ve kullandığı belleği serbest bırakmanızı gerektirir. İkili ağaçlarda ağacın dengesizliğine neden olur. Bellek sistemlerinde, yeni atanan bloklar silme ile geride bırakılan bloklardan daha büyükse, belleğin bir süre kullanılmaz hale gelmesine neden olur.

Kısacası, yerleştirme daha kolaydır çünkü yerleştireceğiniz yeri seçebilirsiniz. Silme işlemi zordur, çünkü hangi öğenin silineceğini önceden tahmin edemezsiniz.


3
Parçalanma, bellekteki yapı veya şemalar için işaretçilerin ve dolaylı ifadelerin devreye girdiği bir konu değildir. Bellek içi, indirme nedeniyle bireysel düğümlerin nerede olduğu önemli değildir. Listeler için, dahili bir düğümü silmek (şemada delik açacağınız yer) ekleme işleminden biraz daha az işlem içerir (1 işaretçi ataması ve 1 ücretsiz ve 1 tahsisat ve 2 işaretçi ataması). Ağaçlar için, bir düğümün eklenmesi bir ağaç silme kadar dengesiz olabilir. Parçalanmanın önemli olmadığı, brito'nun bahsettiği zorluklara neden olan son davalar.
outis

12
Eklemelerin ve silmelerin öngörülebilirlik açısından farklı olduğuna katılmıyorum. Bir liste düğümünün "çevresine takılması", aynı düğümün yerine koyulması durumunda tam olarak tersine olandır. Her iki yönde herhangi bir noktada belirsizlik yoktur ve elementlerine içsel bir yapıya sahip olmayan herhangi bir kapta (örneğin dengeli bir ikili ağaç, eleman ofsetleri arasında katı bir ilişkiye sahip bir dizi) hiçbir şekilde “delik” yoktur. Bu yüzden, korkarım burada neden bahsettiğini bilmiyorum.
sqykly

2
Çok ilginç, ama iddiaların cevapsız olduğunu söyleyebilirim. Veri yapılarını basit / hızlı silme problemi olmadan kolayca organize edebilirsiniz. Sadece daha az yaygın, muhtemelen daha az kullanışlı.
luk32,

@sqykly Ben listenin kötü bir seçim olduğunu düşünüyorum çünkü orta yerleştirme ve orta ilişki aynı derecede zor. Bir vaka, diğerinin yeniden atandığı yeri hafızaya ayırır. Biri diğerinin bir deliği kapattığı bir delik açar. Bu nedenle, tüm durumlar ekleme işleminden daha karmaşık değildir.
ydobonebi

36

Neden silmek daha eklemek daha zor olma eğilimindedir? Veri yapıları silme işleminden ziyade ekleme ile tasarlanır ve haklı olarak yapılır.

Bunu göz önünde bulundurun - bir veri yapısından bir şeyi silmek için, ilk önce orada olması gerekir. Öyleyse önce onu eklemelisin, yani en çok senin eklemelerin kadar silme işlemine sahip olduğun anlamına geliyor. Bir veri yapısını ekleme için optimize ederseniz, silme için optimize edilmiş gibi en az fayda elde edeceğiniz garanti edilir.

Ek olarak, her bir öğeyi sırayla silmek için hangi kullanım var? Neden sadece hepsini bir anda temizleyen bir işlev çağırmıyorsunuz (sadece yeni bir tane oluşturarak)? Ayrıca, veri yapıları bir şey içerdiklerinde en faydalıdır. Öyleyse, eklemeler kadar fazla silme işlemi söz konusu olduğunda, pratikte pek yaygın olmayacak.

Bir şeyi optimize ettiğinizde, en çok ve en çok zaman alan şeyleri optimize etmek istersiniz. Normal kullanımda, bir veri yapısındaki öğelerin silinmesi ekleme işleminden daha az gerçekleşir.


4
Hayal edebileceğim bir kullanım durumu var. İlk yerleştirme ve daha sonra bireysel tüketim için hazırlanmış bir veri yapısı. Elbette bu nadiren görülen bir durumdur ve algoritmik olarak çok ilginç değildir, çünkü sizin de belirttiğiniz gibi, böyle bir işlem yerleştirmeye asimptotik olarak egemen olamaz. Belki, toplu ekleme işleminin amorti maliyeti oldukça iyi ve hızlı ve silme işlemi için basit olabileceğine dair bazı umutlar vardır, bu nedenle karmaşık ama pratik parti eklemeleri ve basit ve hızlı bireysel silmeler olacaktır. Kesinlikle çok nadir bir pratik ihtiyaç.
luk32

1
Mmm, bir örneğin ters sıralı bir vektör olabileceğini düşünüyorum. kÖğeleri çok hızlı bir şekilde ekleyebilirsiniz : ters sıralama girişi ve mevcut vektörle birleştirme - O(k log k + n). O zaman oldukça karmaşık bir şekilde yerleştirilmiş bir yapıya sahipsiniz, ancak üst uunsurları tüketmek önemsiz ve hızlı. Sadece sonuncuyu alın uve vektörün sonunu taşıyın. Yine de, eğer böyle bir şeye ihtiyaç duyan biri olursa, lanetleneceğim. Umarım bu en azından tartışmanı güçlendirir.
luk32,

En çok yaptığınız şey yerine, ortalama kullanım şekli için optimizasyon yapmak istememelisiniz?
Shiv

Basit bir FIFO iş sırası genellikle çoğu zaman boş kalmaya çalışır. İyi tasarlanmış bir sıra, hem girişler hem de silme işlemleri için iyi optimize edilmiş (yani O (1)) (ve çok iyi bir tanesi de hızlı eşzamanlı işlemleri destekleyecektir, ancak bu farklı bir konudur).
Kevin,

6

Zor değil.

İki kat bağlantılı listelerde, taktığınızda, bellek tahsis edeceksiniz ve daha sonra baş veya önceki düğümle ve kuyruk veya sonraki düğümle bağlanacaksınız. Sildiğinizde, tamamen aynı olanlardan sonra bağlantıyı açacak ve ardından belleği boşaltıyor olacaksınız. Bütün bu işlemler simetriktir.

Bu, her iki durumda da eklemek / silmek için düğüme sahip olduğunuzu varsayar. (Ve ekleme durumunda, daha önce ekleyeceğiniz düğüme sahip olduğunuzdan, bir şekilde eklemenin biraz daha karmaşık olduğu düşünülebilir.) Silme düğümü değil, yükü silme girişiminde bulunmaya çalışıyorsanız Düğümden sonra, elbette önce yükü listelemek için listeyi aramanız gerekecek, fakat bu silinme sıkıntısı değil, değil mi?

Dengeli ağaçlarda, aynısı geçerlidir: Bir ağaç genellikle yerleştirmeden hemen sonra ve ayrıca silme işleminden hemen sonra dengelenmeye ihtiyaç duyar. Yalnızca bir dengeleme yordamını denemek ve sahip olmak ve bir ekleme mi yoksa silme mi olursa olsun, her işlemden sonra uygulamak iyi bir fikirdir. Ağacı her zaman dengeli bırakan bir ekleme ve aynı zamanda ağacı her zaman dengeli bırakan bir silme işlemi yapmaya çalışıyorsanız, ikisi aynı dengeleyici rutini paylaşmadan, hayatınızı gereksiz yere karmaşıklaştırıyorsunuz.

Kısacası, birinin diğerinden daha zor olmasının bir nedeni yoktur ve bunun olduğunu buluyorsanız, o zaman düşünmeyi daha doğal bulma eğiliminin (çok insani) eğiliminin mağduru olmanız mümkündür. Yapıcı olarak, çıkartıcı olarak, silme işlemini olması gerekenden daha karmaşık bir şekilde uyguladığınız anlamına gelir. Ama bu bir insan meselesi. Matematiksel bir bakış açısıyla, hiçbir sorun yoktur.


1
Katılmıyorum AVL silme algoritması yerleştirmeden daha karmaşıktır. Bazı düğüm silme işlemleri için, genellikle özyinelemeli yapılan ancak özyinelemesiz olarak da yapılabilen tüm ağacı yeniden dengelemeniz gerekebilir. Eklemek için bunu yapmanız gerekmez. Tüm ağaç yeniden dengelemesinin her durumda önlenebileceği algoritma gelişmelerinden haberdar değilim.
Dennis

@Dennis: AVL ağaçlarının kural yerine istisnayı takip etmesi olabilir.
outis

@ IIRC'de, tüm dengeli arama ağaçlarının daha karmaşık silme yordamları vardır (ekleme yerine).
Raphael

Kapalı karma tabloları ne olacak ? Ekleme (nispeten) basittir, silme en azından zordur çünkü zordur, çünkü "X dizininde olması beklenen şeyi şu anda Y dizininde olması ve onu bulmamız ve geri koymamız gerekir" sorunlar.
Kevin,

3

Çalışma zamanı açısından , Vikipedi'deki veri yapısı işlemlerinin zaman karmaşıklığı karşılaştırmasına bakıldığında, ekleme ve silme işlemlerinin aynı karmaşıklığa sahip olduğuna dikkat edin. Buradaki profil silme işlemi, silinecek yapı elemanına bir referansınızın bulunduğu, indekse göre silmedir; ekleme, öğeye göredir. Uygulamada silmek için daha uzun çalışma süresi, genellikle dizinini silmek için değil de bir öğeye sahip olmanızdır, bu nedenle bir bulma işlemine de ihtiyacınız vardır. Tablodaki çoğu veri yapısı, yerleştirme konumu öğeye bağlı olmadığından veya yerleştirme sırasında konum dolaylı olarak belirlendiğinden ek için bir ek bulma gerektirmez.

Bilişsel karmaşıklığa gelince, soruda bir cevap var: son vakalar. Silme işlemi, ekleme işleminden daha fazlasına sahip olabilir (bu, genel davada henüz kurulmamıştır). Bununla birlikte, bu kenar durumlarından en azından bazılarının belirli tasarımlarda önlenmesi sağlanabilir (örneğin, bağlı bir listede bir sentinel düğüme sahip).


2
"Çoğu veri yapısı, ek için bir bulma gerektirmez." -- gibi? Aslında tam tersini iddia edebilirim. (Aynı pozisyonu tekrar bulmak kadar pahalı olan yerleştirme pozisyonunu "bulursunuz".)
Raphael

@Raphael: Bu cevap, işlem silme işleminin bir parçası olarak bulunmayan bağlantılı işlem karmaşıklığı tablosu bağlamında okunmalıdır. Sorunuza cevap olarak, yapıyı ortak isimle sınıflandırdım. Diziler, listeler, ağaçlar, karma tablolar, yığınlar, sıralar, kümeler ve kümeler, ağaçlar ve kümeler bir uç için bir bulma gerektirir; diğerleri ise, nesneye bağlı olmayan bir indeks kullanır (temel yığınlar, sıralar ve yığınlar için, yalnızca 1 indeks gösterilir ve bulma desteklenmez) ya da maddeden hesaplar. Grafikler, nasıl kullanıldığına bağlı olarak her iki yönde de gidebilir.
outis

... Denemeler ağaç sayılabilir; Ancak, kendi yapıları olarak sınıflandırılırsa, yerleştirme sırasında bir "bulma" olup olmadığı daha fazla tartışma konusudur, bu yüzden onu dahil etmiyorum. Veri yapısı listesinin, uygulama ile arayüzü dikkate almadığını unutmayın. Ayrıca, nasıl saydığınız, büyük ölçüde nasıl sınıflandırdığınıza bağlıdır. Bakalım daha objektif bir ifade düşünebilir miyim.
outis

Aklımdayken, sözlük / set arayüzünü (CS’de olduğu gibi) düşündüğümü kabul ediyorum. Her neyse, bu tablo yanıltıcı ve (iirc) birçok yerde bile yanlış - Wikipedia, CS yanlış bilgi çukuru. : /
Raphael

0

Bahsi geçen tüm konuların üstünde, veri referans bütünlüğü söz konusudur. SQL'deki veritabanları gibi veri yapılarının en doğru şekilde oluşturulması için Oracle referans bütünlüğü çok önemlidir.
Yanlışlıkla icat etmediğinizden emin olmak için icat ettiği pek çok şeyi.
Örneğin, silme işleminde yalnızca silmeye çalıştığınız şeyi silmez, aynı zamanda ilgili verilerin temizliğini de tetikler.
Bu veritabanını önemsiz verilerden temizlemenin yanı sıra verilerin bütünlüğünü de korur.
Örneğin, ikinci tabloda ana babalara ve türlere ilişkin ilgili kayıtlar olarak tablolarınız var.
Ebeveyn ana masanın olduğu yer. Eğer yerinde sağlam bir referans bütünlüğü yoksa, herhangi bir tablodaki kayıtları silebilir ve daha sonra tam aile bilgilerinin nasıl alınacağını bilemezsiniz çünkü alt tablodaki verileriniz ve üst tabloda hiçbir şey yoktur.
Bu nedenle referans bütünlüğü denetimi, alt tablodaki kayıtlar temizlenene kadar ana tablodaki kaydı silmenize izin vermez.
Bu yüzden çoğu veri kaynağında verileri silmek daha zordur.


Sorunun veritabanları yerine bağlantılı listeler, karma tablolar vb. Gibi bellek içi yapılar hakkında sorular sorduğunu düşünüyorum, ancak referans bütünlüğü bellek içi yapılar için bile önemli bir konudur.
supercat,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.