Czy potrafisz wymyślić jakiś konkretny powód, dla którego usunięcie jest zwykle znacznie trudniejsze do wdrożenia niż wstawienie dla wielu (większości?) Struktur danych?
Szybki przykład: listy połączone. Wstawianie jest trywialne, ale usuwanie ma kilka specjalnych przypadków, które znacznie utrudniają. Samowyrównujące się drzewa wyszukiwania binarnego, takie jak AVL i czerwono-czarny, to klasyczne przykłady bolesnej implementacji usuwania.
Chciałbym powiedzieć, że ma to związek ze sposobem myślenia większości ludzi: łatwiej nam jest konstruktywnie definiować rzeczy, co ładnie prowadzi do łatwych wstawek.
algorithms
data-structures
Leo Brito
źródło
źródło
pop
,extract-min
?Odpowiedzi:
To coś więcej niż stan umysłu; istnieją fizyczne (tj. cyfrowe) powody, dla których usuwanie jest trudniejsze.
Po usunięciu pozostawiasz dziurę, w której kiedyś coś było. Technicznym terminem wynikowej entropii jest „fragmentacja”. Na połączonej liście wymaga to „załatania” usuniętego węzła i cofnięcia przydziału pamięci, której używa. W drzewach binarnych powoduje to niezrównoważenie drzewa. W systemach pamięci powoduje, że pamięć nie jest używana przez pewien czas, jeśli nowo przydzielone bloki są większe niż bloki pozostawione przez usunięcie.
Krótko mówiąc, wstawianie jest łatwiejsze, ponieważ możesz wybrać, gdzie chcesz wstawić. Usunięcie jest trudniejsze, ponieważ nie można z góry przewidzieć, który element zostanie usunięty.
źródło
Dlaczego trudniej jest usunąć niż wstawić? Struktury danych są zaprojektowane bardziej z myślą o wstawianiu niż usuwaniu i słusznie.
Zastanów się - aby usunąć coś ze struktury danych, musi to być przede wszystkim. Musisz go najpierw dodać, co oznacza, że co najwyżej masz tyle usunięć, ile wstawień. Jeśli zoptymalizujesz strukturę danych do wstawienia, masz gwarancję uzyskania co najmniej takiej samej korzyści, jak gdyby została zoptymalizowana do usunięcia.
Ponadto jaki jest pożytek z sekwencyjnego usuwania każdego elementu? Dlaczego nie wywołać jakiejś funkcji, która usuwa to wszystko naraz (być może po prostu tworząc nową)? Również struktury danych są najbardziej przydatne, gdy faktycznie coś zawierają. Tak więc przypadek usunięcia tylu elementów, ile wstawień, w praktyce nie będzie zbyt powszechny.
Kiedy coś optymalizujesz, chcesz zoptymalizować to, co robi najwięcej i które zajmuje najwięcej czasu. W normalnym użyciu usuwanie elementów struktury danych zdarza się rzadziej niż wstawianie.
źródło
k
szybko dodać partię elementów: odwróć sortowanie danych wejściowych i scal z istniejącym wektorem -O(k log k + n)
. Następnie masz strukturę z dość skomplikowanym wstawianiem, ale zużywanie najlepszychu
elementów jest banalne i szybkie. Po prostu weź ostatniu
i przenieś koniec wektora. Chociaż, jeśli ktokolwiek kiedykolwiek potrzebuje takiej rzeczy, będę cholerny. Mam nadzieję, że to przynajmniej wzmocni twój argument.To nie jest trudniejsze.
W przypadku podwójnie połączonych list podczas wstawiania będziesz alokować pamięć, a następnie będziesz łączył się z nagłówkiem lub poprzednim węzłem, a także z ogonem lub następnym węzłem. Po usunięciu rozłączysz się dokładnie z tym samym, a następnie zwolnisz pamięć. Wszystkie te operacje są symetryczne.
Zakłada się, że w obu przypadkach masz węzeł do wstawienia / usunięcia. (A w przypadku wstawiania, że masz również węzeł do wstawienia, więc w pewnym sensie wstawianie może być uważane za nieco bardziej skomplikowane.) Jeśli próbujesz usunąć, nie usuwając węzła, ale ładunek węzła, to oczywiście będziesz musiał najpierw przeszukać listę pod kątem ładunku, ale to nie jest wada usunięcia, prawda?
W przypadku zrównoważonych drzew to samo dotyczy: drzewo zasadniczo wymaga równoważenia natychmiast po wstawieniu, a także natychmiast po usunięciu. Dobrym pomysłem jest wypróbowanie tylko jednej procedury równoważenia i stosowanie jej po każdej operacji, niezależnie od tego, czy była to wstawianie, czy usuwanie. Jeśli próbujesz wprowadzić wstawkę, która zawsze pozostawia drzewo w równowadze, a także usunięcie, które zawsze pozostawia drzewo w równowadze, bez jednoczesnego korzystania z tej samej procedury równoważenia, niepotrzebnie komplikujesz swoje życie.
Krótko mówiąc, nie ma powodu, dla którego jedno powinno być trudniejsze od drugiego, a jeśli okaże się, że tak jest, to w rzeczywistości możliwe jest, że jesteś ofiarą (bardzo ludzkiej) tendencji, by uważać za bardziej naturalne myślenie konstruktywnie niż subtraktywnie, co oznacza, że możesz implementować usuwanie w sposób, który jest bardziej skomplikowany niż to konieczne. Ale to ludzki problem. Z matematycznego punktu widzenia nie ma problemu.
źródło
Jeśli chodzi o czas wykonywania, patrząc na porównanie złożoności czasu operacji struktury danych na Wikipedii, zauważ, że operacje wstawiania i usuwania mają tę samą złożoność. Profilowana tam operacja usuwania polega na usunięciu według indeksu, w którym znajduje się odwołanie do elementu struktury do usunięcia; wstawianie jest według pozycji. Dłuższy czas usuwania w praktyce wynika z tego, że zwykle masz element do usunięcia, a nie jego indeks, więc potrzebujesz również operacji wyszukiwania. Większość struktur danych w tabeli nie wymaga dodatkowego wyszukiwania dla wstawki, ponieważ pozycja umieszczenia nie jest zależna od elementu lub pozycja jest ustalana domyślnie podczas wstawiania.
Jeśli chodzi o złożoność poznawczą, w pytaniu jest odpowiedź: przypadki skrajne. Usunięcie może zawierać ich więcej niż wstawienie (nie zostało to jeszcze ustalone w ogólnym przypadku). Jednak przynajmniej niektórym z tych przypadków brzegowych można uniknąć w niektórych projektach (np. Mieć węzeł wartowniczy na połączonej liście).
źródło
Oprócz wszystkich wspomnianych problemów wiąże się to z integralnością referencyjną danych. Dla najbardziej poprawnie budowanej struktury danych, takiej jak bazy danych w SQL, integralność referencyjna Oracle jest bardzo ważna.
Aby upewnić się, że nie zniszczysz go przypadkowo, wymyślono wiele różnych rzeczy.
Na przykład kaskada usuwania, która nie tylko usuwa to, co próbujesz usunąć, ale także uruchamia czyszczenie powiązanych danych.
Ta oczyszczająca baza danych z niepotrzebnych danych, a także zachowuje nienaruszoną integralność danych.
Na przykład masz tabele z rodzicami i rodzajami jako powiązane rekordy w drugiej tabeli.
Gdzie rodzic jest głównym stołem. Jeśli nie masz wzmocnionej integralności referencyjnej, możesz usunąć dowolne rekordy w dowolnej tabeli, a później nie będziesz wiedział, jak uzyskać pełne informacje o rodzinie, ponieważ masz dane w tabeli podrzędnej i nic w tabeli nadrzędnej.
Dlatego sprawdzanie integralności referencyjnej nie pozwoli ci usunąć rekordu z tabeli nadrzędnej, dopóki rekordy z tabeli podrzędnej nie zostaną wyczyszczone.
I dlatego w większości źródeł danych trudniej jest usunąć dane.
źródło