Usuwanie wyrazów z samogłoskami

0

Witam, piszę program, który usuwa osobę, która w nazwisku ma 3 samogłoski. Program się zacina w czasie, kiedy ma usunąć. Co jest źle?

#include <iostream>
#include <string>
#include <list>

using namespace std;
struct dane
{ 
	string imie;
	string nazwisko;
	int rok_urodzenia;
};

void pobierz_dane(list <dane>& d)
{
	dane x;
	cin>>x.imie>>x.nazwisko;
	//cin>>x.rok_urodzenia;
	d.push_back(x);
}
void usuwanie(list <dane>& d)
{
	dane zmienna;
	int licznik=0;
	for (auto v=d.begin(); v!=d.end(); ++v)
	{
		string napis = v->nazwisko;
		size_t pos = napis.find_first_of( "aeiouy" ); // wyszukuje frazy
		while( pos != string::npos )//Jeżeli w trakcie wykonywania przeszukania funkcja szukająca osiągnie oznacza brak dopasowania.
		{
			licznik++;
			pos = napis.find_first_of( "aeiouy", pos ); // ponownie szuka
		}
		if (licznik>3)
		{
			v->nazwisko.erase();
		v->imie.erase();
		}
	}
}
void wyswietl(list <dane>&d)
{
	for (auto v=d.begin(); v!=d.end(); ++v)
		cout<<v->imie<<" "<<v->nazwisko<<endl;
}
int main()
{
	list<dane> danka;
	pobierz_dane(danka);
	pobierz_dane(danka);
	pobierz_dane(danka);
	usuwanie (danka);
	wyswietl(danka);

	system ("pause");
	return 0;
}
 
2

O nie, nie, nie - wewnątrz usuwanie dzieje się za dużo.

  1. Stwórz sobie osobną funkcję licz_samogloski, gdzie nie będziesz wykorzystywał find_first_of, bo niepotrzebnie robisz sobie złożoność kwadratową, podczas gdy spokojnie można to wykonać liniowo.
  2. Powiedziałeś, że osoba musi mieć w nazwisku trzy samogłoski, a Ty sprawdzasz czy nie ma co najmniej czterech.
  3. Nie zerujesz licznika przy każdym nazwisku - nie byłoby tego problemu, gdybyś nie robił takich rozbudowanych funkcji, tylko rozdzielał wszystko na podfunkcje (patrz punkt pierwszy).
  4. Nidzie nic z listy nie usuwasz.
1
  1. C++ czy C z cout?
  2. Zapoznaj się z inkrementacją bo jej nie rozumiesz: http://4programmers.net/Forum/1101404
#include <algorithm>
#include <iostream>
#include <string>
#include <list>
using namespace std;

struct dane
  { 
   string imie;
   string nazwisko;
   unsigned rok_urodzenia; // int - czy może być ujemny rok?
   dane(istream &s) { s>>ws>>imie>>nazwisko>>rok_urodzenia; } // dużo upraszcza
   friend ostream &operator<<(ostream &s,const dane &d) { return s<<d.imie<<' '<<d.nazwisko<<' '<<d.rok_urodzenia; }
   unsigned samogloski()const { return count_if(nazwisko.begin(),nazwisko.end(),[] (char ch) { return string("aeiouy").find(ch)!=string::npos; } ); }
  };
typedef list<dane> dList; // aby zmniejszyć ilość list<dane> i móc szybko zmienić kontainer

void pobierz_dane(dList &d) { d.push_back(dane(cin)); } // np tu znacznie prosciej
void usuwanie(dList &d)  { d.remove_if([] (dane &t) { return t.samogloski()>3; } ); }
void wyswietl(dList &d) { for(auto &i:d) cout<<i<<endl; }
  
int main()
  {
   dList danka;
   for(unsigned i=0;i<6;++i) pobierz_dane(danka);
   usuwanie (danka);
   wyswietl(danka);
   // system("pause"); // jeżeli tego potrzebujesz to twóje IDE jest z poprtzedniego tysiąclecia - wymień na nowsze
   return 0;
  }
0

Mam coś takiego, przydałoby się zapętlić jakoś, bo przy tym sposobie, kiedy już znajdzie np. 'a' to dalej nie szuka, a ktoś w nazwisku może mieć dwa razy literkę 'a'. Jakieś propozycje? :)

#include <iostream>
#include <string>
#include <list>
#include <regex>

using namespace std;
struct dane
{ 
	string imie;
	string nazwisko;
	int rok_urodzenia;
};

void pobierz_dane(list <dane>& d)
{
	dane x;
	cin>>x.imie>>x.nazwisko;
	//cin>>x.rok_urodzenia;
	d.push_back(x);
}/*
 void usuwanie(list <dane>& d)
 {
 dane zmienna;
 int licznik=0;
 for (auto v=d.begin(); v!=d.end(); ++v)
 {
 string napis = v->nazwisko;
 size_t pos = napis.find_first_of( "aeiouy" ); // wyszukuje frazy
 while( pos != string::npos )//Jeżeli w trakcie wykonywania przeszukania funkcja szukająca osiągnie oznacza brak dopasowania.
 {
 licznik++;
 pos = napis.find_first_of( "aeiouy", pos ); // ponownie szuka
 }
 if (licznik>3)
 {
 v->nazwisko.erase();
 v->imie.erase();
 }
 }
 }*/
void wyswietl(list <dane>&d)
{
	for (auto v=d.begin(); v!=d.end(); ++v)
		cout<<v->imie<<" "<<v->nazwisko<<endl;
}
void znajdz(list <dane>&d)
{
	for (auto v=d.begin(); v!=d.end(); ++v)
	{
		int licznik=0;
		string tekst=v->nazwisko;
		int line = 0 ;
		regex wzorzec("a");
		regex wzorzec2("e");
		regex wzorzec3("i");
		regex wzorzec4("o");
		regex wzorzec5("u");
		regex wzorzec6("y");

		smatch wynik;
		++line;
		if( regex_search( tekst, wynik, wzorzec ) )
			licznik++;
		if( regex_search( tekst, wynik, wzorzec2 ) )
			licznik++;
		if( regex_search( tekst, wynik, wzorzec3 ) )
			licznik++;
		if( regex_search( tekst, wynik, wzorzec4 ) )
			licznik++;
		if( regex_search( tekst, wynik, wzorzec5 ) )
			licznik++;
		if( regex_search( tekst, wynik, wzorzec6 ) )
			licznik++;


		if (licznik>2)
		{
			v->nazwisko.erase();
			v->imie.erase();
		}
	}
}
int main()
{
	list<dane> danka;
	pobierz_dane(danka);
	//pobierz_dane(danka);
	pobierz_dane(danka);
	znajdz (danka);
	wyswietl(danka);

	system ("pause");
	return 0;
}
 
1

OMG!
6 wywołań regex aby sprawdzić czy napis zawiera jedną literę?
Po to aby nieprawidłowo rozwiązać zadanie, wyszło: ... która w nazwisku ma 3 różne samogłoski ..
Natychmiast wywal, wróć do poprzedniego kodu, poczytaj co napisał @Patryk27 oraz ja wyżej oraz przerób stary kod.

0

Skłoniłem się ku wyrażeniom regularnym, ponieważ ostatnio je na laboratoriach miałem i chciałem przećwiczyć, mimo że wiem, iż taka metoda jest niedopuszczalna. Spróbuje napisać trzymając się waszych wskazówek. Dzięki! :)

0

Okej, takiego obrotu spraw się nie spodziewałem - chylę czoła, jako że teraz technicznie masz złożoność O(n) :P

Myślałem nad czymś bardziej w rodzaju: http://ideone.com/92zTQy
Twoim zadaniem jest poprawić czySamogloska tak, aby nie było tam tej brzydkiej konstrukcji (c == ...) || (c == ...) - możesz wykorzystać jakiś std::set albo cokolwiek co Ci jeszcze wpadnie na myśl*.

* przy czym wykorzystanie innej instrukcji (typu switch) wciąż będzie brzydkie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1