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

[C++]Usuwanie elementów tablicy.

elektronik512 31 Sty 2010 20:46 15142 18
  • #1 31 Sty 2010 20:46
    elektronik512
    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;
    }

    0 18
  • #2 31 Sty 2010 21:58
    Szymon Tarnowski
    Poziom 27  

    Spróbuj najpierw zdefiniować co rozumiesz pod pojęciem "usunąć z tablicy".

    0
  • #3 01 Lut 2010 09:34
    elektronik512
    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

    0
  • #4 01 Lut 2010 11:15
    Dariusz Bismor
    Poziom 17  

    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

    -1
  • #5 01 Lut 2010 17:22
    elektronik512
    Poziom 9  

    A mógłbyś powiedzieć mniej więcej co się podaje w parametrach tej funkcji?

    0
  • #6 02 Lut 2010 10:19
    Dariusz Bismor
    Poziom 17  

    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

    0
  • #7 02 Lut 2010 10:31
    arnoldziq
    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

    0
  • #8 02 Lut 2010 10:34
    nomar600
    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.

    0
  • #9 02 Lut 2010 13:19
    Dariusz Bismor
    Poziom 17  

    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

    -2
  • #10 02 Lut 2010 14:02
    toma5z
    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.

    0
  • #11 02 Lut 2010 16:51
    ed-ek
    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?

    0
  • #12 02 Lut 2010 19:35
    Dariusz Bismor
    Poziom 17  

    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

    -1
  • #13 02 Lut 2010 20:53
    elektronik512
    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.

    0
  • #14 03 Lut 2010 11:49
    Dariusz Bismor
    Poziom 17  

    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

    -1
  • Pomocny post
    #15 04 Lut 2010 13:06
    ed-ek
    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;
      }

    0
  • #16 04 Lut 2010 17:00
    Dariusz Bismor
    Poziom 17  

    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

    -1
  • #17 05 Lut 2010 08:02
    ed-ek
    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.

    0
  • #18 05 Lut 2010 10:46
    Dariusz Bismor
    Poziom 17  

    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

    0
  • #19 08 Lut 2010 12:51
    ed-ek
    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;
    }

    0