Zliczanie wystąpień powtórzeń znaków w pętli for.

0

Witam tworzę pętlę, mającą na celu sprawdzenie, ile znaków występuje ponad raz. Napisałem coś takiego i sprawdza się jeżeli dany znak występuje maksymalnie 2 razy. Jednak jeśli występuje 3 razy lub więcej program powiększa r dwa razy mimo, że to wciąż ten sam znak.

begin
  r:=0;
  for f:=1 to x do
  begin
    for k:=1 to x do
    if s1[f]=s1[k] then
    r:=r+1;
  end;
  r:=r-x;
end;  

Nie mam żadnego pomysłu jak to ominąć. Może coś podpowiecie?

0

co to jest r, s1 i k?

0

A tak, przepraszam
r-zmienna wyrażająca liczbę znaków, które się powtarzają
s1-jest to tablica jednowymiarowa typu char(o dlugosci x)

k jest zmienną przy pętli for (k:= od 1 do x)

0

możesz się bawić w breaki, odejmowanie i zmienianie zakresów pętli wewnętrznej, ale kod będzie nieintuicyjny
lepiej w tym przypadku zrobić tablicę o takiej wielkości ile możliwych jest znaków, a następnie przelecieć jedną pętlą i zliczyć wystąpienie każdego znaku
drugą pętlą (niezagnieżdżoną) przelecieć po tablicy i zliczyć pola w których naliczono > 1

0

@Maraspp93: chodzi Tobie chyba o coś takiego jak poniżej:

function CzaryMary(AInput : string) : integer;
var
  I : integer;
begin
  Result := 0;
  for I := 2 to Length(AInput) do
  begin
    if Pos(AInput[I], Copy(Ainput, 1, I - 1)) > 0 then
    begin
      Result := Result + 1;
    end;
  end;
end;
0

Jak chcesz policzyć dla wszystkich znaków w ciągu, to możesz też i tak:

function DoubledCharCount(const aStr: string): word;
const C_MAX_CHAR_VAL=256; //dla znakow poza ASCII mozna to zwiekszyc
var fCounter:array[1..C_MAX_CHAR_VAL] of word;
    i:integer;
begin
 //zarujemy licznik dla poszczegolnych znakow
 ZeroMemory(@(fCounter[1]),C_MAX_CHAR_VAL*SizeOf(word));

 //liczymy
 for i:=1 to Length(aStr) do
  inc(fCounter[Ord(aStr[i])]);

 //zliczamy te ktore maja licznik>1
 result:=0;
 for i:=1 to C_MAX_CHAR_VAL do
  if fCounter[i]>1 then
   Inc(Result);
end;
0

Problem polega na tym jeszcze, że owe łańcuchy mam zdefiniowane jako jednowymiarowe tablice znaków. Przepraszam, że nie napisałem o tym z początku. Oto cały program:

program lancuchasd;
type
 T = array of char;
 procedure rozmiarlancucha1(var asd: T; n: integer);
 begin
 setlength(asd,n);
 end;
  procedure rozmiarlancucha2(var dsa: T; z: integer);
 begin
 setlength(dsa,z);
 end;
procedure rozmiarlancucha3(var s1: T; x: integer);
begin
setlength(s1,x);
end;
procedure wypelnienielancucha1(var asd: T);
var
  a: integer;
begin
  for a := low(asd) to high(asd) do
      asd[a] := chr(random(255));
end;
procedure wypelnienielancucha2(var dsa: T);
var
  a: integer;
begin
  for a := low(dsa) to high(dsa) do
      dsa[a] := chr(random(255));
end;
procedure pokazlancuch1(asd: T);
var
  a: integer;
begin
  writeln;

  for a := low(asd) to high(asd) do
  begin
      write(asd[a]:3);

    writeln;
  end;
  end;
  procedure pokazlancuch2(dsa: T);
var
  b: integer;
begin
  writeln;

  for b := low(dsa) to high(dsa) do
  begin
      write(dsa[b]:3);

    writeln;
  end;

  writeln;
end;
procedure pokazlancuch3(s1: T);
var
c: integer;
begin
writeln;

for c := low(s1) to high(s1) do
begin
    write(s1[c]:3);

  writeln;
end;

writeln;
end;
var asd,dsa,s1: T;
	k,f,r,n,z,x,i,y:integer;
begin
Randomize();
n:=Random(1-10)+10;
z:=Random(1-10)+10;
rozmiarlancucha1(asd,n);
rozmiarlancucha2(dsa,z);
x:=n+z;
rozmiarlancucha3(s1,x);
wypelnienielancucha1(asd);
wypelnienielancucha2(dsa);
begin   {TU ZACZYNA SIĘ MOJA PRÓBA UCHWYCENIA ILE TYPÓW ZNAKÓW WYŚWIETLA SIĘ W ŁAŃCUCHU S1 DWA I WIĘCEJ RAZY}
  for i:= 0 to n-1 do
        s1[i]:=asd[i];
    for  y:=n to x do
    s1[y]:=dsa[y-n];
end;
begin
  r:=0;
  for f:=1 to x do
  begin
    for k:=1 to x do
    if s1[f]=s1[k] then
    r:=r+1;
  end;
  r:=r-x;
end;
write('Lancuch pierwszy: ');
pokazlancuch1(asd);
write('Lancuch drugi: ');
pokazlancuch2(dsa);
write('Polaczony lancuch ');
pokazlancuch3(s1);
writeln('Nowo uzyskany lancuch ma ',x,' elementow');
writeln(r,' znaki wystepuja co najmniej 2 razy');
readln;
end.
 
1

Nazewnictwo zmiennych jest fatalne zamiast jednoliterowych oznaczeń albo jebnięć w klawiaturę używaj nazw które coś oznaczają.

 procedure rozmiarlancucha1(var asd: T; n: integer);
 begin
 setlength(asd,n);
 end;
  procedure rozmiarlancucha2(var dsa: T; z: integer);
 begin
 setlength(dsa,z);
 end;
procedure rozmiarlancucha3(var s1: T; x: integer);
begin
setlength(s1,x);
end;

Po co u licha ci aż 3 identyczne procedury? Wystarczy jedna np. taka (zwróć uwagę na sposób nazewnictwa):

procedure UstawRozmiarTablicy(var Tablica: TDynCharArray; Rozmiar: Integer);
begin
  SetLength(s1,x);
end;

Choć opakowanie identycznej funkcji tylko pod polską nazwą jest nieporozumieniem.

To samo wypelnienielancucha1 oraz wypelnienielancucha2 po co????? pokazlancuch1 w 3 odmianach -,-
co oznacza asd - rozwiń ten skrót albo ten dsa WTF?
itd... itp....

Random(1-10)+10 - tu jest błąd podstawowy...
Losujesz liczby z zakresu od minus nieskończoności do -9 oraz od 0 do plus nieskończoności czyli w rzeczywistości wszystkie poza tymi z przedziału który cie interesuje.
Powinno być coś w stylu Random(10) żeby wylosować liczby od 0 do 9 nie wiem z jakiego przedziału te liczby miały być ale na pewno nie ujemne.
Na twoim miejscu używałbym stringów zamiast tablic dynamicznych - używa się ich prawie tak samo i przechowują to na czym ci zależy czyli znaki anie liczby.
Reszta została już powiedziana.

0
Marasp93 napisał(a)

Witam tworzę pętlę, mającą na celu sprawdzenie, ile znaków występuje ponad raz.

Moja propozycja:

function MultiCharsCountAsInteger(AInput: array of AnsiChar): Integer;
const
  COUNTED_CHAR_VALUE = AnsiChar(#0);
var
  intCharToken, intCounterToken, intCharCount: Integer;
begin
  Result := 0;

  for intCharToken := Low(AInput) to High(AInput) do
    if AInput[intCharToken] <> COUNTED_CHAR_VALUE then
    begin
      intCharCount := 1;

      for intCounterToken := intCharToken + 1 to High(AInput) do
        if AInput[intCharToken] = AInput[intCounterToken] then
        begin
          Inc(intCharCount);
          AInput[intCounterToken] := COUNTED_CHAR_VALUE;
        end;

      if intCharCount > 1 then
        Inc(Result);
    end;
end;

Przyjmuje tzw. "open array", więc można podać cokolwiek - tablicę, łańcuch, literał itd.; Nie wymaga tworzenia macierzy po to, aby przechowywać znaki i/lub ilości ich wystąpień; No i działa bardzo podobnie do sortowania bąbelkowego;

Jeżeli interesuje Cię zwrócenie łańcucha, który zawierać będzie znaki, które wystąpiły co najmniej dwa razy w łańcuchu wejściowym, to funkcja będzie wyglądać tak:

function MultiCharsCountAsString(AInput: array of AnsiChar): AnsiString;
const
  COUNTED_CHAR_VALUE = AnsiChar(#0);
var
  intCharToken, intCounterToken, intCharCount: Integer;
begin
  Result := '';

  for intCharToken := Low(AInput) to High(AInput) do
    if AInput[intCharToken] <> COUNTED_CHAR_VALUE then
    begin
      intCharCount := 1;

      for intCounterToken := intCharToken + 1 to High(AInput) do
        if AInput[intCharToken] = AInput[intCounterToken] then
        begin
          Inc(intCharCount);
          AInput[intCounterToken] := COUNTED_CHAR_VALUE;
        end;

      if intCharCount > 1 then
        Result += AInput[intCharToken];
    end;
end;

Test działania obu funkcji tutaj: http://ideone.com/NT8jB9

W przypadku użycia tej drugiej funkcji, oprócz ilości znaków występujących wielokrotnie w dowolnych miejscach (nie tylko obok siebie i w jednym miejscu), masz także do dyspozycji wartości tych znaków, zwracane w rezultacie funkcji;

PS: Żeby zobaczyć jak funkcja działa i jak zmienia się zawartość macierzy wejściowej w iteracjach, w których warunek zostaje spełniony, wystarczy po spełnieniu warunku wyświetlić zawartość macierzy i łańcucha rezultatu;

Przykład: http://ideone.com/lSCXUV

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