piątek, 7 marca 2014

MergeSort i Assert w PowerShell

Chciałem napisać prostą asercje i poćwiczyć sortowanie, więc napisałem script, z którym podzielę się z tobą :)
Na samym początku będziemy potrzebować funkcje, która będzie łączyła lewą i prawą stronę tablicy. Te części są posortowane.
function Merge
{
    param([array]$A,
    [array]$temp=@(),
    [int]$low=0,
    [int]$high=$($A.Length-1),

    [int]$middle = 
$([math]::Floor($low + ($high - $low)/2))
    )
    
    $i = $low
    $j = $middle +1
    
    Assert-Command {IsSorted ($A[$i..$middle]) }
    Assert-Command {IsSorted ($A[$j..$high]) }

    $temp = $A
    $swapA = @(0)* $A.Length
    for($k = $low; $k -le $high; $k++)
    {
        if( $i -gt $middle)
        {
            $swapA[$k] = $temp[$j]
            $j++        
        }
        elseif ($j -gt $high)
        {
            $swapA[$k] = $temp[$i]
            $i++
        }
        elseif( $temp[$j] -gt $temp[$i] )
        {
            $swapA[$k] = $temp[$i]
            $i++
        }
        else
        {
            $swapA[$k] = $temp[$j]
            $j++
        }
    }
    $sortedA =$swapA[$low..$high]

    Assert-Command {IsSorted $sortedA}
    return $sortedA
}
Napiszemy prostą funkcję do sprawdzenia czy elementy są posortowane:
function IsSorted([array]$arr)
{

    for($i=0; $i -lt $arr.Length-1; $i++)
    {
        if($arr[$i] -gt $arr[$i+1])
        {
            return $false
        }
    }
    return $true
}

Do funkcji scalania potrzebna jest funkcja asercji:
function Assert-Command
{
    param(
    [Parameter(Position=0,Mandatory=$true)]
    [ScriptBlock]$condition,

    [Parameter(Position=1)]
    [string]$message
    )
    $invoke = $MyInvocation

    try{
        $ErrorActionPreference = "STOP"
        $result = &$condition
    }catch{
        $result=$false
        $exceptionType = $_.Exception.GetType().FullName
    }


    if(-not($result))
    {
        $errMess = "Assert failed in line: $($invoke.Line) `n"
        $errMess += "Message: $message `n"
        $errMess += "Exception type: $exceptionType `n"
        $errMess += "Used parameters: $($invoke.BoundParameters.condition) `n"
        throw $errMess
    }
}
I na końcu potrzebujemy funkcji sortując:
function MergeSort-Object
{
    param([array]$A,
    [array]$temp=@(),
    [int]$low=0,
    [int]$high=$($A.Length-1),

    [int]$middle = $([math]::Floor($low + ($high - $low)/2))
    )
    
    if($low -ge $high)
    {
        return $A[$low]
    }

    [array]$sortedPart1 = MergeSort-Object -A $A -low $low -high $middle
    $A = Fill-Array -table $A -with $sortedPart1 -offSet $low

    [array]$sortedPart2  = MergeSort-Object -A $A -low ($middle+1) -high $high
    $A = Fill-Array -table $A -with $sortedPart2 -offSet ($middle+1)

    [array]$sorted = Merge -A $A -low $low -middle $middle -high $high
    return $sorted 
}
Niestety będziemy musieli użyć pomocniczej funkcji do wypełnienia tablicy już posortowanej części. Są to uroki przekazywania parametrów funkcji przez wartość, a nie przez referencje.
function Fill-Array
{
    param([array]$table,
    [int]$offSet=0,
    [array]$with
    )

    [array]$newTable = $table
    
    for($i =0; $i -lt $with.Length; $i++)
    {
        
        $newTable[$offSet + $i] = $with[$i]
    }
    return $newTable
}
I przykładowe sortowanie tablicy wygląda następująco:
 MergeSort-Object -A 1,3,7,99,5,3,32,5,11,91 

Brak komentarzy:

Prześlij komentarz