2009-05-18 11 views
12

Jak usunąć element z tablicy i przesunąć pozostałe elementy w dół. Tak więc, jeśli mam tablicę,Usuń element tablicy i przenieś pozostałe.

array[]={1,2,3,4,5} 

i chcesz usunąć 3 i przesunięcie pozostałej, więc mam,

array[]={1,2,4,5} 

Jak bym go o to w jak najmniejszej ilości kodu?

Odpowiedz

21

Wystarczy nadpisać co usuwasz z kolejnej wartości w tablicy, propagować tę zmianę, a następnie pamiętać, gdzie nowy końcowy jest:

int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 

// delete 3 (index 2) 
for (int i = 2; i < 8; ++i) 
    array[i] = array[i + 1]; // copy next element left 

Teraz twoja tablica jest {1, 2, 4, 5, 6, 7, 8, 9, 9}. Nie można usunąć dodatkowego 9, ponieważ jest to macierz o wielkości statystycznej, wystarczy ją zignorować. Można to zrobić z std::copy:

std::copy(array + 3, // copy everything starting here 
      array + 9, // and ending here, not including it, 
      array + 2) // to this destination 

C++ 11, zastosowanie może wykorzystywać std::move (przeciążenia algorytm nie przeciążenia) zamiast narzędzie.

Bardziej ogólnie, należy std::remove do usunięcia elementów pasujących wartość:

// remove *all* 3's, return new ending (remaining elements unspecified) 
auto arrayEnd = std::remove(std::begin(array), std::end(array), 3); 

Jeszcze bardziej ogólnie, istnieje std::remove_if.

Należy pamiętać, że użycie tutaj std::vector<int> może być bardziej odpowiednie, ponieważ jest to "prawdziwa" dynamicznie przydzielana tablica rozmiarów. (W tym sensie, że prośba o jego size() odzwierciedla usunięte elementy.)

+0

brak wzmianki o 'copy (iter, iter, iter)' lub 'move (iter, iter, iter)'? –

+0

@MooingDuck: Powrót w ruchu '09 '(iter, iter, iter) 'nie istniało. : P Steve Jessop wspomina o tym poniżej, byłoby to (były) kradzież, aby umieścić to w mojej odpowiedzi, imo. – GManNickG

+0

@GManNickG: kradnij - szczególnie na stare pytania Myślę, że ideałem jest, aby zaakceptowana odpowiedź była dobra. Czasem jest trochę bezczelnie napisać odpowiedź, która zawiera wszystkie najlepsze odpowiedzi na wszystkie inne pytania, ale jestem pewien, że jest to jednak zatwierdzona praktyka, ISTR często poleca to. Wszystko, czego nie chcę, żebyś użył, nie będę wysyłał do SO :-) –

3

W zależności od wymagań możesz użyć list standardowych w przypadku tego typu operacji. Możesz przeglądać listę, aż znajdziesz element i wymazać element. Jeśli nie możesz korzystać z list, będziesz musiał samodzielnie wszystko zmienić, korzystając z jakiegoś algorytmu lub ręcznie.

+0

Po drugie proponuję użyć std :: list. Jeśli chcesz usunąć element ze środka wektora, będzie to wymagało przesunięcia wszystkich elementów za nim, co jest bardzo kosztowne (średnio O (n)). Jednak usunięcie elementu ze środka listy podczas przechodzenia przez nią jest prostą operacją O (1). – newacct

4

Nie możesz osiągnąć tego, co chcesz, za pomocą tablic. Zamiast tego użyj wektorów i przeczytaj o algorytmie std :: remove. Coś w rodzaju:

std::remove(array, array+5, 3) 

będzie działać na macierzy, ale jej nie skróci (dlaczego - ponieważ jest to niemożliwe). Wektorami, że to będzie coś

v.erase(std::remove(v.begin(), v.end(), 3), v.end()) 
+0

Domyślam się, że jest to niemożliwe, ponieważ pamięć została już alokowana, więc początkowy blok pamięci nadal będzie zawierał informacje o tablicy 5 elementów. – Rodrigo

9

std :: kopii spełnia swoje zadanie w miarę ruchomych elementów jest zaniepokojony:

#include <algorithm> 

std::copy(array+3, array+5, array+2); 

Należy pamiętać, że warunkiem koniecznym dla kopii jest to, że odbiorca nie musi być w zasięgu źródła. Dopuszczalne jest nakładanie się zakresów.

Również ze względu na sposób pracy tablic w C++, to nie "skraca" tablicy. Po prostu przesuwa elementy wokół niego. Nie ma sposobu na zmianę rozmiaru tablicy, ale jeśli używasz osobnej liczby całkowitej do śledzenia jej "rozmiaru", co oznacza rozmiar części, o którą się troszczysz, możesz ją oczywiście zmniejszyć.

Więc tablica będziesz skończyć ze będzie tak, jakby były inicjowane z:

int array[] = {1,2,4,5,5}; 
20

Można użyć memmove(), ale trzeba śledzić rozmiaru tablicy siebie:

size_t array_size = 5; 
int array[5] = {1, 2, 3, 4, 5}; 

// delete element at index 2 
memmove(array + 2, array + 3, (array_size - 2 - 1) * sizeof(int)); 
array_size--; 

W C++, choć byłoby lepiej użyć std::vector:

std::vector<int> array; 
// initialize array... 

// delete element at index 2 
array.erase(array.begin() + 2); 
+1

Należy pamiętać, że memmove() działa tylko dla typów POD, podczas gdy OTOH prawie każdy typ może być używany z wektorem, nawet te, które mają zdefiniowany przez użytkownika operator =(). –

0

Jeśli obawiasz się o rozmiar kodu i/lub wydajność (również dla analizy WCET, jeśli potrzebujesz), myślę, że to prawdopodobnie będzie jeden z bardziej przejrzystych rozwiązań (do wyszukiwania i usuwania elementów):

unsigned int l=0, removed=0; 

for(unsigned int i=0; i<count; i++) { 
    if(array[i] != to_remove) 
     array[l++] = array[i]; 
    else 
     removed++; 
} 

count -= removed; 
0

Wystarczy więc zauważyć: Jeżeli wymóg, aby zachować elementy zlecenia jest zrelaksowany jest o wiele bardziej wydajne, aby zastąpić element jest usuwany z ostatni element.