Pornire rapidă „Interpolarea șirurilor de caractere în C#”

Interpolarea șirurilor de caractere în C#

Această pornire rapidă vă învață să folosiți interpolarea șirurilor de caractere pentru a insera valori într-un singur șir de caractere. Învățați de asemenea cum să controlați reprezentările textuale ale acestor valori în șirul rezultat. Folosiți browser-ul dvs. pentru a scrie și rula cod C# și puteți să vedeți imediat rezultatele produse.

Creați un șir interpolat

Rulați următorul cod în fereastra interactivă. Pentru a face asta, tastați codul în fereastra interactivă (înlocuiți cu numele dvs.) și selectați Run:

var nume = „”;
Console.WriteLine($”Buna ziua, {nume}. Este o placere sa va intalnesc!”);

Când rulați codul, Output afișează un șir care include numele dvs. în salutare. Argumentul șir al apelului metodei WriteLine este un șir interpolat. Este un fel de șablon care vă permite să construiți un singur șir (numit șir rezultat) dintr-un șir care include cod incorporat. Șirurile interpolate sunt în special folositoare pentru inserarea de valori într-un șir sau concatenarea (alipirea) câtorva șiruri.

Exemplul de mai sus conține cele 2 elemente pe care oricare șir interpolat trebuie să le aibă:

  • Un șir literal care începe cu caracterul $ înainte de ghilimelele lui de deschidere. Nu poate fi nici un spațiu între simbolul $ și caracterul de ghilimele. (Dacă doriți săvedeți ce se întâmplă când includeți unul, inserați un spațiu după caracterul $ în fereastra interactivă și rulați codul actualizat. Compilatorul C# se plânge, „Unexpected character ‘$'” – „Caracter neașteptat ‘$’”.)
  • Unul sau mai multe expresii interpolate. O expresie interpolată este indicată de o acoladă deschisă și de o acoladă închisă ({ și }). Puteți pune orice expresie C# care întoarce o valoare (inclusiv null) între acolade.
Haideți să încercăm puțin mai multe exemple de interpolare de șiruri cu câteva alte tipuri de date.

Includeți diferite tipuri de date

În pasul anterior, ați folosit interpolarea șirurilor pentru a insera un șir în interiorul altuia. Rezultatul unei expresii interpolate poate fi de orice tip de date, totuși. Haideți să includem valori de variate tipuri de date într-un șir interpolat.

În exemplul următor, mai întâi, definim un tip de date clasă Leguma care are proprietatea Nume și metoda ToString, care suprascrie comportamentul metodei Object.ToString(). Modificatorul de acces public face acea metodă disponibilă oricărui cod client pentru a obține o reprezentare de tip șir de caractere a unei instanțe Leguma. În exemplul acesta metoda Leguma.ToString întoarce valoarea proprietății Nume care este inițializată în constructorul Leguma: Leguma(string nume) => Nume = nume;. Apoi creăm o instanță a clasei Leguma folosind cuvântul cheie new și oferind un parametru nume pentru constructorul Leguma. În final, includem acea instanță într-un șir interpolat care conține și o valoarea DateTime, o valoare Decimal, și o valoare din enumerația Unit. Rulați următorul cod în fereastra interactivă:

public class Leguma
{
   public Leguma(string nume) => Nume = nume;

   public string Nume { get; }
   public override string ToString() => Nume;
}

public enum Unit { bucata, kilogram, gram, duzina };
var item = new Leguma(„vinete”);
var date = DateTime.Now;
var price = 1.99m;
var unit = Unit.bucata;
Console.WriteLine($”In {date}, pretul a {item} a fost {price} pe {unit}.”);


Notați că expresia interpolată item în șirul interpolat se rezolvă cu textul „vinete” în șirul rezultat. Aceasta este deoarece, când tipul expresiei rezultat nu este șir de caractere, rezultatul se rezolvă cu un șir de caractere în felul următor:

  • Dacă expresia interpolată se evaluează la null, un șir gol („”, sau String.Empty) este folosit.
  • Dacă expresia interpolată nu se evaluează la null, în mod obișnuit metoda ToString a tipului rezultat este apelată. Puteți testa aceasta actualizând implementarea metodei Leguma.ToString. Poate nici nu este nevoie să implementați metoda ToString fiindcă fiecare tip are o implementare a acestei metode. Pentru a testa aceasta, comentați definiția metodei Leguma.ToString în exemplul dat (pentru a face aceasta, puneți un simbol de comentariu, //, în fața ei). În ieșire, șirul „vinete” este înlocuit de numele de tip complet calificat (domeniul de nume (en. namespace) definit de REPL-ul C# împreună cu numele de tip), care este comportamentul implicit al metodei Object.ToString(). Comportamentul implicit al metodei ToString pentru o valoare enumerație este să întoarcă reprezentarea ca șir de caractere a valorii.
În ieșirea de la acest exemplu, data este prea precisă (prețul unei vinete nu se schimbă în fiecare secundă), și valoarea prețului nu indică o monedă. În următorul pas, veți învăța cum să rezolvați aceste probleme controlând formatul reprezentărilor șir ale rezultatelor expresiilor.

Controlați formatarea expresiilor interpolate

În pasul anterior, două șiruri sărac formatate au fost introduse în șirul rezultat. Una a fost o valoare dată și timp pentru care doar data era potrivită. A doua a fost un preț care nu își indica moneda. Ambele probleme sunt ușor de adresat. Interpolarea șirurilor vă permite să specificați șiruri de format care controlează formatarea tipurilor particulare. Modificați apelul la Console.WriteLine din exemplul anterior să includă șirurile de format pentru expresiile datei și prețului după cum se arată în următoarea linie:

Console.WriteLine($”In {date:d}, pretul a {item} a fost {price:C2} pe {unit}.”);

Specificați un șir de format urmând expresia interpolată cu două-puncte („:”) și șirul de format. „d” este un șir de format standard pentru dată și timp care reprezintă formatul de dată scurtă. „C2” este un șir de format standard numeric care reprezintă un număr ca o valoare monetară cu 2 cifre după punctul zecimal.
Un număr de tipuri din bibliotecile .NET suportă o mulțime predefinită de șiruri de format. Acestea includ toate tipurile numerice și tipurile dată și timp. Pentru o listă completă de tipuri care suportă șiruri de format, vedeți Format Strings and .NET Class Library Types (tradus: Șiruri de format și tipuri din biblioteca de clase .NET) în articolul Formatting Types in .NET (tradus: Formatarea tipurilor în .NET).
Încercați să modificați șirurile de format în exemplul dat pentru a vedea cum afectează ele formatarea valorii dată și timp și a valorii numerice. Schimbați „d”-ul din {date:d} în „t” (pentru a afișa formatul scurt de timp), „y” (pentru a afișa anul și luna), și „yyyy” (pentru a afișa anul ca un număr alcătuit din 4 cifre). Schimbați „C2”-ul din {price:C2} în „e” (pentru notație exponențială) și „F3” (pentru o valoare numerică cu 3 cifre după punctul zecimal).
În plus pe lângă controlul formatării, puteți de asemenea să controlați lățimea câmpului și alinierea șirurilor formatate care sunt incluse în șirul rezultat. În următorul pas, veți învăța cum sa faceți aceasta.

Controlați lățimea câmpului și alinierea expresiilor interpolate

De obicei, când rezultatul unei expresii interpolate este formatată ca șir, acel șir este inclus în șirul rezultat fără spații în față sau în spate. În particular când lucrați cu un set de date, a fi capabil să controlați lățimea câmpului și alinierea textului ajută la producerea unei ieșiri mai lizibile. Pentru a vedea aceasta, rulați următorul cod:
var inventory = new Dictionary()
  {
      [„hammer, ball pein”] = 18,
      [„hammer, cross pein”] = 5,
      [„screwdriver, Phillips #2”] = 14
  };
  Console.WriteLine($”Inventory on {DateTime.Now:d}”);
  Console.WriteLine(” „);
  Console.WriteLine($”|{„Item”,-25}|{„Quantity”,10}|”);
  foreach (var item in inventory)
     Console.WriteLine($”|{item.Key,-25}|{item.Value,10}|”);
Numele item-urilor sunt aliniate la stânga, și cantitățile lor sunt aliniate la dreapta. Specificați alinierea adăugând o virgulă („,”) după o expresie interpolată și desemnând lățimea minimă a câmpului. Dacă valoarea specificată este un număr pozitiv, câmpul este aliniat la dreapta. Dacă este un număr negativ, câmpul este aliniat la stânga.
Încercați să ștergeți semnele minus din cod {„Item”,-25} și {item.Key,-25} și rulați exemplul din nou. De această dată, item-urile sunt aliniate la dreapta.
Puteți combina un specificator de aliniere și un șir de format pentru o singură expresie interpolată. Pentru a face aceasta, specificați alinierea mai întâi, urmată de două-puncte și de șirul de format. Încercați următorul cod care afișează 3 șiruri formatate cu lățimi de câmp definite:
Console.WriteLine($”[{DateTime.Now,-20:d}] Hour [{DateTime.Now,-10:HH}] [{1063.342,15:N2}] feet”);

Felicitări!

Ați finalizat pornirea rapidă despre interpolarea șirurilor.
Pentru mai multe informații, vedeți subiectul String interpolation (tradus: Interpolarea șirurilor) și tutorialul String interpolation in C#.

Pornire rapidă „Ramuri și bucle”

Ramuri și bucle

Această pornire rapidă vă învață cum să scrieți cod care examinează variabile și schimbă calea de execuție bazat pe aceste variabile. Veți folosi browserul dvs. pentru a scrie C# interactiv și a vedea rezultatele compilării și rulării codului dvs. Această pornire rapidă conține o serie de lecții care exploră structurile de ramificare și repetiție în C#. Aceste lecții vă învață elementele fundamentale ale limbajului C#.

Faceți decizii cu instrucțiunea if

Rulați următorul cod în fereastra interactivă. Pentru a face asta, tastați următorul bloc de cod în fereastra interactivă și faceți clic pe butonul Run.
int a = 5;
int b = 6;
if (a + b > 10)
    Console.WriteLine(„Raspunsul este mai mare decat 10.”);
Modificați declarația lui b astfel încât suma să fie mai mică decât 10:
int b = 3;
Faceți clic pe butonul Run din nou. Deoarece răspunsul este mai mic decât 10, nimic nu este tipărit. Condiția pe care o testați este falsă. Nu aveți niciun cod de executat deoarece ați scris doar una dintre ramurile posibile pentru o instrucțiune if: ramura true (tradus adevărat).
Sfat. Explorând C# (sau oricare limbaj de programare), veți face greșeli gând scrieți cod. Compilatorul va găsi aceste erori și vi le va raporta. Când ieșirea conține mesaje de eroare, priviți atent la codul exemplu, și la codul din fereastra interactivă pentru a vedea ce să corectați. Aceste exercițiu vă va ajuta să învățați structura codului C#.
Primul exemplu arată puterea lui if și a tipurilor booleane. Un boolean este o variabilă care poate avea una din două valori: true sau false. C# definește un tip special, bool pentru variabile booleane. Instrucțiunea if verifică valoarea unui bool. Când valoarea este true, instrucțiunea următoare lui if se execută. Altfel, ea este omisă.
Procesul de verificare de condiții și executarea de instrucțiuni bazată pe aceste condiții este foarte puternic. Haideți să explorăm mai mult.

Faceți if și else să funcționeze împreună

Pentru a executa cod diferit în ambele ramuri adevărat și fals, creeați o ramură else care se execută când condiția este falsă. Încercați acesta:

int a = 5;
int b = 3;
if (a + b > 10)
    Console.WriteLine(„Raspunsul este mai mare decat 10”);
else
    Console.WriteLine(„Raspunsul nu este mai mare decat 10”);

Instrucțiunea urmând cuvântul cheie else se execută doar când condiția testată este false. Combinând if și else cu condiții booleane vă oferă toată puterea de care aveți nevoie.

Important. Indentarea de sub instrucțiunile if și else este pentru cititorii umani. Limbajul C# nu tratează indentarea sau spațiul alb ca semnificativ. Instrucțiunea urmând cuvintele cheie if sau else va fi executată bazat pe condiție. Toate exemplele din această pornire rapidă urmează o practică comună de a indenta liniile bazat pe fluxul de control al instrucțiunilor.

Deoarece indentarea nu este semnificativă, trebuie să folosiți { și } pentru a indica unde doriți mai mult de o instrucțiune să fie parte a blocului care se execută condițional. Programatorii C# folosesc de obicei aceste acolade la toate clauzele if și else. Următorul exemplu este același cu cel pe care tocmai l-ați creat. Încercați-l.

int a = 5;
int b = 3;
if (a + b > 10)
{
    Console.WriteLine(„Raspunsul este mai mare decat 10„);
}
else
{
    Console.WriteLine(„Raspunsul nu este mai mare decat 10„);
}

Sfat. De-a lungul restului acestei porniri rapide, exemplele de cod toate includ acolade, urmând practicile acceptate.

Puteți testa condiții mai complicate:

int a = 5;
int b = 3;
int c = 4;
if ((a + b + c > 10) && (a > b))
{
    Console.WriteLine(„Raspunsul este mai mare decat 10”);
    Console.WriteLine(„Si primul numar este mai mare decat al doilea”);
}
else
{
    Console.WriteLine(„Raspunsul nu este mai mare decat 10”);
    Console.WriteLine(„Sau primul numar nu este mai mare decat al doilea”);
}

&& reprezintă „și”. El înseamnă că ambele condiții trebuie să fie adevărate pentru a executa instrucțiunea din ramura true. Aceste exemple arată de asemenea că dvs. puteți avea mai multe instrucțiuni în fiecare ramură condițională, cu condiția că le închideți între { și }.

Puteți de asemenea să folosiți || pentru a reprezenta „sau”:

int a = 5;
int b = 3;
int c = 4;
if ((a + b + c > 10) || (a > b))
{
    Console.WriteLine(„Raspunsul este mai mare decat 10”);
    Console.WriteLine(„Sau primul numar este mai mare decat al doilea”);
}
else
{
    Console.WriteLine(„Raspunsul nu este mai mare decat 10”);
    Console.WriteLine(„Si primul numar nu este mai mare decat al doilea”);
}

Folosiți bucle pentru a repeta operații

Un alt concept important pentru a crea programe mai mari sunt buclele. Veți folosi bucle pentru a repeta instrucțiuni pe care dvs. le vreți executate mai mult decât o dată. Încercați acest cod în fereastra interactivă:

int contor = 0;
while (contor < 10)
{
  Console.WriteLine($”Hello World! Contorul este {contor}”);
  contor++;
}

Instrucțiunea while verifică o condiție și execută instrucțiunea urmând while-ul. Ea va repeta verificarea condiției și executarea acestor instrucțiuni până când condiția este falsă.

Un alt nou operator se află în acest exemplu. ++ de după variabila contor este operatorul de incrementare. El adaugă 1 la valoarea contorului, și reține acea valoare în variabila contor.

Important. Asigurați-vă că condiția buclei while chiar trece la fals în timp ce se execută codul. Altfel, dvs. creați o buclă infinită cu care programul nu se încheie niciodată. Haideți să nu demonstrăm aceasta, deoarece motorul care rulează codul dvs. va rămâne fără timp și nu veți vedea nicio ieșire din programul dvs.

Bucla while testează condiția înainte de executarea codului care urmează după while. Bucla do while execută codul mai întâi, și apoi verifică condiția. Ea arată:

int contor = 0;
do
{
  Console.WriteLine($”Hello World! Contorul este {contor}”);
  contor++;
} while (contor < 10);

Această buclă do și bucla while de mai devreme lucrează la fel.

Haideți să mergem înainte la un ultim tip de instrucțiune buclă.

Lucrați cu bucla for

O altă instrucțiune obișnuită de tip buclă pe care o să-o vedeți în cod C# este bucla for. Încercați acest cod în fereastra interactivă:

for (int contor = 0; contor < 10; contor++)
{
  Console.WriteLine($”Hello World! Contorul este {contor}”);
}

Acesta face același lucru ca bucla while și bucla do pe care le-ați folosit deja. Instrucțiunea for are 3 părți care controlează cum ea funcționează.

Prima parte este inițializatorul for: for contor = 0; declară contor ca variabila buclei, și îi setează valoarea inițială la 0.

Partea din mijloc este condiția for: contor < 10 declară că această buclă for continuă să execute cât timp valoarea contorului este mai mică decât 10.

Partea finală este iteratorul for: contor++ specifică felul în care să se modifice variabila buclei după executarea blocului de după instrucțiunea for. Aici, el specifică faptul că contor ar trebui incrementat cu 1 de fiecare dată când blocul se execută.

Experimentați cu acestea dvs. înșivă. Încercați fiecare din următoarele:

  • Schimbați inițializatorul pentru a începe la o valoare diferită.
  • Schimbați condiția pentru a se opri la o valoare diferită.
Când ați terminat, haideți să mergem înainte să scrieți puțin cod dvs. înșivă pentru a folosi ceea ce ați învățat.

Combinați ramuri și bucle

Acum că ați văzut instrucțiunea if și structurile de repetiție în limbajul C#, vedeți dacă puteți scrie cod C# pentru a găsi suma tuturor întregilor de la 1 la 20 care sunt divizibili cu 3. Aici sunt câteva indicii:

  • Operatorul % vă dă restul unei operații de împărțire.
  • Instrucțiunea if vă dă condiția pentru a vedea dacă un număr ar trebui să fie parte din sumă.
  • Bucla for vă poate ajuta să repetați o serie de pași pentru toate numerele de la 1 la 20.
Încercați dvs. înșivă. Apoi verificați cum ați făcut. Ca un indiciu, ar trebui să obțineți 63 ca răspuns.

Finalul provocării

Ați venit cu ceva ca asta?

int suma = 0;
for (int numar = 1; numar < 21; numar++)
{
  if (numar % 3 == 0)
  {
    suma = suma + numar;
  }
}
Console.WriteLine($”Suma este {suma}”);

Felicitări!

Ați completat pornirea rapidă „ramuri și bucle”.

Puteți învăța mai multe despre aceste concepte în aceste subiecte:

If and else statement (instrucțiunea if și else)
While statement (instrucțiunea while)
Do statement (instrucțiunea do)
For statement (instrucțiunea for)

Tradus din această pagină oficială de documentație Microsoft.

Tehnici de programare – Recursivitate

Recursivitate

Să pornim de la definiția de bază: o funcție este recursivă dacă în definiția ei se folosește o referire la ea însăși.
Din aceasta definiție putem considera modelul general al unui algoritm recursiv de forma:
rec(param_formali) { rec(param_formali) }
Pentru ca acest model să aibă sens din punct de vedere algoritmic, avem nevoie de o condiție de oprire dacă de modificările parametrilor formali:
rec(param_formali)
{
    if ( conditie_iesire(param_formali) ) { instructiuni finale }
    else rec(param_formali_modificati)
}
Există o serie de funcții matematice definite prin recursivitate, dintre care amintim:
> Funcția factorial










> Funcția Ackermann (Ackermann-Peter)

> Șirul lui Fibonacci


Conform definiției:
Putem interpreta definiția și în felul următor:
> Cel mai mare divizor comun (Algoritmul lui Euclid)

a) Fractali

O problemă importantă a recursivității o constituie fractalii. În această secțiune vom aminti doar sumar conceptul fractalilor geometrici în care modelul de bază al funcției recursive va genera figuri geometrice (în diferite ipostaze și diferite dimensiuni), iar condiția de oprire va fi dată de posibilitatea desenării acestor figuri geometrice (latura > 1 pixel).
Să presupunem un exemplu în care figura de bază este un pătrat (x, y, l). Procedura patrat desenează figura geometrică numită pătrat cu centrul în (x, y) și de latură l. (Fig. 1. a, b, c)
Fig. 1. a)
Următorul subprogram:
fractal (x, y, l)
{
    patrat(x, y, l);
    fractal((x – l) / 2, (y – l) / 2, l / 2)
}
Va genera următoarea figură:
Fig. 1. b)
fractal (x, y, l)
{
    if ( l > 5 ) // se referă la dimensiunea în pixeli
    {
        patrat(x, y, l)
        fractal((x – l) / 2, (y – l) / 2, l / 2)
        fractal((x + l) / 2, (y + l) / 2, l / 2)
    }
}
Fig. 1. c)
În același mod se obțin și figurile clasice Koch, Sierpinski, Kepler, Cantor…

b) Turnurile din Hanoi

Nu putem vorbi de recursivitate fără să tratăm problema turnurilor din Hanoi. Această problemă presupune existența unui set de n discuri de diferite mărimi (în Fig. 2. avem n = 4 discuri), așezate în ordine pe o tijă numită sursă (discul cu circumferința cea mai mare se găsește cel mai jos). Există de asemenea încă două tije numite intermediar și destinație.
Obiectivul problemei (jocului) constă în mutarea celor n discuri de pe tija sursă pe tija destinație folosind tija intermediar cu următoarele trei restricții:
1. Se poate muta o dată o singură piesă de pe o anumită tijă (cea mai de sus). În Fig. 2. singura piesă disponibilă este cea roșie.
2. Nu se poate pune un disc de dimensiune mai mare peste un disc de dimensiune (circumferință) mai mică.
3. Numărul de mutări trebuie să fie minim.
Fig. 2. – Problema turnurilor din Hanoi
Rezolvarea acestei probleme constă în rezolvarea a trei etape distincte.
Prima etapă necesită mutarea a n – 1 discuri de pe sursă pe intermediar, ceea ce ne va da acces la discul cel mai mare.
Fig. 3. – Prima etapă de rezolvare a problemei
A doua etapă constă în mutarea unui disc de pe sursă pe destinație, lucru ce se poate face foarte ușor.
Fig. 4. – A doua etapă de rezolvare a problemei
A treia etapă constă în revenirea la discurile mutate în prima etapă și să mutăm aceste n-1 discuri de pe „intermediar” pe „destinație” obținând astfel configurația finală (Fig. 5.)
Fig. 5. – A treia etapă de rezolvare a problemei
Dacă ne uităm la restricțiile inițiale observăm că am îndeplinit doar două dintre cele trei: nu am pus un disc de dimensiune mai mare pe un disc de dimensiune mai mică și am obținut un număr minim de pași. Nu am îndeplinit însă condiția are cere să se mute un singur disc o dată (ar fi corect dacă n – 1 ar fi 1 adică n ar fi 2).
Fig. 6. – Turnurile din Hanoi cu 2 discuri
Să revenim însă când n – 1 > 1 ca în figura 3. și să rearanjăm tijele, făcând abstracție de cel mai mare disc (nu intră în calcul decât la etapa a doua) și obținem problema turnurilor din Hanoi, dar cu n – 1 discuri și altă tijă numită intermediar (C) și altă tijă numită destinație (B).
Fig. 7. – Interschimbarea tijelor B și C
Analog pentru etapa a treia în care se schimbă sursa și intermediarul.
Fig. 8. – Interschimbarea tijei sursă cu tija intermediar
La acest nivel putem concepe următorul model care va constitui și baza de funcționare a algoritmului recursiv.
Funcția de rezolvare Hanoi(n, A, B, C) se poate descompune în trei subprobleme în ordinea următoare:
1. Hanoi (n – 1, A, C, B)
2. Hanoi (1, A, B, C)
3. Hanoi (n – 1, B, A, C)
Hanoi(1, A, B, C) este soluția trivială: mută de pe A pe C.
#include
using namespace std;

void Hanoi(int nDiscuri, char tSursa, char tInter, char tDest)
{
    if ( nDiscuri > 0 )
    {
        Hanoi(nDiscuri – 1, tSursa, tDest, tInter);
        cout << tSursa < ” << tDest << endl;
        Hanoi(nDiscuri – 1, tInter, tSursa, tDest);
    }
}

int main()
{
    Hanoi (3,’A’,’B’,’C’);
    return 0;
}
Pentru a înțelege mai bine conceptul de recursivitate aplicat la acest tip de probleme, vom analiza în continuare problema turnurilor din Hanoi cu aceleași condiții inițiale, dar vom introduce încă o tijă intermediară. Pentru a obține o singură soluție la un număr dat de discuri, vom introduce restricția de a alege ca și tijă intermediară pe care să mutăm piesa curentă totdeauna cea mai din stânga liberă, în caz că sunt mai multe libere (Fig. 9.)
Fig. 9. – Turnurile din Hanoi cu 4 tije
Se poate observa deja în figura anterioară modulul de funcționare al algoritmului recursiv: Hanoi(n, A, B, C, D) înseamnă:
1. Hanoi (n – 2, A, C, D, B)

2. Hanoi (1, A, B, D, C) soluția trivială A -> C
3. Hanoi (1, A, B, C, D) soluția trivială A -> D
4. Hanoi (1, C, A, B, D) soluția trivială C -> D
5. Hanoi (n – 2, B, A, C, D)

Mai trebuie să construim condiția de oprire a algoritmului recursiv. Acesta va trebui oprit fie când n ajunge la valoarea 1 fie când ajunge la 2, în funcție de valoarea inițială a lui n (par sau impar).
#include
using namespace std;

void Hanoi4tije(int nDiscuri,
        char tSursa, char tInter1, char tInter2, char tDest)
{
    if ( nDiscuri == 1 )
        cout << tSursa < ” << tDest << endl;
    else if ( nDiscuri == 2 )
    {
        cout << tSursa < ” << tInter1 << endl;
        cout << tSursa < ” << tDest << endl;
        cout << tInter1 < ” << tDest << endl;
    }
    else
    {
        Hanoi4tije(nDiscuri – 2, tSursa, tInter2, tDest, tInter1);
        cout << tSursa < ” << tInter2 << endl;
        cout << tSursa < ” << tDest << endl;
        cout << tInter2 < ” << tDest << endl;
        Hanoi4tije(nDiscuri – 2, tInter1, tSursa, tInter2, tDest);
    }
}

int main()
{
    Hanoi4tije(3, ‘A’, ‘B’, ‘C’, ‘D’);
    return 0;
}

Problemă backtracking Bacalaureat sesiunea august 2001, varianta 1

Enunț

Șiruri de cifre cu cifrele 1,2,3,4

Să se genereze toate șirurile formate din n cifre, fiecare șir generat având următoarele proprietăți:
– conține numai cifre din mulțimea {1, 2, 3, 4};
– orice două cifre alăturate sunt fie ambele pare, fie ambele impare.
Numărul natural n (3 ≤ n ≤ 15) se citește de la tastatură. Toate soluțiile vor fi scrise una după alta, cu spații între ele, fiecare șir fiind scris fără spații între cifrele ce-l formează. De exemplu, pentru n=3, se afișează (nu neapărat în această ordine) șirurile: 111, 113, 131, 311, 311, 313, 331, 333, 222, 224, 242, 244, 422, 424, 442, 444.

Cod sursă

#include
using namespace std;

void back(int K, int N, int Sol[])
{
    if (K >= N)
    {
        for (int i = 0; i < N; ++i)
        {
            cout << Sol[i];
        }
        cout << endl;
        return;
    }

    for (int i = 1; i <= 4; ++i)
    {
        if (K >= 1)
        {
            if (Sol[K – 1] % 2 == i % 2)
            {
                Sol[K] = i;
                back(K + 1, N, Sol);
            }
        }
        else
        {
            Sol[K] = i;
            back(K + 1, N, Sol);
        }
    }
}

int main()
{
    int N, Sol[16];

    cin >> N;

    back(0, N, Sol);

    return 0;
}

Schema funcției backtracking back din codul de mai sus

O altă idee de rezolvare

Dacă toate perechile de cifre alăturate sunt fie pare, fie impare, toate cifrele din fiecare număr rezultat sunt pare, sau impare. În mulțimea {1, 2, 3, 4} sunt 2 numere pare și 2 numere impare. Mai întâi generăm șirurile formate după regulă de mai sus din mulțimea {1, 3} (numerele impare) și apoi {2, 4} (numerele pare). Pentru această soluție, modificăm doar funcțiile back și main să arate astfel:

void back2(int K, int N, int P[], int Sol[])
{
    if (K >= N)
    {
        for (int i = 0; i < N; ++i)
        {
            cout << Sol[i];
        }
        cout << endl;
        return;
    }

    Sol[K] = P[0];
    back(K + 1, N, Sol);
    Sol[K] = P[1];
    back(K + 1, N, Sol);
}

int main()
{
    int N, Sol[16], P[2];

    cin >> N;

    P[0] = 1;
    P[1] = 3;
    back2(0, N, P, Sol);

    P[0] = 2;
    P[1] = 4;
    back2(0, N, P, Sol);

    return 0;

Schema funcției backtracking (modificată) back2

Pornire rapidă „Numere în C#”

Introducere

Această pornire rapidă vă învață despre tipurile de numere în C# în mod interactiv, folosind browser-ul pentru a scrie C# și a vedea rezultatele compilării și rulării codului dvs. Ea conține o serie de lecții care explorează numere și operații matematice în C#. Aceste lecții vă învață elementele fundamentale ale limbajului C#.

Explorați matematica numerelor întregi

Rulați codul următor în fereastra interactivă. Pentru a face aceasta, tastați următorul bloc de cod în fereastra interactivă și faceți clic pe butonul Run:

int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine(c);

Tocmai ați văzut una dintre operațiile matematice fundamentale cu întregi. Tipul int reprezintă un întreg, un pozitiv sau negativ număr întreg. Folosiți simbolul + pentru adunare. Alte operații matematice pentru întregi includ:

  • pentru scădere
  • * pentru înmulțire
  • / pentru împărțire

Sfat. De-a lungul acestei porniri rapide, puteți explora dvs. înșivă modificând codul pe care l-ați scris în fereastra interactivă. Această pornire rapidă oferă exemple pe care le puteți încerca la fiecare pas.

Începeți prin a explora toate aceste operații diverse. Modificați a treia linie pentru a încerca fiecare din aceste operații. După fiecare editare, faceți clic pe butonul Run.

Scădere:

int c = a – b;

Înmulțire:

int c = a * b;

Împărțire:

int c = a / b;

Puteți de asemenea experimenta făcând mai multe operații matematice în același rând, dacă doriți.

Sfat. În timp ce explorați C# (sau oricare limbaj de programare), veți face greșeli când scrieți cod. Compilatorul va găsi aceste erori și vi le va raporta. Când ieșirea conține mesaje de eroare, priviți atent la codul exemplu și la codul din fereastra interactivă pentru a vedea ce să reparați. Acest exercițiu vă va ajuta să învățați structura codului C#.

Explorați ordinea operațiilor

Limbajul C# definește precedența a diferiți operatori matematici cu reguli consistente cu regulile pe care le-ați învățat în matematică. Înmulțirea și împărțirea au precedență mai mare decât adunarea și împărțirea. Explorați aceasta rulând următorul cod în fereastra interactivă:

int a = 5;
int b = 4;
int c = 2;
int d = a + b * c;
Console.WriteLine(d);

Ieșirea demonstrează că înmulțirea este efectuată înaintea adunării.

Puteți forța o ordine diferită de operare adăugând paranteze în jurul operației sau operațiilor pe care le doriți efectuate mai întâi:

int a = 5;
int b = 4;
int c = 2;
int d = (a  + b) * c;
Console.WriteLine(d);

Explorați mai departe combinând mulți diferiți operatori. Înlocuiți linia a patra de deasupra cu ceva asemănător cu asta:

int d = (a + b) – 6 * c + (12 * 4) / 3 + 12;

Poate ați observat un comportament interesant pentru numerele întregi. Împărțirea întregilor întotdeauna produce un rezultat întreg, chiar și atunci când v-ați aștepta ca rezultatul să includă o parte zecimală sau fracțională.

Dacă nu ați văzut acest comportament, încercați următorul:

int a = 7;
int b = 4;
int c = 3;
int d = (a  + b) / c;
Console.WriteLine(d);

Faceți clic pe Run din nou pentru a vedea rezultatele.

Explorați precizia și limitele numerelor întregi

Ultimul exemplu v-a arătat că împărțirea întreagă trunchiază rezultatul. Puteți obține restul folosind operatorul modulo, caracterul %.

int a = 7;
int b = 4;
int c = 3;
int d = (a  + b) / c;
int e = (a + b) % c;
Console.WriteLine($”cat: {d}”);
Console.WriteLine($”rest: {e}”);

Tipul întreg din C# diferă de tipul matematic număr întreg în încă un mod: tipul int are limite minimă și maximă. Rulați acest cod în fereastra interactivă pentru a vedea aceste limite.

int max = int.MaxValue;
int min = int.MinValue;
Console.WriteLine($”Intervalul de intregi este de la {min} la {max}”);

Dacă un calcul produce o valoare care trece de aceste limite, aveți o condiție de underflow sau overflow (condiție de depășire). Răspunsul pare să înfășoare de la o limită la alta. Adăugați aceste două linii la fereastra interactivă pentru a vedea un exemplu:

int what = max + 3;
Console.WriteLine($”Un exemplu de depasire pozitiva (overflow): {what}”);

Observați că răspunsul este foarte aproape de cel mai mic întreg (negativ). Este la fel ca min + 2. Operația de adunare a depășit pozitiv valorile permise pentru întregi. Răspunsul este un foarte mare număr negativ deoarece o depășire pozitivă „se întoarce” de la cea mai mare valoare posibilă întreagă la cea mai mică.

Există alte tipuri numerice cu diferite limite și precizie pe care le-ați folosi când tipul int nu vă împacă nevoile. Haideți să le explorăm pe acestea în continuare.

Lucrați cu tipul double

Tipul numeric double reprezintă un număr în virgulă mobilă de precizie dublă. Acești termeni ar putea fi noi pentru dvs. Un număr în virgulă mobilă este folositor pentru a reprezenta numere ne-întregi care ar putea fi foarte mari sau mici în dimensiune. Precizie dublă înseamnă că aceste numere sunt stocate folosind precizie mai mare decât precizie simplă. Pe calculatoarele moderne, este mai comun să se folosească precizie dublă decât numere de precizie simplă. Haideți să explorăm. Încercați următorul cod în fereastra interactivă și vedeți rezultatul:

double a = 5;
double b = 4;
double c = 2;
double d = (a  + b) / c;
Console.WriteLine(d);

Observați că răspunsul include partea zecimală a câtului. Încercați o expresie puțin mai complicată cu double-uri:

double a = 19;
double b = 23;
double c = 8;
double d = (a  + b) / c;
Console.WriteLine(d);

Intervalul unei valori double este mult mai mare decât valorile întregi. Încercați următorul cod în fereastra interactivă:

double max = double.MaxValue;
double min = double.MinValue;
Console.WriteLine($”Intervalul lui double este de la {min} la {max}”);

Valorile acestea sunt tipărite în notație științifică. Numărul din stânga lui E este significandul. Numărul din dreapta este exponentul, ca o putere a lui 10.

La fel ca numerele zecimale în matematică, numerele double în C# pot avea erori de rotunjire. Încercați acest cod:

double third = 1.0. / 3.0;
Console.WriteLine(third);

Știți că 0.3 cu 3 repetându-se nu este exact același cu 1/3.

Provocare

Încercați alte calcule cu numere mari, numere mici, înmulțire și împărțire folosind tipul double. Încercați calcule mai complicate.

Lucrați cu tipuri în virgulă fixă

Ați văzut tipurile numerice de bază în C#: întregi și double-uri. Există un alt tip de învățat: tipul decimal. Tipul decimal are un interval mai mic dar precizie mai mare decât double. Termenul virgulă fixă înseamnă că punctul zecimal (sau punct binar) nu se mișcă. Haideți să aruncăm o privire:

decimal min = decimal.MinValue;
decimal max = decimal.MaxValue;
Console.WriteLine($”Intervalul tipului decimal este între {min} și {max}”);

Observați că intervalul este mai mic decât tipul double. Puteți vedea mai marea precizie cu tipul decimal încercând următorul cod:

double a = 1.0;
double b = 3.0;
Console.WriteLine(a / b);

decimal c = 1.0M;
decimal d = 3.0M;
Console.WriteLine(c / d);

Sufixul M pe numere este cum indicați că o constantă trebuie să folosească tipul decimal.

Observați că matematica folosind tipul decimal are mai multe cifre în dreapta punctului decimal.

Provocare

Acum că ați văzut diferite tipuri numerice, scrieți cod care calculează aria unui cerc a cărui rază este 2.50 centimetri. Țineți minte că aria unui cerc este raza ridicată la pătrat înmulțit cu PI. Un indiciu: .NET conține o constantă pentru PI, Math.PI pe care o puteți folosi pentru această valoare.

Ar trebui să obțineți un răspuns între 19 și 20.

Provocare finalizată

Ați venit cu ceva asemănător cu aceasta?

double raza = 2.50;
double aria = Math.PI * raza * raza;
Console.WriteLine(aria);

Încercați câteva alte formule dacă doriți.

Felicitări!

Ați încheiat pornirea rapidă „Numere în C#”.

Puteți învăța mai multe despre numere în C# în următoarele subiecte:

Tradus din această pagină oficială de documentație Microsoft.

Problemă de grafuri clasa a XI-a, matematică-informatică, informatică ne-intensiv

Enunț

Se consideră un graf neorientat cu n vârfuri și m muchii, al cărei matrice de adiacență este citită de la tastatură. Fișierul „graf.txt” conține mai multe secvențe de vârfuri, aflate una sub alta, vârfurile fiecărei secvențe fiind scrise pe câte un rând și separate prin spații (nu se cunoaște câte astfel de secvențe există în fișier). Scrieți un program care afișează pe ecran acele secvențe de vârfuri din fișierul de intrare ce constituie lanțuri în graful dat, precizând pentru fiecare lanț dacă este elementar sau ne-elementar, apoi determină lanțul (lanțurile) de lungime maximă (reamintim că lungimea unui lanț este dată de numărul vârfurilor componente.

Exemplu

graf.txt:
1 2 6
8 7 6 1
3 4 5 3 2 8
5 3 2 7
1 2 8

fisier.in (în enunț, citit de la tastatură):
8 9
1 1 0 0 0 1 0 1
1 1 1 0 0 0 0 1
0 1 1 1 1 0 0 0
0 0 1 1 1 0 0 0
0 0 1 1 1 0 0 0
1 0 0 0 0 1 1 0
0 0 0 0 0 1 1 1
1 1 0 0 0 0 1 1

Se afișează în consolă:
1.
NU ESTE LANT
2.
ESTE LANT
ESTE ELEMENTAR
3.
ESTE LANT
NU ESTE ELEMENTAR
4.
NU ESTE LANT
5.
ESTE LANT
ESTE ELEMENTAR
Lanturile de lungime maxima 5 sunt in lista de lanturi:
 – al 2-lea

Codul sursă

#include
#include
#include
#include
using namespace std;

bool este_lant(int N, int M, vector<vector> &A,
    char line[], int l)
{
    string str = line;
    istringstream s(str);

    vector lant(0);
    int x;
    while (s >> x)
    {
        lant.push_back(x);
    }

    for (int i = 0; i < lant.size() – 1; ++i)
    {
        if (A[lant[i]][lant[i + 1]] == 0)
        {
            return false;
        }
    }
    return true;
}

bool este_elementar(int N, int M, vector<vector> &A,
    char line[], int l)
{
    string str = line;
    istringstream s(str);

    vector lant(0);
    int x;
    while (s >> x)
    {
        lant.push_back(x);
    }

    for (int i = 0; i < lant.size(); ++i)
    {
        for (int j = i + 1; j < lant.size(); ++j)
        {
            if (lant[i] == lant[j])
            {
                return false;
            }
        }
    }
    return true;
}

int main()
{
    int N, M;

    // primul fisier de intrare:
    ifstream in(„fisier.in”);
    in >> N >> M;
    vector<vector> A(N + 1, vector(N + 1));
    for (int i = 1; i <= N; ++i)
    {
        for (int j = 1; j <= N; ++j)
        {
            in >> A[i][j];
        }
    }
    in.close();


    // al doilea fisier de intrare:
    ifstream in2(„graf.txt”);

    // valorile de pe acelasi indice din vectorii
    // urmatori sunt asociate:
    vector lungimi_lanturi(0);
    vector id_lanturi(0);

    int id = 1;

    // va retine randul curent:
    char line[100];

    int l;
    do
    {
        // se citeste un rand intreg:
        in2.getline(line, 100);
        l = strlen(line);

        // randul este gol:
        if (l == 0) continue;

        // determina daca sirul de varfuri din randul curent
        // este un lant:
        bool e_lant = este_lant(N, M, A, line, l);

        // id este indicele (incepand de la 1) al randului curent:
        cout << (id++) << ". " << endl;

        // afiseaza daca este lant sau nu:
        cout << (e_lant ? "ESTE LANT" : "NU ESTE LANT") << endl;

        // daca e lant, se efectueaza verificari suplimentare:
        if (e_lant)
        {
            bool e_elementar = este_elementar(N, M, A, line, l);

            cout << (e_elementar ? "ESTE ELEMENTAR" : "NU ESTE ELEMENTAR") << endl;

            // se numara spatiile din rand pt. a afla lungimea
            // lantului:
            int spatii = 0;
            for (int i = 0; i < l; ++i)
            {
                if (line[i] == ‘ ‘)
                {
                    ++spatii;
                }
            }

            id_lanturi.push_back(id – 2);
            lungimi_lanturi.push_back(spatii);
        }
    } while (l > 0);
    
    in2.close();

    // se cauta lanturile de lungime maxima:
    int maxl = -1;
    for (int i = 0; i < id_lanturi.size(); ++i)
    {
        int lungime_lant = lungimi_lanturi[i];
        if (lungime_lant > maxl)
        {
            maxl = lungime_lant;
        }
    }

    cout << "Lanturile de lungime maxima " << maxl <<
        ” sunt in lista de lanturi:” << endl;
    for (int i = 0; i < id_lanturi.size(); ++i)
    {
        int lungime_lant = lungimi_lanturi[i];
        if (lungime_lant == maxl)
        {
            cout << " – al " << (i + 1) <<
                „-lea” << endl;
        }
    }

    return 0;
}

Pornire rapidă „Hello World în C#”

Salut C#

Această pornire rapidă vă învață C# interactiv, folosind browser-ul pentru a scrie c# și a vedea rezultatele compilării și rulării codului dvs. Ea conține o serie de lecții care încep cu un program „Hello World”. Aceste lecții vă învață elementele fundamentale ale limbajului C#.

Rularea primului dvs. program C#

Rulați următorul cod în fereastra interactivă. Pentru a face asta, tastați următorul bloc de cod în fereastra interactivă și faceți clic pe butonul Run.

Console.WriteLine(„Hello World!”);

Felicitări! Ați rulat primul dvs. program C#. Este un simplu program care tipărește mesajul „Hello World!”. El a folosit metoda Console.WriteLine pentru a tipări acel mesaj. Console este tipul care reprezintă fereastra consolă. WriteLine este o metodă a tipului Console care tipărește o linie de text în acea consolă text.

Haideți să mergem înainte și să explorăm mai mult. Restul acestei lecții explorează lucrul cu tipul string, care reprezintă text în C#. Precum tipul Console, tipul string are metode. Metodele string lucrează cu text.

Declararea și folosirea variabilelor

Primul dvs. program a tipărit string-ul „Hello World!” pe ecran.

Sfat. Pe măsură ce explorați C# (sau oricare limbaj de programare), veți face greșeli când scrieți cod. Compilatorul va găsi acele erori și vi le va raporta. Când ieșirea conține mesaje de eroare, priviți de aproape la codul exemplu, și codul în fereastra interactivă pentru a vedea ce să reparați. Acel exercițiu vă va ajuta să învățați structura codului C#.

Primul dvs. program este limitat la tipărirea unui singur mesaj. Puteți scrie programe mai utile folosind variabile. O variabilă este un simbol pe care îl puteți folosi pentru a rula același cod cu valori diferite. Haideți să încercăm asta! Înlocuiți codul pe care l-ați scris în fereastra interactivă cu codul următor:

string aFriend = „Bill”;
Console.WriteLine(aFriend);

Prima linie declară o variabilă, aFriend și îi atribuie o valoare, „Bill”. A doua linie tipărește numele.

Puteți atribui valori diferite oricărei variabile pe care o declarați. Puteți schimba numele la unul dintre prietenii dvs. Adăugați aceste două linii în fereastra interactivă după codul pe care l-ați adăugat deja.

aFriend = „Maira”;
Console.WriteLine(aFriend);

Observați că aceeași linie de cod tipărește 2 mesaje diferite, bazat pe valoarea stocată în variabila aFriend.

Probabil ați observat de asemenea că acest cuvânt, „Hello”, lipsește în ultimele 2 mesaje. Haideți să rezolvăm asta acum. Modificați liniile care tipăresc mesajul în următorul:

Console.WriteLine(„Hello ” + aFriend);

Faceți clic pe Run din nou pentru a vedea rezultatele.

Ați folosit până acum + pentru a construi șiruri de caractere din variabile și șiruri constante. Există o cale mai bună. Puteți pune o variabilă între caracterele { și } pentru a-i spune lui C# să înlocuiasca acel text cu valoarea variabilei.

Aceasta se numește interpolarea șirurilor de caractere.

Dacă adăugați un $ înainte de ghilimelele de deschidere ale unui șir de caractere, puteți apoi include variabile, precum aFriend, înăuntrul șirurilor de caractere între acolade. Dați-i o încercare:

Console.WriteLine($”Hello {aFriend}”);

Faceți clic pe Run din nou pentru a vedea rezultatele. În loc de „Hello {aFriend}”, mesajul ar trebui să fie „Hello Maira”.

Lucrul cu șirurile de caractere

Ultima dvs. editare a fost prima noatră privire la ce puteți face cu șirurile de caractere. Haideți să explorăm mai mult.

Nu sunteți limitați la o singură variabilă între acolade. Încercați aceasta:

string firstFriend = „Maria”;
string secondFriend = „Sage”;
Console.WriteLine($”My friends are {firstFriend} and {secondFriend}”);

Pe măsură ce explorați mai mult cu șirurile de caractere, veți găsi că șirurile sunt mai mult decât o colecție de litere. Puteți afla lungimea unui șir folosind Length. Length este o proprietate a string și returnează numărul de caractere în acel șir de caractere. Adăugați următorul cod la sfârșitul ferestrei interactive:

Console.WriteLine($”The name {firstFriend} has {firstFriend.Length} letters.”);
Console.WriteLine($”The name {secondFriend} has {secondFriend.Length} letters.”);

Sfat. Acesta este un moment bun pentru a explora dvs. de unul singur. Ați învățat că Console.WriteLine() scrie text pe ecran. Ați învățat cum să declarați variabile și să concatenați șiruri împreună. Experimentați în fereastra interactivă. Fereastra are o funcție numită IntelliSense care face sugestii pentru ce puteți face. Tastați un . după d în firstFriend. Veți vedea o listă cu sugestii pentru proprietăți și metode pe care le puteți folosi.

Faceți mai multe cu șirurile de caractere

Ați folosit o metodă, Console.WriteLine, pentru a tipări mesaje. O metodă este un bloc de cod care implementează o acțiune. Ea are un nume, deci o puteți accesa.

Presupuneți că șirurile dvs. de caractere au spații la început sau la sfârșit pe care nu vreți să le afișați. Vreți să tundeți spațiile din șirurile de caractere. Metoda Trim și metodele conexe TrimStart și TrimEnd fac acea muncă. Dvs. puteți simplu să folosiți aceste metode pentru a elimina spațiile de la început și de la sfârșit. Încercați acest cod:

string greeting = ”        Hello World!        „;
Console.WriteLine($”[{greeting}]”);

string trimmedGreeting = greeting.TrimStart();
Console.WriteLine($”[{trimmedGreeting}]”);

trimmedGreeting = greeting.TrimEnd();
Console.WriteLine($”[{trimmedGreeting}]”);

trimmedGreeting = greeting.Trim();
Console.WriteLine($”[{trimmedGreeting}]”);

Acest exemplu întărește două concepte importante pentru lucrul cu șiruri de caractere. Metodele care manipulează șiruri de caractere întorc noi obiecte string în loc să le modifice pe loc. Puteți vedea că fiecare apel la oricare din metodele Trim întoarce un nou string dar nu schimbă mesajul original.

Există alte metode disponibile pentru a lucra cu șiruri de caractere. De exemplu, probabil ați folosit o comandă caută și înlocuiește într-un editor sau procesor de texte înainte. Metoda Replace face ceva similar într-un șir de caractere. Ea caută pentru un subșir și il înlocuiește un un text diferit. Funcția Replace ia 2 parametri. Acestea sunt șirurile dintre paranteze. Primul șir este textul de căutat. Al doilea șir este textul cu care se înlocuiește. Încercați dvs. înșivă. Adăugați acest cod. Tastați-l înăuntru pentru a vedea indiciile cum începeți să tastați .Re după variabila sayHello.

string sayHello = „Hello World!”;
Console.WriteLine(sayHello);
sayHello = sayHello.Replace(„Hello”, „Greetings”);
Console.WriteLine(sayHello);

Alte două metode folositoare fac un șir ALL CAPS (toate literele mari de tipar) sau cu toate literele mici. Încercați codul următor. Tastați-l înăuntru pentru a vedea cum IntelliSense dă indicii cum începeți să tastați To:

Console.WriteLine(sayHello.ToUpper());
Console.WriteLine(sayHello.ToLower());

Căutați șiruri de caractere

Cealaltă parte a unei operații de caută și înlocuiește este să găsiți text într-un șir. Puteți folosi metoda Contains pentru căutare. Ea vă ajută dacă un șir conține un subșir înăuntrul lui. Încercați următorul cod pentru a explora Contains:

string songLyrics = „You say goodbye, and I say hello”;
Console.WriteLine(songLyrics.Contains(„goodbye”));
Console.WriteLine(songLyrics.Contains(„greetingss”));

Metoda Contains returnează o valoare booleană care spune dacă șirul pe care l-ați căutt a fost găsit. O valoare booleană stochează o fie o valoare true (adevărat) sau false (fals). Veți învăța mai multe despre valorile booleane într-o lecție viitoare.

Provocare

Există două metode similare, StartsWith și EndsWith care de asemenea caută subșiruri într-un șir. Acestea găsesc un subșir la începutul sau la sfârșitul șirului. Încercați să modificați exemplele anterioare pentru a folosi StartsWith și EndsWith în loc de Contains. Căutați „You” sau „goodbye” la începutul unui șir. Căutați „hello” sau „goodbye” la sfârșitul unui șir.

Notă. Priviți punctuația dvs. când testați pentru text la sfârșitul șirului de caractere. Dacă șirul se sfârșește cu un punct, trebuie să verificați pentru un șir care se sfârșește cu un punct.

Ar trebui să obțineți true pentru a se începe cu „You” și a se sfârși cu „hello” și false pentru a începe sau a se sfâri cu „goodbye”.

Provocare finalizată

Ați făcut ceva asemănător cu acestea?

string songLyrics = „You say goodbye, and I say hello”;
Console.WriteLine(songLyrics.StartsWith(„You”));
Console.WriteLine(songLyrics.StartsWith(„goodbye”));

Console.WriteLine(songLyrics.EndsWith(„hello”));
Console.WriteLine(songLyrics.EndsWith(„goodbye”));

Felicitări!

Ați completat introducerea rapidă „Hello C#”.

Puteți învăța mai multe despre lucrul cu string-uri în subiectul despre string-uri din Ghidul de programare C#. Sfaturi cum-să despre lucrul cu string-uri.

Tradus din această pagină oficială de documentație Microsoft.

[C#] Convertirea string în Color și invers

Aceste metode statice sunt folositoare, de exemplu, într-un program în care utilizatorul poate selecta o culoare care trebuie salvată ca o setare, de exemplu într-un fișier XML, și încărcată din acel fișier XML la următoarea pornire a programului. Metoda Color.ToString nu este suficientă uneori (de exemplu, în cazul în care șirul de caractere trebuie într-un alt format).

Metodele sunt puse într-o clasă statică Utils, care nu e pusă în întregime aici. Sunt marcate ca internal pentru a putea fi folosite din interiorul proiectului în care se află dar nu din afară.

Cod sursă

internal static string ColorToString(Color color)
{
    byte a = color.A,
        r = color.R,
        g = color.G,
        b = color.B;
    byte[] arr = new byte[] { a, r, g, b };
    string s = BitConverter.ToString(arr).Replace(„-„, „”);
    return „#” + s;
}

internal static Color StringToColor(string str)
{
    int a = Int32.Parse(str.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
    int r = Int32.Parse(str.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);
    int g = Int32.Parse(str.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);
    int b = Int32.Parse(str.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);

    return Color.FromArgb(a, r, g, b);
}

Capturi de ecran

Explicație

Color este un tip structură din domeniul (en. namespace) System.Drawing. Are proprietăție A (opacitatea, alfa), R (red, roșu), G (green, verde), B (blue, albastru). Aceste 4 proprietăți au tipul byte și stochează valori de la 0 la 255. Cu cât valoarea e mai mare, cu atât culoarea respectivă e mai intensă în culoarea afișată de structura Color respectivă, sau în cazul A culoarea devine mai puțin transparentă cu cât valoarea e mai mare, 255 însemnând opac complet.

Funcția ColorToString transformă culoarea color într-un string. Ea folosește metoda statică BitConverter.ToString pentru a transforma tabloul unidimensional de lungime 4, tip byte cu cele 4 proprietăți in ordinea de mai sus, pentru a obține un șir de caractere cu cele 4 proprietăți în baza 16. Apoi imediat se apelează Replace pentru a șterge caracterele „” din șirul obținut. De exemplu, înainte de Replace valoarea este „F4-19-28-F1” și se șterg caracterele „” apoi se pune un # în față, se obține valoarea returnată „#F41928F1”.

Funcția StringToColor primește un string din care se șterge primul caracter (#) și se iau rând pe rând 2 câte 2 caractere din el: din primele 2 se obține un int cu nr. transformat în baza 10 din baza 16, la fel din celelalte. Apoi se folosește metoda statică Color.FromArgb apelată cu cele 4 valori definitorii ale unei culori: a, r, g, b.

Cele 2 metode sunt inverse una alteia.

Dacă sunt folosite în producție, aceste metode trebuie făcute să intercepteze excepțiile posibile (try catch finally). Doar metoda StringToColor necesită modificări în acest caz:

internal static Color StringToColor(string str)
{
    try
    {
        int a = Int32.Parse(str.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
        int r = Int32.Parse(str.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);
        int g = Int32.Parse(str.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);
        int b = Int32.Parse(str.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);

        return Color.FromArgb(a, r, g, b);
    }
    catch (Exception)
    {
        return Color.Empty;
    }
}

[C++, programare dinamică] Numărul de numere de N cifre cu produsul cifrelor 0

Dându-se N, scrieți un program care determină câte numere de N cifre cu produsul cifrelor 0 există.

·        N este numărul de cifre ale numerelor cerute

Fiindcă sunt în discuție numere în baza 10, rezultatul este întotdeauna 0 dacă produsul este mai mare decât 9N, 9 fiind cea mai mare cifră în baza 10. Pentru algoritmul naiv, folosit pentru verificare, este important că dacă un număr conține cel puțin o cifră 0 atunci produsul cifrelor sale este 0 și numărul de numere căutat crește cu 1.

Stabilirea formulei de recurență

Dacă notăm:

·        A[x] = câte numere de x cifre au produsul cifrelor 0, și

·        B[i] = câte numere de i cifre există

Cazurile de bază ale recurenței sunt:

·        A[0] = 0 (nu există nr. de 0 cifre)

·        A[1] = 1 (cazul numărului 0)

·        Mai rămâne cazul general A[x] = ?, tratat în continuare.

Pentru ca un număr să aibă x cifre, trebuie ca prima cifră să fie diferită de 0, deci pentru prima cifră există 9 posibilități (cazurile celor 10 cifre din baza 10, mai rămân 9 cifre dacă 0 se exclude). Din acest paragraf rezultă următoarele valori pentru B:

B[1] = nr. de nr. de 1 cifră posibile = 10,

               B[2] = 9 * 10 nr. de 2 cifre posibile,

               B[3] = 9 * 10 * 10 numere de 3 cifre posibile

etc.

Urmează exprimări ale A[x].
A[2] se calculează manual mai jos și rezultă din calcule valoarea 9 * 1.
Prima cifră nu poate fi 0 deci pentru prima cifră sunt în total 9 posibilități. A doua cifră poate și reprezintă o singură posibilitate. Cazurile sunt: 10, 20, ….., 90.
A[3] = 9 * 1 * 9 (nr. de 3 cifre cu a doua cifră 0 = 9 * câte numere de 1 cifră există, minus 1, adică fără 0)
               + 9 * 9 * 1 (nr. de 3 cifre cu a treia cifră 0 = 9 * câte numere de 1 cifră există, minus 1, adică fără 0))
+ 9 * 1 * 1 (nr. de 3 cifre cu a doua și a treia cifră 0)
= nr. de numere de 3 cifre cu cel puțin o cifră 0

Intuitiv dar incorect:
= 9 * (B[1] – 1) + 9 * (B[1] – 1) + A[2] (ce e bold = 9 sau A[2], se aduna la fiecare A[x] pe lângă A[x – 1] și altele, la sfârșitul sumei)
Din formula generala gasita mai tarziu, rezulta aceasta relatie pt A[3]:
                                             = 9 * A[2] + 9 * A[2] + 9
Apoi:
               B[4] = 9 * 10 * 10 * 10,
               Dintre care A[4] = 9 * 1 * 9 * 9 + 9 * 9 * 1 * 9 + 9 * 9 * 9 * 1 +
                                             9 * 1 * 1 * 9 + 9 * 9 * 1 * 1 + 9 * 1 * 9 * 1 +
                                             9 * 1 * 1 * 1 // o notație mai scurtă: 9199, 9919, 9991, 9119, 9911, 9191, 9111, ce e cu bold face împreună valoarea (9 * A[3]).
                                             = 9 * A[3][0] + 9*1*9*9 + 9*1*1*9 + 9*1*9*1 + 9 ( 9*1*1*1 ) =
A[4] = 9*(991+919+911) + 9*(99+91) + 9*(19) + 9*(11)
O exprimare incompletă dar care aduce înțelesuri noi:
                              A[4] = 9 * A[3] + 9 * A[3] / 9 (nr. de nr. de 3 cifre cu a doua cifră 0)
9 * A[3]: Cifra 1: 9 posibilități, cifra 2: 9 posibilități
9 * A[3] / 9: Cifra 1: 9 posibilități, cifra 2: 1 posibilitate (0),
    și prin împ. la 9 => Cifra 1: 1 posibilitate, cifra 2: 1 posibilitate,
    și prin înm. cu 9 se adaugă o cifră în față.
Împreună, cei doi termeni din expresia lui A[4] de mai sus însumează pt. a doua cifră 10 posibilități, câte sunt în general, dar în expresie, al doilea termen se împarte la 9 pentru ca posibilitățile din cifra 1 să devină 9/9 (9 împărțit din 9) din 9 adică 1. Astfel se tratează cazul când prima cifră e oricare poate fi în general (9 posibilități) și când prima cifră e oricare cifră din baza 10 (adică 10 posibilități).
Alte exprimări:
               = 9 * A[3] + 9 * (câte nr. de 2 cifre cu cifra unităților nenulă sunt) + 9 * (B[1] – 1) + 9
               = 9 * A[3] + 9 * (B[2] – 1) + 9 * (B[1] – 1) + 9.
Dintre care A[5] = 9 * A[4] + 9 * A[3] + 9 * A[2] + 9 * A[1] (am scos semnele de + și *, fiecare termen este sumă de produse de 9 și 1)
Încercare de a scrie formula generală: A[x] = A[x-1] + (A[x-2] – 1) + (A[x-3] – 1) + … + A[1] ;
Formula generală cu termeni crescători: A[x] = A[1] + … + (A[x-3] – 1) + (A[x-2] – 1) + A[x-1];
Verificare:
A[2] = 9 * A[1] + 0
A[3] = A[1] + A[2] = 9 * A[2] + 9 // (1) + (9*1)
A[4] = 9 * A[3] + 9
+ 9 * (nr. de 3 cifre cu cifra zecilor 0) + (nr. de 3 cifre cu cifra unităților 0) +
                                            
Având în vedere încercările de mai sus, mi-am dat seama este bine în produse să nu iau cele 10 posibilități de cifre direct, că e nevoie să iau 9 separat de unu-le care repr. cifra 0.
Exerciții:
A[2] = 91 = 9*A[1]
A[3] = 9*(91) + 9*(19) + 9*(11)
                              = 9*A[2] + 9*A[1] + 9
A[4] = 9*(991+919+911) + 9*(99+91) + 9*(19) + 9*(11)
                              = 9*A[3] + 9*(99 + A[2]) + 9*A[1] + 9
A[5] = 9*A[4][0] + 9*(999+991+919+911) + 9*(99+91) + 9*(9+1)
                              = 9*A[4] + 9*(999+A[3]) + 9*(99 + A[2]) + 9*A[1] + 9
Penultima încercare de a scrie o formulă de recurență corectă:
A[x] = 9 * A[x-1] + 9 * (_(x-2)cifreDe9_ + A[x-2])  +
               9 * (_(x-3)cifreDe9_ + A[x-3]) + … + 9*A[2] + 9
Exerciții:
A[1] = 1
A[2] = 9 * A[1]
A[3] = 9 * A[2] + 9 * A[2] + 9
               = 9*9 + 9 * 9 + 9= 81 +81+9
A[4] = 9 * A[3] + 9 * (99 + A[2]) + 9 * A[2] + 9
               = 9 * (A[3] + 9*9 + A[2] + A[2] + 1) =
               = 9 * (171 + 81 + 9 + 9 + 1) = 9(271) =  2439
A[5]= 9 * A[4] + 9 * (999 + A[3]) + 9 * (99 * A[2]) + 9 * A[2] + 9
               = 9 *(A[4] + 9*9*9 + A[3] + 9 * 9 + A[2] + A[2] + 1) =
               = 9 * ()
Formula finală:
A[x] = 9 * (A[x-1] + _(x-2)cifreDe9_ + A[x-2]  +
               _(x-3)cifreDe9_ + A[x-3] + … + A[2] + 1)

Codul sursă

#include
#include
#include
using namespace std;

/// Prin algoritm naiv, intoarce nr. de numere de
/// N cifre cu produsul cifrelor 0. pow10 si pow9N sunt
/// valori precalculate pentru optimizarea for-ului din
/// functia main().
long long int naiv(int N,
 long long int pow10[18],
 long long int pow9N)
{
 if (N == 0) return 0;

 long long int j = 0, prod, ii, i, start;
 if (N == 1) start = 0;
 else start = pow10[N – 1];

 for (i = start; i < pow10[N]; ++i)
 {
  if (i == 0)
  {
   ++j;
  }
  else
  {
   ii = i;
   while (ii)
   {
    if (ii % 10 == 0)
    {
     ++j;
     break;
    }
    ii /= 10;
   }
  }
 }

 return j;
}


// cate numere de N cifre se pot face sa aiba produsul cifrelor 0
long long int pd(long long int N, vector &A)
{
 A[0] = 0;
 A[1] = 1;
 A[2] = 9;
 for (long long int i = 3; i <= N; ++i)
 {
  A[i] = 0;
  for (long long int j = 1; j <= i; ++j)
  {
   if (j == 1)
    A[i]++;
   else if (j == 2)
    A[i] += A[2];
   else if (j == 3)
   {
    if (i > 3)
    {
     A[i] += A[j – 1] +
      pow(9, j – 1);
    }
    else
    {
     A[i] += A[j – 1];
    }
   }
   else if (j >= 4)
   {
    if (j == i)
    {
     A[i] += A[j – 1];
    }
    else
    {
     A[i] += A[j – 1] +
      pow(9, j – 1);
    }
   }
  }
  A[i] *= 9;
 }

 return A[N];
}


int main()
{
 int N;

 cout << "Introduceti numarul de cifre: " << endl;
 cin >> N;

 vector A(N + 1);
 // contine puteri ale lui 10 pt. calcul mai rapid in algoritmul naiv
 long long int pow10[] = {
  1,
  10,
  100,
  1000,
  10000,
  100000,
  1000000,
  10000000,
  100000000,
  1000000000,
  10000000000,
  100000000000,
  1000000000000,
  10000000000000,
  100000000000000,
  1000000000000000,
  10000000000000000,
  100000000000000000,
  1000000000000000000,
  10000000000000000000
 };

 long long int pow9N = pow(9, N);
 ofstream out(„Text.txt”);
 long long int rezultat = pd(N, A);
 // compara rezultatele alg. naiv cu cel de pd.
 for (int i = 0; i <= N; ++i)
 {
  long long int rn = naiv(i, pow10, pow9N);
  out << "A[" << i << "] = " <<
   A[i] << " (pd)\t\t|\t\t" << rn <<
   ” (naiv)\t\t|\t\t” <<
   (rn == A[i] ? „CORECT” : „___GRESIT”) << endl;
 }
 out.close();

 cout << "Rezultatele au fost afisate in fisier." << endl;
 return 0;
}

Capturi de ecran

Ieșire

O parte din ce afiseaza programul in fisier:
A[0] = 0 (pd)  |  0 (naiv)  |  CORECT
A[1] = 1 (pd)  |  1 (naiv)  |  CORECT
A[2] = 9 (pd)  |  9 (naiv)  |  CORECT
A[3] = 171 (pd)  |  171 (naiv)  |  CORECT
A[4] = 2439 (pd)  |  2439 (naiv)  |  CORECT
A[5] = 30951 (pd)  |  30951 (naiv)  |  CORECT
A[6] = 368559 (pd)  |  368559 (naiv)  |  CORECT
A[7] = 4217031 (pd)  |  4217031 (naiv)  |  CORECT
A[8] = 46953279 (pd)  |  46953279 (naiv)  |  CORECT
A[9] = 512579511 (pd)  |  512579511 (naiv)  |  CORECT
A[10] = 5513215599 (pd)  |  5513215599 (naiv)  |  CORECT

[C# WinForms] Reținerea dimensiunii unei ferestre de la o sesiune la alta

1. În Visual Studio se creează un proiect nou cu limbajul C#, de tip Desktop App sau Windows Forms App. Se observă că se creează automat în acest proiect un formular (Form1) și mai multe fișiere vizibile în panoul din dreapta-sus numit Solution Explorer. Imediat apoi se deschide automat fișierul Form1.cs in modul Design.

2. Se deschide elementul Properties din panoul Solution Explorer cu săgeata din stânga lui Properties. În interiorul sublistei se vede numele de fișier „Settings.settings”. Se face dublu-clic pe el. Se deschide un nou tab corespunzător.

3. În noul tab se poate introduce o nouă înregistrare (rând), mai exact în tabelul cu coloanele „Name”, „Type”, „Scope” și „Value” (ro. Valoare). Înregistrările din tabel sunt setări pe care programul le poate citi sau/și scrie. Inițial nu există nici una. În celula din coloana „Name” (ro. Nume) se introduce un identificator de variabilă care va fi folosit în programul care se scrie pentru a citi/scrie setarea. Coloana „Type” (ro. Tip) cuprinde ComboBox-uri (casete de selectare) care conțin variante de tipuri de date posibile pentru setările programului, dintre care pentru o setare se alege tipul ei. Celula din coloana „Scope” (ro. Domeniu) conține o alegere a dezvoltatorului programului între „User” (ro. Utilizator) și „Application”. Setările cu domeniul „User” pot fi scrise și citite din programul creat, pentru fiecare utilizator al sistemului de operare în parte, dar cele „Application” nu pot fi decât citite din programul creat (nu pot fi scrise).

4. În figura următoare s-a creat o setare de tipul System.Drawing.Size (ro. Dimensiune) numită „Form1Size”. În coloana „Scope” se alege „User” și în coloana „Value” se introduc 2 numere întregi separate prin virgulă și, eventual, spații care reprezintă în general lățimea și, respectiv, înălțimea unui obiect (în cazul dat, un formular/o fereastră).

5. Se va vedea mai jos în acest articol cum se accesează setările din cod. După modificarea paginii Settings.settings se apasă butonul Save (Ctrl+S) (ro. Salvează) sau butonul Save All (Ctrl+Shift+S) (ro. Salvează toate).

Se dorește ca setările programului, salvate automat în general într-un fișier de pe calculatorul pe care este instalat sau rulat programul, să fie citite la pornirea programului și salvate pe disc la închiderea ferestrei programului (dacă s-au creat mai multe ferestre, se consideră fereastra principală). Formularul principal, inițial numit „Form1”, are două evenimente care trebuie interceptate pentru a realiza ce se propune: „Load” (ro. „încărcare”) si „FormClosing” (tradus aproximativ „în timpul închiderii formularului”). Dedesubt se vede evenimentul „Load”. Pentru a crea o metodă care interceptează acest eveniment (en. „[event] handler”) se face dublu-clic pe rândul „Load” din tabelul din panoul Properties din dreapta-jos (se poate mai simplu prin dublu-clic pe spațiul gol din formular în designer):

6. După dublu-clic se deschide Form1.cs în editorul de cod, dar designerul poate rămâne deschis într-un tab separat. Cursorul de editare al codului este poziționat în noua metodă „Form1_Load”. Codul scris între cele 2 acolade, între care se află cursorul de editare, se execută la încărcarea ferestrei (Form1).


7. Se scrie doar un sigur rând de cod între cele 2 acolade, deoarece setările programului sunt încărcate automat la pornirea lui (nu e nevoie de o instrucțiune pentru asta): Size = Properties.Settings.Default.Form1Size;

8. Se comandă întoarcerea la designerul lui Form1 și se face la fel cum s-a făcut pentru „Load” dar pentru „FormClosing”, eveniment care se apelează când fereastra este în proces de închidere (există și evenimentul „FormClosed” care are altă semnificație):

9. Astfel se deschide editorul de cod într-o nouă metoda, „Form1_FormClosing”:

10. Se pun în ea 2 rânduri de cod:

Properties.Settings.Default.Form1Size = Size;
Properties.Settings.Default.Save();

Primul rând setează proprietatea pentru sesiunea curenta și al doilea salvează setările (inclusiv cele setate altundeva) pe disc pentru viitoarele porniri ale programului.

Fișierul Form1.cs arată astfel:

Observații

1. Programul nu ține cont că fereastra poate primi dimensiune mare și prin maximizare. Pentru a ține cont de maximizare, se folosesc fie proprietatea MaximizeBox pentru a împiedica maximizarea ferestrei, fie evenimentul SizeChanged împreună cu proprietatea WindowState pentru a monitoriza când se schimba dimensiunea și starea de maximizată a ferestrei în același moment (în același grup de evenimente de la SO mânuite în aceleași momente).

2. Odată ce setarea Form1Size de tip Size a fost creată în designerul fișierului Settings.settings din secțiunea Properties a proiectului pe care l-am numit „cs-remember-form-size” și fișierul Settings.settings a fost salvat, valoarea setării Form1Size nu mai poate fi schimbată decât prin codul programului. Chiar dacă dăm comanda Build > Clean solution și apoi recompilăm programul în aceeași configurație de construcție ca la început (de ex., Debug sau Release), valoarea din designerul Settings.settings nu mai ajunge să fie folosită de program decât la operațiunea Publish din meniul contextual al proiectului. Odată publicat cu Publish, valoarea setării rămâne ca la prima instalare a programului din dosarul de publicare (implicit dosarul acesta este „publish” din directorul proiectului) până la folosirea programului pt. redimensionarea ferestrei, sau până la dezinstalare și reinstalare (uneori și opțiunea din programul de dezinstalare numită „Restore the application to its previous state” funcționează).

3. Pagina cu setările programului se poate deschide și făcând clic-dreapta pe „cs-remember-form-size” (numele proiectului creat) în Solution Explorer (Ctrl-W, S) și selectând Properties (Alt-Enter) din meniul contextual apărut, și în noul tab deschis se selectează în bara de navigare din stânga pagina „Settings”.

4. Documentația oficială legată de pagina de Setări din Visual Studio este aici (EN).

5. Într-un program serios, e nevoie de câte 1-2 setări asemănătoare celei descrise în acest articol pentru fiecare fereastră a programului, una pentru dimensiunea ferestrei (dacă fereastra este redimensionabilă), și cealaltă pentru poziția ferestrei pe ecran.