ANALYSIS of ALGORITHMS, Bulletin Board

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Quickselect and inversions. (II)




Greetings.

I am sending a correction to the code contained in
  http://pauillac.inria.fr/algo/AofA/mailing_list/msg00432.html.

The quickselect implementation in the above message shifted the index
of the element being selected when there was no need to shift it. This 
resulted in some intermediate generating functions not being symmetric 
with respect to the location of the pivot.

Here are the correct generating functions.

0: 1
1 1
0/1
0: 2
1: 2
2 4
0/4
0: 5 + z
1: 6
2: 5 + z
3 16 + 2z
2/18
0: 15 + 6z + 2z^2 + z^3
1: 20 + 4z
2: 20 + 4z
3: 15 + 6z + 2z^2 + z^3
4 70 + 20z + 4z^2 + 2z^3
34/96
0: 52 + 33z + 15z^2 + 11z^3 + 5z^4 + 3z^5 + z^6
1: 75 + 30z + 10z^2 + 5z^3
2: 86 + 28z + 6z^2
3: 75 + 30z + 10z^2 + 5z^3
4: 52 + 33z + 15z^2 + 11z^3 + 5z^4 + 3z^5 + z^6
5 340 + 154z + 56z^2 + 32z^3 + 10z^4 + 6z^5 + 2z^6
444/600
0: 203 + 182z + 109z^2 + 81z^3 + 50z^4 + 40z^5 + 26z^6 + 15z^7 + 9z^8 + 4z^9 + z^10
1: 312 + 198z + 90z^2 + 66z^3 + 30z^4 + 18z^5 + 6z^6
2: 396 + 198z + 76z^2 + 40z^3 + 10z^4
3: 396 + 198z + 76z^2 + 40z^3 + 10z^4
4: 312 + 198z + 90z^2 + 66z^3 + 30z^4 + 18z^5 + 6z^6
5: 203 + 182z + 109z^2 + 81z^3 + 50z^4 + 40z^5 + 26z^6 + 15z^7 + 9z^8 + 4z^9 + z^10
6 1822 + 1156z + 550z^2 + 374z^3 + 180z^4 + 116z^5 + 64z^6 + 30z^7 + 18z^8 + 8z^9 + 2z^10
5508/4320
0: 877 + 1034z + 777z^2 + 631z^3 + 434z^4 + 351z^5 + 272z^6 + 206z^7 + 164z^8 + 118z^9 + 78z^10 + 49z^11 + 29z^12 + 14z^13 + 5z^14 + z^15
1: 1421 + 1274z + 763z^2 + 567z^3 + 350z^4 + 280z^5 + 182z^6 + 105z^7 + 63z^8 + 28z^9 + 7z^10
2: 1951 + 1402z + 712z^2 + 477z^3 + 255z^4 + 156z^5 + 72z^6 + 15z^7
3: 2162 + 1466z + 672z^2 + 430z^3 + 210z^4 + 80z^5 + 20z^6
4: 1951 + 1402z + 712z^2 + 477z^3 + 255z^4 + 156z^5 + 72z^6 + 15z^7
5: 1421 + 1274z + 763z^2 + 567z^3 + 350z^4 + 280z^5 + 182z^6 + 105z^7 + 63z^8 + 28z^9 + 7z^10
6: 877 + 1034z + 777z^2 + 631z^3 + 434z^4 + 351z^5 + 272z^6 + 206z^7 + 164z^8 + 118z^9 + 78z^10 + 49z^11 + 29z^12 + 14z^13 + 5z^14 + z^15
7 10660 + 8886z + 5176z^2 + 3780z^3 + 2288z^4 + 1654z^5 + 1072z^6 + 652z^7 + 454z^8 + 292z^9 + 170z^10 + 98z^11 + 58z^12 + 28z^13 + 10z^14 + 2z^15
69264/35280

Regards,

Marko Riedel

#! /usr/bin/perl -w
#

sub fact {
  my ($n) = @_;

  return 1 if $n==0 or $n==1;

  my ($p) = (1);
  $p*=$n-- while $n>1;

  return $p;
}

sub qsel {
  my ($perm, $lower, $upper, $index) = @_;
  my ($temp);

  return if $lower==$upper;

  if($lower+1==$upper){
    $temp=$perm->[$lower];

    if($temp>$perm->[$upper]){
      $perm->[$lower]=$perm->[$upper];
      $perm->[$upper]=$temp;
    }

    return;
  }

  my ($pivot, $i, $j) = 
    ($perm->[$lower], $lower+1, $upper);
  while($i<=$j){
    while($i<=$j && $perm->[$i]<$pivot){
      $perm->[$i-1]=$perm->[$i];
      $i++;
    }
    while($j>=$i && $perm->[$j]>$pivot){
      $j--;
    }
    
    if($i<$j){
      $temp=$perm->[$i];
      $perm->[$i]=$perm->[$j];
      $perm->[$j]=$temp;
    }
  }
  $perm->[$i-1]=$pivot;

  qsel($perm, $lower, $i-2, $index) 
    if $i-2>$lower && $index<=$i-2;
  qsel($perm, $i, $upper, $index) 
    if $i<$upper && $index>=$i;
}

sub nextperm {
  my ($n, $i, $j) = @_;
  my (@crep, $rem, @source, @perm, $item);
 
  for($j=1; $j<=$n; $j++){
    $rem=$i%$j;
    unshift @crep, $rem;
    $i=($i-$rem)/$j;
  }

  @source=(0..$n-1);
  for($j=0; $j<$n; $j++){
    $item=splice @source, $crep[$j], 1;
    push @perm, $item;
  }

  return \@perm;
}

sub inversions {
  my ($perm) = @_;
  my ($n, $count, $i, $j) = (scalar @$perm, 0);

  for($i=0; $i<$n; $i++){
    for($j=$i+1; $j<$n; $j++){
      $count++ if $perm->[$i]>$perm->[$j];
    }
  }

  return $count;
}

sub gfadd {
  my ($g1, $g2) = @_;
  my ($g, $sum, $i) = 
    ([($g1->[0]<$g2->[0] ?
       $g1->[0] : $g2->[0]),
      ($g1->[1]>$g2->[1] ?
       $g1->[1] : $g2->[1]),
      []]);

  for($i=$g->[0]; $i<=$g->[1]; $i++){
    $sum=0;
    $sum+=$g1->[2][$i] if defined $g1->[2][$i];
    $sum+=$g2->[2][$i] if defined $g2->[2][$i];

    $g->[2][$i]=$sum if $sum!=0;
  }

  return $g;
}

sub gf2string {
  my ($poly, @str, $term) = @_;

  foreach my $i ($poly->[0] .. $poly->[1]){
    if(defined $poly->[2][$i]){
      $term=($i == 0 ? '' : ($i == 1 ? 'z' : "z^$i"));
      push @str, 
      ($poly->[2][$i] == 1 ? 
       ($i==0 ? '1' : '') : "$poly->[2][$i]") .	$term;
    } 
  }

  return join ' + ', @str;
}

sub gfat1 {
  my ($poly, $total, $total1) = (@_, 0, 0);

  foreach my $i ($poly->[0] .. $poly->[1]){
    if(defined $poly->[2][$i]){
      $total  += $poly->[2][$i];
      $total1 += $i * $poly->[2][$i];
    }
  }

  return [$total1, $total];
}



MAIN: {
  my ($max, $n) = @ARGV;

  die "$0 <n>\n" if not defined $max;

  for($n=1; $n<=$max; $n++){
    my ($gf, $tgf, $i, $j, $perm, $invs) =
      ([undef, undef, []]);
    for($j=0; $j<$n; $j++){
      $tgf=[undef, undef, []];
      for($i=0; $i<fact($n); $i++){
	$perm=nextperm($n, $i);
	qsel($perm, 0, $n-1, $j);
	$invs=inversions($perm);
	
	$tgf->[0]=$invs 
	  if not defined $tgf->[0] or $tgf->[0]>$invs;
	$tgf->[1]=$invs 
	  if not defined $tgf->[1] or $tgf->[1]<$invs;
	$tgf->[2][$invs]=0 
	  if not defined $tgf->[2][$invs];
	$tgf->[2][$invs]++;
      }

      print "$j: " . gf2string($tgf) . "\n";
      $gf=($j>0 ? gfadd($gf, $tgf) : $tgf);
    }
    
    print "$n " . gf2string($gf) . "\n";
    my ($at1) = gfat1($gf);
    print "$at1->[0]/$at1->[1]\n";
  }
}

Date Prev | Date Next | Date Index | Thread Index