Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > pl.comp.programming > #28514 > unrolled thread
| Started by | Borneq <borneq@antyspam.hidden.pl> |
|---|---|
| First post | 2016-04-22 00:22 +0200 |
| Last post | 2016-04-23 01:54 +0200 |
| Articles | 7 — 3 participants |
Back to article view | Back to pl.comp.programming
Szybki algorytm na permutację Borneq <borneq@antyspam.hidden.pl> - 2016-04-22 00:22 +0200
Re: Szybki algorytm na permutację "M.M." <mmarszik@gmail.com> - 2016-04-22 09:43 -0700
Re: Szybki algorytm na permutację bartekltg <bartekltg@gmail.com> - 2016-04-23 01:47 +0200
Re: Szybki algorytm na permutację "M.M." <mmarszik@gmail.com> - 2016-04-23 02:38 -0700
Re: Szybki algorytm na permutację bartekltg <bartekltg@gmail.com> - 2016-04-23 11:47 +0200
Re: Szybki algorytm na permutację "M.M." <mmarszik@gmail.com> - 2016-04-23 03:10 -0700
Re: Szybki algorytm na permutację bartekltg <bartekltg@gmail.com> - 2016-04-23 01:54 +0200
| From | Borneq <borneq@antyspam.hidden.pl> |
|---|---|
| Date | 2016-04-22 00:22 +0200 |
| Subject | Szybki algorytm na permutację |
| Message-ID | <nfbjra$fer$1@node2.news.atman.pl> |
z wykorzystaniem random() Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i drugą, początkowo wielkości 0. Z posortowanych wybieram za pomocą random(n) któryś element, i najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam element ostatni. Potem wybieram za pomocą random(n-1) wkładam w dziurę. I tak dalej
[toc] | [next] | [standalone]
| From | "M.M." <mmarszik@gmail.com> |
|---|---|
| Date | 2016-04-22 09:43 -0700 |
| Message-ID | <50b1e418-8178-4dbe-924c-735ceda5e398@googlegroups.com> |
| In reply to | #28514 |
On Friday, April 22, 2016 at 12:22:35 AM UTC+2, Borneq wrote: > z wykorzystaniem random() > Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i > drugą, początkowo wielkości 0. > Z posortowanych wybieram za pomocą random(n) któryś element, i > najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam > element ostatni. > Potem wybieram za pomocą random(n-1) wkładam w dziurę. > I tak dalej Może tak? for( int i=1 ; i<=N ; i++ ) tab[i] = i; for( int i=0 ; i<N*2 ; i++ ) swp( tab[rand()%N] , tab[rand()%N] );
[toc] | [prev] | [next] | [standalone]
| From | bartekltg <bartekltg@gmail.com> |
|---|---|
| Date | 2016-04-23 01:47 +0200 |
| Message-ID | <nfed5s$4oo$1@node2.news.atman.pl> |
| In reply to | #28517 |
On 22.04.2016 18:43, M.M. wrote: > On Friday, April 22, 2016 at 12:22:35 AM UTC+2, Borneq wrote: >> z wykorzystaniem random() >> Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i >> drugą, początkowo wielkości 0. >> Z posortowanych wybieram za pomocą random(n) któryś element, i >> najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam >> element ostatni. >> Potem wybieram za pomocą random(n-1) wkładam w dziurę. >> I tak dalej > > Może tak? > for( int i=1 ; i<=N ; i++ ) > tab[i] = i; > for( int i=0 ; i<N*2 ; i++ ) > swp( tab[rand()%N] , tab[rand()%N] ); Bardzo źle. Wynonujesz 4N losowań. Czy rozkład wyniku jest równomierny, wcale bym się nie zakładał. pzdr bartekltg
[toc] | [prev] | [next] | [standalone]
| From | "M.M." <mmarszik@gmail.com> |
|---|---|
| Date | 2016-04-23 02:38 -0700 |
| Message-ID | <dd2bde62-021b-4413-8613-026730ce10e3@googlegroups.com> |
| In reply to | #28519 |
On Saturday, April 23, 2016 at 1:47:09 AM UTC+2, bartekltg wrote:
> On 22.04.2016 18:43, M.M. wrote:
> > On Friday, April 22, 2016 at 12:22:35 AM UTC+2, Borneq wrote:
> >> z wykorzystaniem random()
> >> Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i
> >> drugą, początkowo wielkości 0.
> >> Z posortowanych wybieram za pomocą random(n) któryś element, i
> >> najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam
> >> element ostatni.
> >> Potem wybieram za pomocą random(n-1) wkładam w dziurę.
> >> I tak dalej
>
> >
> > Może tak?
> > for( int i=1 ; i<=N ; i++ )
> > tab[i] = i;
> > for( int i=0 ; i<N*2 ; i++ )
> > swp( tab[rand()%N] , tab[rand()%N] );
>
> Bardzo źle.
> Wynonujesz 4N losowań.
> Czy rozkład wyniku jest równomierny, wcale bym się nie zakładał.
>
> pzdr
> bartekltg
Nie wiem, też bym się nie założył, ale na pewno Knuth shuffle dał
mniejsze odchylenie standardowe w kilku testach:
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <QHash>
#include <QString>
#include <cmath>
#define N (10000000)
#define M (5)
static void swp( int &a , int &b ) {
const int x = a;
a = b;
b = x;
}
static QHash<QString,int> test1() {
QHash<QString,int> hash;
for( int i=0 ; i<N ; i++ ) {
int tab[M];
for( int j=0 ; j<M ; j++ )
tab[j] = j;
for( int j=0 ; j<M*2 ; j++ )
swp( tab[rand()%M] , tab[rand()%M] );
QString p;
for( int j=0 ; j<M ; j++ )
p.append( QString::number(tab[j]) );
if( hash.contains(p) )
hash[p]++;
else
hash.insert(p,1);
}
return hash;
}
static QHash<QString,int> test2() {
QHash<QString,int> hash;
for( int i=0 ; i<N ; i++ ) {
int tab[M];
for( int j=0 ; j<M ; j++ )
tab[j] = j;
for( int j=0 ; j<M-1 ; j++ )
swp( tab[j] , tab[ j + rand()%(M-j) ] );
QString p;
for( int j=0 ; j<M ; j++ )
p.append( QString::number(tab[j]) );
if( hash.contains(p) )
hash[p]++;
else
hash.insert(p,1);
}
return hash;
}
static void stat( const QHash<QString,int> &hash ) {
double sum=0, sum2=0, avg, cnt=0, min=1, max=0;
for( QHash<QString,int>::const_iterator i=hash.begin() ; i!=hash.end() ; ++i ) {
const double tmp = (double) i.value() / N;
sum += tmp;
cnt ++ ;
if( min > tmp ) min = tmp;
if( max < tmp ) max = tmp;
}
avg = sum / cnt;
for( QHash<QString,int>::const_iterator i=hash.begin() ; i!=hash.end() ; ++i ) {
const double tmp = (double) i.value() / N;
sum2 += (tmp-avg) * (tmp-avg);
}
printf("cnt=%.0lf sum=%lf min=%lf max=%lf avg=%lf std=%lf\n" , cnt , sum , min , max , avg , sqrt( sum2 / cnt ) );
fflush(stdout);
}
int main(int argc, char *argv[])
{
const uint seed = (uint)time(NULL);
printf("seed = %u\n",seed);
srand( seed );
{
const QHash<QString,int> hash = test1();
stat(hash);
}
srand( seed );
{
const QHash<QString,int> hash = test2();
stat(hash);
}
return 0;
}
seed = 1461404107
cnt=120 sum=1.000000 min=0.008029 max=0.009185 avg=0.008333 std=0.000209
cnt=120 sum=1.000000 min=0.008270 max=0.008425 avg=0.008333 std=0.000029
[toc] | [prev] | [next] | [standalone]
| From | bartekltg <bartekltg@gmail.com> |
|---|---|
| Date | 2016-04-23 11:47 +0200 |
| Message-ID | <nffgc0$foj$1@node1.news.atman.pl> |
| In reply to | #28521 |
On 23.04.2016 11:38, M.M. wrote: > On Saturday, April 23, 2016 at 1:47:09 AM UTC+2, bartekltg wrote: >> >On 22.04.2016 18:43, M.M. wrote: >>> > >On Friday, April 22, 2016 at 12:22:35 AM UTC+2, Borneq wrote: >>>> > >>z wykorzystaniem random() >>>> > >>Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i >>>> > >>drugą, początkowo wielkości 0. >>>> > >>Z posortowanych wybieram za pomocą random(n) któryś element, i >>>> > >>najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam >>>> > >>element ostatni. >>>> > >>Potem wybieram za pomocą random(n-1) wkładam w dziurę. >>>> > >>I tak dalej >> > >>> > > >>> > >Może tak? >>> > >for( int i=1 ; i<=N ; i++ ) >>> > > tab[i] = i; >>> > >for( int i=0 ; i<N*2 ; i++ ) >>> > > swp( tab[rand()%N] , tab[rand()%N] ); >> > >> >Bardzo źle. >> >Wynonujesz 4N losowań. >> >Czy rozkład wyniku jest równomierny, wcale bym się nie zakładał. >> > >> >pzdr >> >bartekltg > Nie wiem, też bym się nie założył, ale na pewno Knuth shuffle dał > mniejsze odchylenie standardowe w kilku testach: Knutha możęsz policzyć. Bardzo prosto. Wymyśl dowolną permutację i licz prawdopodobieństwo, że ją wylosujesz. W każdym kroku musisz wybrać właściwa liczbę i nie ma potem możliwośći popsucia. 1 liczba z n, 1 liczba z n-1.... Łącznie prawdopodobieństwo 1/n! Identyczne dla dowolnej permutacji. BTW, dlaczego wołasz srand( seed ); dwa razy? pzdr bartekltg
[toc] | [prev] | [next] | [standalone]
| From | "M.M." <mmarszik@gmail.com> |
|---|---|
| Date | 2016-04-23 03:10 -0700 |
| Message-ID | <22e93328-8aee-4c82-9764-f3f736b3aeb0@googlegroups.com> |
| In reply to | #28522 |
On Saturday, April 23, 2016 at 11:47:45 AM UTC+2, bartekltg wrote: > On 23.04.2016 11:38, M.M. wrote: > > On Saturday, April 23, 2016 at 1:47:09 AM UTC+2, bartekltg wrote: > >> >On 22.04.2016 18:43, M.M. wrote: > >>> > >On Friday, April 22, 2016 at 12:22:35 AM UTC+2, Borneq wrote: > >>>> > >>z wykorzystaniem random() > >>>> > >>Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i > >>>> > >>drugą, początkowo wielkości 0. > >>>> > >>Z posortowanych wybieram za pomocą random(n) któryś element, i > >>>> > >>najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam > >>>> > >>element ostatni. > >>>> > >>Potem wybieram za pomocą random(n-1) wkładam w dziurę. > >>>> > >>I tak dalej > >> > > >>> > > > >>> > >Może tak? > >>> > >for( int i=1 ; i<=N ; i++ ) > >>> > > tab[i] = i; > >>> > >for( int i=0 ; i<N*2 ; i++ ) > >>> > > swp( tab[rand()%N] , tab[rand()%N] ); > >> > > >> >Bardzo źle. > >> >Wynonujesz 4N losowań. > >> >Czy rozkład wyniku jest równomierny, wcale bym się nie zakładał. > >> > > >> >pzdr > >> >bartekltg > > Nie wiem, też bym się nie założył, ale na pewno Knuth shuffle dał > > mniejsze odchylenie standardowe w kilku testach: > > > Knutha możęsz policzyć. Bardzo prosto. Wymyśl dowolną > permutację i licz prawdopodobieństwo, że ją wylosujesz. > W każdym kroku musisz wybrać właściwa liczbę i nie ma potem > możliwośći popsucia. 1 liczba z n, 1 liczba z n-1.... > Łącznie prawdopodobieństwo 1/n! Identyczne dla dowolnej permutacji. Tak, zaletą knutha jest to, że można łatwo przeprowadzić dowód. > BTW, dlaczego wołasz srand( seed ); dwa razy? Chyba z rozpędu, zazwyczaj trzeba zadbać o to, aby obie metody dostały ten sam losowy ciąg, ale tutaj jest inna ilość losowań, więc nic to nie daje. Pozdrawiam
[toc] | [prev] | [next] | [standalone]
| From | bartekltg <bartekltg@gmail.com> |
|---|---|
| Date | 2016-04-23 01:54 +0200 |
| Message-ID | <nfedka$e74$1@node1.news.atman.pl> |
| In reply to | #28514 |
On 22.04.2016 00:22, Borneq wrote:
> z wykorzystaniem random()
> Przychodzi mi do głowy jeden pomysł: tablicę posortowanych wielkości n i
> drugą, początkowo wielkości 0.
> Z posortowanych wybieram za pomocą random(n) któryś element, i
> najważniejsze: w dziurę (dziura - element o indeksie random(n)) wkładam
> element ostatni.
> Potem wybieram za pomocą random(n-1) wkładam w dziurę.
> I tak dalej
Prawie idealnie. Z tym, ze nie potrzebujesz wcale osobnej tablicy,
Masz jedną tablicę, idziesz po niej plętlą
Wszytko co przed indeksem i traktujesz jak swoją drugą tablicę
(tam są losowo zmieszane) a tablice od i (włącznie) w górę
traktujesz jak swoją pierwszą tablicę (źródło nieuzytych liczb).
I robisz tak samo, czyli losujesz z niej jeden element, zamiast
jednak przesyłąć go do innej tablicy i zatykać największym,
przestawiasz go w miejsce i, a dzirę zatykasz tym, co było na miejscu i.
To tzw, "Knuth shuffle".
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
-- To shuffle an array a of n elements (indices 0..n-1):
for i from 0 to n−2 do
j ← random integer such that 0 ≤ j < n-i
exchange a[i] and a[i+j]
Wydawało mi się, że jest powszechnie znany. Niczym qsort.
To on siedzie (być mozę w wersji 'od tyłu') w std::random_shuffle.
pzdr
bartekltg
[toc] | [prev] | [standalone]
Back to top | Article view | pl.comp.programming
csiph-web