Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[C++]Usuwanie elementów tablicy.

31 Sty 2010 20:46 16918 18
  • Poziom 9  
    Wie ktoś może jak usunąć określone elementy z tablicy? Mam taki program i chciałbym żeby usuwał on litery z tablicy, ale nie wiem jak usunąć wybrany element z tablicy ;/
    Code:
    #include<iostream>
    

    using namespace std;

    int main()
    {
       char dozwolone[10]={0,1,2,3,4,5,6,7,8,9};
       char* znak=new char[50];
       cin>>znak;
       int i=0;
       int k=0;
       int c;
       while(znak[i]!=0)
       {
          c=znak[i]-'0';
          for(int j=0;j<=9;j++)
          {
             if(c==dozwolone[j])
             {
                cout<<c<<endl;
                k++;
             }
          }
          i++;
       }
       delete[] znak;
       system("pause");
       return 0;
    }
  • Poziom 27  
    Spróbuj najpierw zdefiniować co rozumiesz pod pojęciem "usunąć z tablicy".
  • Poziom 9  
    Np, jak w tablicy jest 5 elementów : 5,6,e,4,g to chcę, aby po usunięciu były w tablicy 3 elementy:5,6,4
  • Poziom 18  
    Kod, który pokazałeś, jest tak na prawdę w języku C, nie C++. W języku C++ usuwanie elementów z tablicy wykonuje się to za pomocą standardowego algorytmu remove_if. Aby z niego skorzystać, należy napisać predykat jednoargumentowy (unarny) zwracający true wtedy, gdy dany znak nie należy do zestawu dozwolonych znaków. Ponieważ algorytm remove_if tak na prawdę nie usuwa niechcianych elementów z pojemnika, a tylko przesuwa je na koniec, zazwyczaj "opakowuje" się go metodą erase pojemnika.
    Zakładając, ze masz napisany predykat "sprawdzacz()", zadanie usuwania elementów jest banalne:
    Code:
    p.erase( remove_if( p.begin(), p.end(), sprawdzacz ), p.end() );

    gdzie "p" oznacza pojemnik, np. listę lub vector.
    Jeśli upierasz się przy wykorzystaniu tablicy znakowej, też można skorzystać z tego algorytmu, ale już bez erase, np. tak:
    Code:
    char *koniec = remove_if( znak, znak+50, sprawdzacz ), znak+50 );

    Wskaźnik "koniec" po wykonaniu tej instrukcji wskazuje na pierwszy element nie należący do zestawu dozwolonych znaków; wszystkie elementy od "znak" do "koniec-1" to elementy dozwolone, z zachowaniem ich pierwotnego porządku.

    HTH,
    Dariusz
  • Poziom 9  
    A mógłbyś powiedzieć mniej więcej co się podaje w parametrach tej funkcji?
  • Poziom 18  
    Jak pisałem, chodzi o predykat unarny, czyli jednoargumentowy. Tym argumentem jest, oczywiście, element przechowywany w pojemniku (tablicy) - w Twoim przypadku znak. Predykat zwraca true, gdy znak nie należy do dozwolonego zestawu, false w przeciwnym przypadku.

    Dariusz
  • Moderator Programowanie
    Drogi kolego Dariusz Bismor,
    czy byłby kolega łaskaw opisać użycie w/w funkcji ponownie, bardziej zrozumiałym językiem. Zwłaszcza prosiłbym o unikanie zwrotów takich jak predykat unarny.
    Proszę nie zapominać, że post jest skierowany do początkującego programisty.

    Z góry dziękuję, arnoldziq
  • Poziom 10  
    Do tego celu najlepiej zwykłą tablicę zastąpić vectorem ze standardowej biblioteki STL. Obsługa jest bardzo prosta, do elementów odnosisz się jak w zwykłej tablicy, vector może przechowywać dowolne typy danych, obsługa odbywa się za pomocą kilku prostych funkcji, no i vector w razie potrzeby sam zwiększa swój rozmiar. Zainteresuj się biblioteką STL i kontenerami, a w szczególności vectorem. Do Twojego problemu to idealne rozwiązanie.
  • Poziom 18  
    W zasadzie wydaje mi się, że prośba arnoldziq'a ociera się o punkt 16 regulaminu forum (i to dwukrotnie), ale w końcu to moderator, a ja wywołany do tablicy zawsze karnie odpowiadam.

    Znaczenie słowa predykat w kontekście programowania w języku C++ wynika z punktu 25 akapit 7 i 8 Standardu języka C++: predykat to obiekt funkcyjny zwracający wartość typu bool. Dokładne wyjaśnienie, co to jest obiekt funkcyjny, przekracza ramy forum - polecam jakąkolwiek książkę na temat biblioteki standardowej. Na potrzeby tego wątku wystarczy założyć - jak zrobił to autor pytania w piątej wypowiedzi - że jest to funkcja.

    Funkcja unarna i binarna to po prostu funkcje jedno- i dwuargumentowe. Używam tych nazw, bo używa ich i Standard (patrz 20.5.3), ale podaję też polskie nazwy.

    Użycie funkcji - jeśli jest ona już zdefiniowana - zostało podane w mojej pierwszej wypowiedzi:
    "Zakładając, ze masz napisany predykat "sprawdzacz()", zadanie usuwania elementów jest banalne ...".

    Czymś jeszcze - poza napisaniem gotowego kodu (patrz punkt 16 regulaminu!) - mogę służyć?

    Dariusz
  • Poziom 13  
    elektronik512 napisał:
    Np, jak w tablicy jest 5 elementów : 5,6,e,4,g to chcę, aby po usunięciu były w tablicy 3 elementy:5,6,4


    Ja mam jeden łopatologiczny sposób na usuwanie el. z tablicy.

    Jak masz tablice N=5 elementów z elementami kolejno: 5,6,e,4,g a chcesz uzyskac 5,6,4
    to robisz tak zę wpisujesz do 3ciej komórki(2 index tablicy) czwarty element(3 index tablicy) i masz: 5,6,4,4,g potem kasujesz dwa ostatnie elementy w tablicy N=N-2; Oczywiście N nie moze byc const.
  • Poziom 34  
    Mam pytanie. Jeżeli w tablicy mamy:
    1,2,a,b,d,a,2,f,6,8,b,a;
    i chcemy usunąć: 2,a;
    to czy usuwamy wszystkie żądane znaki i tablica będzie:
    1,b,d,f,6,8,b;
    czy inne kryterium?
  • Poziom 18  
    Giętkość rozwiązania, które jest oparte o algorytm standardowy, polega na tym, że można zrealizować dowolny scenariusz. Wszystko zależy od predykatu. Predykat można napisać, na przykład tak, by usuwał nie więcej niż dwa wystąpienia każdego elementu, a trzecie i każde następne zostawiał. Albo tak, by zostawiał tylko piąte wystąpienie, a każde inne usuwał.

    HTH,
    Dariusz
  • Poziom 9  
    Poczytałem trochę o klasie vektor i wykombinowałem coś takiego, ale program nie chce usuwać danych ;/ Nie do końca wiem jak działa ta funkcja "erase".
    Code:
    #include<iostream>
    
    #include<vector>

    using namespace std;

    int main()
    {
       vector<char>tab;
       vector<char>dozwolone;
       dozwolone.push_back('0');
       dozwolone.push_back('1');
       dozwolone.push_back('2');
       dozwolone.push_back('3');
       dozwolone.push_back('4');
       dozwolone.push_back('5');
       dozwolone.push_back('6');
       dozwolone.push_back('7');
       dozwolone.push_back('8');
       dozwolone.push_back('9');
       char* a=new char[50];
       cin>>a;
       int k=0;
       while(a[k]!=0)
       {
          tab.push_back(a[k]);
          k++;
       }
       vector<char>::iterator i;
       vector<char>::iterator j;
       for(i=tab.begin();i<tab.end();i++)
       {
          cout<<*i;
       }
       cout<<endl;
       int c=0;
       for(i=tab.begin();i<tab.end();i++)
       {
          for(j=dozwolone.begin();j<dozwolone.end();j++)
          {
             if(*i==*j)
                tab.erase(tab.begin()+c);
          }
          c++;
       }
       cout<<endl;
       for(i=tab.begin();i<tab.end();i++)
          cout<<*i;
       cout<<endl;
       delete[] a;
       system("pause");
       return 0;
    }

    ps. Program ma teraz usuwać cyfry zamiast znaków.
  • Poziom 18  
    Oj, kolego, uwierz mi, że warto zainwestować w jakąś książkę dot. programowania w C++. Wtedy Twój program będzie wyglądał tak:
    Code:
    int main(){
    
      char * usuwane = "1234567890";
      vector<char> usuw( usuwane, usuwane+10 );
      list<char> p;

      copy( istreambuf_iterator<char>(cin), istreambuf_iterator<char>(), back_inserter( p ) );
      p.erase( remove_if( p.begin(), p.end(), sprawdzacz() ), p.end() );
      copy( p.begin(), p.end(), ostream_iterator<char>(cout, " ") );

      return 0;
    }

    Teraz kilka uwag.
    Po pierwsze, źle Ci doradzono, że należy przechować wczytane dane w vector-ze. Wektor jest takim pojemnikiem, w którym usuwanie danych nie będących na końcu jest kosztowne czasowo. W Twoim przypadku z góry wiesz, że będziesz to robił. Znacznie lepiej jest zatem użyć listy.
    Po drugie, jeżeli już chcesz przechować zestaw znaków podlegający usunięciu w wektorze (choć nie ma takiej potrzeby, tablica to też pojemnik), zrób to tak, jak powyżej, a nie nieelegancką i nieoptymalną czasowo serią push_back()-ów.
    Po trzecie, bez sensu jest wczytywać dane do tablicy znakowej (ratunku, przepełnienie!), a potem przepisywać je do pojemnika. Rozwiązanie powyżej jest lepsze (żeby zakończyć wczytywanie należy nacisnąć enter i Ctrl-D). Można by także wykorzystać getline() i string - wtedy nie będzie trzeba naciskać Ctrl-D.
    I wreszcie usuwanie: po co wyważać otwarte drzwi pisząc te dwie zagłębione pętle for, które w dodatku nie działają? Kod gotowy - prosty i bezbłędny! - masz powyżej, napisz tylko predykat "sprawdzacz" (nie powinien być wiele dłuższy niż 5 linii).

    Istnieje jeszcze jedno rozwiązanie. Jeżeli nie zależy Ci na zachowaniu kolejności wczytanych danych, może łatwiej jest najpierw pojemnik posortować, a potem znaleźć miejsce, od którego zaczynają się cyfry. W pewnych sytuacjach może to działać szybciej.

    A teraz zagadka: jakie nagłówki są potrzebne żeby to skompilować?

    HTH,
    Dariusz
  • Pomocny post
    Poziom 34  
    Jeżeli koniecznie chcemy usuwać znaki z tablicy, załączam kod pozwalający usunąć dowolnie wybrane znaki. Jeżeli chcemy usuwać tylko cyfry lub litery, kod znaczne się upraszcza. Niewątpliwie można to napisać prościej, za uwagi będę wdzięczny. Znaki do usunięcia wprowadzam do kontenera, bo nie znam z góry ich ilości.
    Code:

    #include <iostream>
    #include <conio.h>
    #include <time.h>
    #include <vector>
    using namespace std;
    int const mx=35;
    int i,j,it,ile=0,mxx=35;
    vector<char>znaki;
    char tab[35],usun,st;
    int *ile_zn;
        int erase (int x)
         {
                 for(i=x;it<mxx;i++)
                 {
                  if(i==mxx-1)break;                 
                  tab[i]=tab[i+1];     
                 }mxx--;
            return mxx;     
          }     
    int main()
    {
        time_t t;
       srand((unsigned) time(&t));
     cout<<"tablica wejsciowa"<<endl;
      i=0;
      while(i<35)
      {
       int x=48+rand()%54;
       if((x>57)&&(x<97))continue;else
       {
        tab[i]=char(x);cout<<tab[i]<<" ";
        i++;
        }                                         
      }     
    // koniec wypelniania tablicy   
       while(st !='/')
       { 
         cout<<endl<<"wprowadz znak do usuniecia,znak: / konczy wprowadzanie"<<endl;             
         cin>>st;
        if(st=='/')break;     
        znaki.push_back(st);
        ile++;
        }
     if((st=='/')&&(ile==0)) {cout<<"brak znaku!";getch();exit(0);}   
      ile_zn=new int(ile);
        for(i=0;i<ile;i++)
        {ile_zn[i]=0;
         for(j=0;j<mxx;j++)
         {
           if(znaki[i]==tab[j])ile_zn[i]=ile_zn[i]+1;               
          }
          }
        for(i=0;i<ile;i++)cout<<"ile_zn= "<<znaki[i]<<" = "<<ile_zn[i]<<endl;
             
         for(j=0;j<ile;j++)     
          for(int k=0;k<ile_zn[j];k++)                       
           for(i=0;i<mxx;i++)
           {
            usun=znaki[j];           
            if(tab[i]==usun){it=i;erase(it);break;}
           } 
    cout<<"nowa tablica"<<endl;
     for(i=0;i<mxx;i++)cout<<char(tab[i])<<" ";
     delete []ile_zn;         
     getch();   
     return 0;
      }
  • Poziom 18  
    Ale jazda! Kod o długości 6 linii + 5 na funktor vs kod o długości 30 linii. Kolego ed-ek, spójrz prawdzie w oczy: nie piszesz w C++, a w C (z małą pomocą tablic o zmiennym rozmiarze).

    Dariusz
  • Poziom 34  
    Dariusz Bismor napisał:
    Ale jazda! Kod o długości 6 linii + 5 na funktor vs kod o długości 30 linii. Kolego ed-ek, spójrz prawdzie w oczy: nie piszesz w C++, a w C (z małą pomocą tablic o zmiennym rozmiarze).

    Dariusz

    Abym mógł ocenić i skorzystać z Twojego rozwiązania, przedstaw kod. Mój kod nie jest aż tak długi, wiele linii zawiera wpisanie tablicy, pokazanie ilości elementów do usunięcia, dodatkowe bajery. W istocie jądro kodu to mniej niż 20 linii. Co oznacza że nie piszę w C++? Jeżeli nie przedstawisz swego kodu, Twój post jest bezwartościowy i nie może być argumentem do dalszej dyskusji. Przedstaw kod. Być może wielu skorzysta.
  • Poziom 18  
    Mój kod przedstawiłem powyżej. Jest to kompletny kod, wycięty z działającego programu. Brakuje tylko "#includów" i kodu funktora sprawdzacz(). Nie podaję go celowo, bo nauka musi kosztować - inaczej nie zapamiętasz. Podejmij rękawicę, wysil się, poczytaj, pokombinuj. Jeśli nawet nie wyjdzie - pokaż, co udało Ci się zrobić. Wtedy pomogę to poprawić.

    Co do C i C++, popatrzcie na Standard języka C++: 2/3 to opis biblioteki. Jedną z zalet programowania wysokopoziomowego w C++ jest zwięzłość kodu i związany z tym niski koszt jego utrzymania. Jeżeli ktoś nie zna biblioteki i koduje sam to, co tam jest zamieszczone, to nie zna języka. Kod kolegi ed-ek jest typowym przykładem: po zamianie wektora na tablicę i cin, cout na scanf, printf jest to kod języka C.

    Dariusz
  • Poziom 34  
    Pisałem że jeżeli chcemy usuwać z tablicy tylko litery lub tylko cyfry, kod będzie prostszy. Przedstawiam kod będący w istocie dwoma programami usuwania liter lub cyfr.. Nie trzeba tworzyć żadnego kontenera. To czy kod jest napisany w C++ nie zależy od dołączonych bibliotek - których używamy w zależności od potrzeb, a od charakteru instrukcji kodu.
    Code:

    #include <iostream>
    #include <conio.h>
    using namespace std;
    int main ()
    {
      cout<<"usuwanie cyfr z tablicy, tab. pierwotna:"<<endl;
      char *tab1;
      int n=8,i,ii=0,j=0; 
      char tab[]={'1','z','e','5','9','g','1','5'};
         for(i=0;i<n;i++)
          {
           cout<<tab[i]<<" ";             
           if(isdigit(int (tab[i])))ii++;
           }
      cout<<endl<<"nowa tablica:"<<endl;     
      tab1=new char[n-ii];
      for(i=0;i<n;i++)
       if(!isdigit(int (tab[i])))
       {tab1[j]=tab[i];cout<<tab1[j]<<" ";j++;}   
      delete []tab1;   
      //------------------------------
      cout<<endl<<"usuwanie liter z tablicy, nowa tablica:"<<endl;
        tab1=new char[ii];
        j=0;
      for(i=0;i<n;i++)
       if(isdigit(int (tab[i])))
       {tab1[j]=tab[i];cout<<tab1[j]<<" ";j++;}   
      delete []tab1;   
       
      getch();   
      return 0;
    }