Wartości losowe w tablicach
Generator liczb losowych w języku C# zdefiniowany jest w bibliotece System.Runtime.dll. Klasa Random reprezentuje generator liczb pseudolosowych oparty na algorytmie tworzącym sekwencję liczb spełniających określone wymagania statystyczne związane z losowością.
Deklaracja generatora liczb losowych
W zależności od potrzeb programu generator może być zadeklarowany jako dostępny w całej klasie, wtedy zmienna reprezentująca generator inicjowana jest jak poniżej
Wskazówka:
public partial class Form1 : Form
{
int ileLosowan;
//generator dostępny dla całej klasy Form1
Random los = new Random();
const int rozmiar = 10;
W sytuacjach gdy generator będzie używany lokalnie w jednej funkcji, wtedy zmienną reprezentującą generator inicjujemy jak poniżej
Wskazówka:
private void button1_Click(object sender, EventArgs e)
{
//var- słowo kluczowe deklarujące zmienną lokalną
var los = new Random();
int p = int.Parse(textBox2.Text);
int q = int.Parse(textBox3.Text);
Przykłady wywołania generatora
Najprościej wartość losową uzyskuje się po wykonaniu tej instrukcji
Wskazówka:
Random los = new Random();
int i = los.Next();
Generowanie liczb losowych można ograniczyć do rożnych przedziałów losowanych wartości. Ograniczenie nie gwarantuje losowania bez powtórzeń.
Przykładowe sposoby definiowania przedziałów wartości losowych
Losowanie liczb całkowitych z przedziału p<=x<=q
Wskazówka:
//losowanie z przedziału <p,q>, p<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
int x=p+los.Next()%(q- p+1);
textBox1.AppendText(x+Environment.NewLine);
}
Losowanie liczb całkowitych z przedziału p<x<=q
Wskazówka:
//losowanie z przedziału (p,q>, p<x<=q
for (int i = 0; i < ileLosowan; i++)
{
int x = los.Next(p, q)+1;
textBox1.AppendText(x + Environment.NewLine);
}
Losowanie liczb całkowitych z przedziału 0<=x<=q
Wskazówka:
//losowanie z przedziału <0,q>, 0<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
int x = los.Next()%(q+1);
textBox1.AppendText(x + Environment.NewLine);
}
Losowanie liczb rzeczywistych z przedziału p<=x<=q
Wskazówka:
//losowanie liczb rzeczywistych z przedziału <p,q>, p<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
double x =p+(double)los.Next()/Int32.MaxValue*(q -p);
textBox1.AppendText(x + Environment.NewLine);
}
Losowanie liczb rzeczywistych z przedziału 0<=x<=1
Wskazówka:
//losowanie liczb rzeczywistych z przedziału <0,1>, 0<=x<=1
for (int i = 0; i < ileLosowan; i++)
{
double x = (double)los.Next() / Int32.MaxValue;
textBox1.AppendText(x + Environment.NewLine);
}
Losowanie liczb rzeczywistych z przedziału 0<=x<=q
Wskazówka:
//losowanie liczb rzeczywistych z przedziału <0,q>, 0<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
double x = (double)los.Next() / Int32.MaxValue*q;
textBox1.AppendText(x + Environment.NewLine);
}
Zad. 1
Zaprojektuj aplikację desktopową, która umożliwi generowanie liczb z wyżej wymienionych przykładów przedziałów losowych wartości.
Poniżej przykładowy zrzut działającej aplikacji.
Wypełnianie tablic losowymi wartościami bez powtórzeń
Losowanie bez powtórzeń wartości przypisywanych do tablic wymaga kontrolowania wylosowanej wartości czy już nie wystąpiła. Jeżeli wystąpiła to losowanie należy powtarzać dopóki nie zostanie wylosowana nowa niepowtarzająca się wartość.
Kontrolowanie niepowtarzalności jest wąskim gardłem tej metody. Kontrolowanie należy wykonywać od zerowego indeksu tablicy do indeksu granicznego z ostatnim wpisanym losowym elementem.
Przykładowy kod funkcji sprawdzającej czy wartość była już wylosowana
Wskazówka:
bool bylaWylosowana(int liczba, int[] t, int granica)
{
for (int i = 0; i < granica; i++)
if (t[i] == liczba)
return true;//była wylosowana
//nie była wylosowana
return false;
}
Proces losowania należy powtarzać do momentu wypełnienia całej tablicy. Poniżej przykład funkcji losującej i jednocześnie pokazującej wylosowaną wartość w kontrolce TextBox pracującej w układzie wielu linii.
Wskazówka:
void LosujDoTablicy()
{
textBox1.Clear();
//var- słowo kluczowe deklarujące zmienną lokalną
var los = new Random();
int p = int.Parse(textBox2.Text);
//górna granica powinna gawarantować co najmniej
//ilość liczb niepowtarzających się
int q = p+rozmiar-1;
int licznikLosowan = 0;
while (licznikLosowan < rozmiar)
{
//losowanie z przedziału <p,q>, p<=x<=q
int x = p + los.Next() % (q - p + 1);
if (!bylaWylosowana(x, tab, licznikLosowan))
{
tab[licznikLosowan] = x;
//pokaz wylosowana tablicę
textBox1.AppendText(tab[licznikLosowan] +
Environment.NewLine);
licznikLosowan++;
}
}
}
Zad. 2
Zaprojektuj aplikacje desktopową, która wypełni tablicę 20- elementową wartościami z przedziału od 1 do 20.
Losowanie elementów tablicy bez powtórzeń
Mając dowolna tablicę, o której wiemy że jest wypełniona wartościami niepowtarzającymi się, można wykonać losowanie bez powtórzeń tych wartości odpowiednio losując indeksy ze zmianą zakresu losowania indeksów. Takie rozwiązanie nie wymaga sprawdzania czy już ten indeks nie został wylosowany. Należy zamienić miejscami ostatni element z wylosowanym elementem i zmniejszyć po zamianie zakres losowania o jeden.
Poniższa ilustracja pokazuje jak zmieniała się tablica po każdorazowym losowaniu bez powtórzeń.
Poniżej przykładowy kod funkcji losującej bez powtórzeń elementy tablicy
Wskazówka:
void LosujElementTablicyBezPowtorzen(int[] t)
{
var los = new Random();
int id = los.Next(0, rozmiar - nrLosowania);
textBox1.AppendText("wylosowano :" + t[id] + Environment.NewLine);
//zamien indeksami
int bufor = t[id];
//podmień miejscami ostatnią z zakresu z wylosowaną
t[id] = t[rozmiar - 1 - nrLosowania];
t[rozmiar - 1 - nrLosowania] = bufor;
nrLosowania++;
label4.Text = "Losowanie " +
nrLosowania +
" z " + rozmiar +
Environment.NewLine;
}
Zad. 3
Rozszerz działanie aplikacji desktopowej z zadania numer 2 o funkcje losującą bez powtórzeń elementy tablicy. Wylosowane elementy po każdym losowaniu pokaz na ekranie.
Pełny kod aplikacji przedstawionej w temacie
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wartosci_losowe_w_tablicach
{
public partial class Form1 : Form
{
int ileLosowan;
const int rozmiar = 10;
int[] tab = new int[rozmiar];
int nrLosowania = 0;
public Form1()
{
InitializeComponent();
label4.Text = "Losowanie "+
nrLosowania +
" z " + rozmiar;
}
private void button1_Click(object sender, EventArgs e)
{
//var- słowo kluczowe deklarujące zmienną lokalną
var los = new Random();
int p = int.Parse(textBox2.Text);
int q = int.Parse(textBox3.Text);
ileLosowan = int.Parse(textBox4.Text);
textBox1.Clear();
textBox1.AppendText("liczby całkowite z przedziału <p,q>, p<=x<=q" + Environment.NewLine);
//losowanie z przedziału <p,q>, p<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
int x=p+los.Next()%(q- p+1);
textBox1.AppendText(x+Environment.NewLine);
}
textBox1.AppendText("liczby całkowite z przedziału (p,q>, p<x<=q" + Environment.NewLine);
//losowanie z przedziału (p,q>, p<x<=q
for (int i = 0; i < ileLosowan; i++)
{
int x = los.Next(p, q)+1;
textBox1.AppendText(x + Environment.NewLine);
}
textBox1.AppendText("liczby całkowite z przedziału <0,q>, 0<=x<=q" + Environment.NewLine);
//losowanie z przedziału <0,q>, 0<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
int x = los.Next()%(q+1);
textBox1.AppendText(x + Environment.NewLine);
}
textBox1.AppendText("liczby rzeczywiste z przedziału <p,q>, p<=x<=q" + Environment.NewLine);
//losowanie liczb rzeczywistych z przedziału <p,q>, p<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
double x =p+(double)los.Next()/Int32.MaxValue*(q -p);
textBox1.AppendText(x + Environment.NewLine);
}
textBox1.AppendText("liczby rzeczywiste z przedziału <0,1>, 0<=x<=1" + Environment.NewLine);
//losowanie liczb rzeczywistych z przedziału <0,1>, 0<=x<=1
for (int i = 0; i < ileLosowan; i++)
{
double x = (double)los.Next() / Int32.MaxValue;
textBox1.AppendText(x + Environment.NewLine);
}
textBox1.AppendText("liczby rzeczywiste z przedziału <0,q>, 0<=x<=q" + Environment.NewLine);
//losowanie liczb rzeczywistych z przedziału <0,q>, 0<=x<=q
for (int i = 0; i < ileLosowan; i++)
{
double x = (double)los.Next() / Int32.MaxValue*q;
textBox1.AppendText(x + Environment.NewLine);
}
}
bool bylaWylosowana(int liczba, int[] t, int granica)
{
for (int i = 0; i < granica; i++)
if (t[i] == liczba)
return true;//była wylosowana
//nie była wylosowana
return false;
}
void LosujDoTablicy()
{
textBox1.Clear();
//var- słowo kluczowe deklarujące zmienną lokalną
var los = new Random();
int p = int.Parse(textBox2.Text);
//górna granica powinna gawarantować co najmniej
//ilość liczb niepowtarzających się
int q = p+rozmiar-1;
int licznikLosowan = 0;
while (licznikLosowan < rozmiar)
{
//losowanie z przedziału <p,q>, p<=x<=q
int x = p + los.Next() % (q - p + 1);
if (!bylaWylosowana(x, tab, licznikLosowan))
{
tab[licznikLosowan] = x;
//pokaz wylosowana tablicę
textBox1.AppendText(tab[licznikLosowan] + Environment.NewLine);
licznikLosowan++;
}
}
}
private void button2_Click(object sender, EventArgs e)
{
LosujDoTablicy();
button3.Enabled = true;
nrLosowania = 0;
label4.Text = "Losowanie " +
nrLosowania +
" z " + rozmiar;
}
void LosujElementTablicyBezPowtorzen(int[] t)
{
var los = new Random();
int id = los.Next(0, rozmiar - nrLosowania);
textBox1.AppendText("wylosowano :" + t[id] + Environment.NewLine);
//zamien indeksami
int bufor = t[id];
//podmień miejscami ostatnią z zakresu z wylosowaną
t[id] = t[rozmiar - 1 - nrLosowania];
t[rozmiar - 1 - nrLosowania] = bufor;
nrLosowania++;
label4.Text = "Losowanie " +
nrLosowania +
" z " + rozmiar +
Environment.NewLine;
}
private void button3_Click(object sender, EventArgs e)
{
if (nrLosowania == rozmiar) return;
//pokaz tablicę przed losowaniem
textBox1.AppendText("Tablica przed losowaniem :" +
Environment.NewLine);
for (int i = 0; i < tab.Length; i++)
textBox1.AppendText(tab[i] + "; ");
LosujElementTablicyBezPowtorzen(tab);
//pokaz tablicę po losowaniu
textBox1.AppendText("Tablica po losowaniu :" +
Environment.NewLine);
for (int i = 0; i < tab.Length; i++)
textBox1.AppendText(tab[i] + "; ");
textBox1.AppendText(Environment.NewLine);
}
}
}