function Search-Sequential([array]$arr, $item, [switch]$firstfound) { $found=@() for($i=0; $i -lt $arr.Length; $i++) { if($arr[$i].Equals($item) ) { $found+=$i if($firstfound) { return $found } } } return $found }Użycie funkcji jest intuicyjne:
$arr = 1,2,3,4,4,4,4,4,5,5,5,6,6,7,8,99,120 Search-Sequential -arr $arr -item 5 #8,9,10Drugim ciekawym algorytmem przeszukiwania jest przeszukiwanie binarne:
function Search-Binare([array]$arr, $item, [switch]$firstfound) { $low =0 $high = $arr.Length -1 $found=@() While($low -le $high) { $middleIdx = [math]::Floor(($low + $high)/2) $middleValue = $arr[$middleIdx] if($middleValue -lt $item) { $low = $middleIdx+1 } elseif($middleValue -gt $item) { $high = $middleIdx -1 } else{ $found+=$middleIdx if(!$firstfound) { $leftNeighborMiddleIdx = $middleIdx-1 if($low -le $leftNeighborMiddleIdx) { $leftArr = $arr[$low..$leftNeighborMiddleIdx] $foundOnLeftWithOffset = Search-Binare -arr $leftArr -item $item -firstfound:$firstfound $foundOnLeft = $foundOnLeftWithOffset | %{ $low + $_ } $found+=$foundOnLeft } $rightNeighborMiddleIdx = $middleIdx+1 if($rightNeighborMiddleIdx -le $high) { $rightArr = $arr[$rightNeighborMiddleIdx..$high] $foundOnRightWithOffset = Search-Binare -arr $rightArr -item $item -firstfound:$firstfound $foundOnRigh = $foundOnRightWithOffset | %{$rightNeighborMiddleIdx + $_} $found+=$foundOnRigh } } return $found } } }Niestety musiałem dodać wywołanie rekurencyjne, aby przeszukał sąsiednie elementy. Przeszukiwanie binarne dla tej samej tabeli zwraca te same elementy, ale w innej kolejności:
Search-Binare -arr $arr -item 5 #8,10,9Postanowiłem napisać jeszcze jeden alg. za pomocą tablicy haszującej. Na samym początku potrzebowalibyśmy funkcji do przekształcenia zwyczajnej tablicy na hashtable:
function ConvertTo-Hashtable( [array]$arr, [scriptblock]$hashFunction = $({param($x) return $x.GetHashCode()})) { [array]$hashTable = @(,$null) * 100 for($i=0; $i -lt $arr.Length; $i++) { $item = $arr[$i] $hashCode = $hashFunction.InvokeReturnAsIs($item) $diff = $hashCode - $hashTable.Length if($diff -ge 0) { $hashTable += @(,$null) * ($diff +1) } if(-not($hashTable[$hashCode])) { $hashTable[$hashCode] =@() } $hashTable[$hashCode] += $i } return $hashTable }Warto zauważyć tutaj jaka jest funkcja haszująca. Korzystamy z ogólnodostępnej funkcji GetHashCode.
Funkcja haszująca jest zapisana w script bloku. Konwersja i wyszukiwanie wygląda następująco:
$arr = 1,2,3,4,4,4,4,4,5,5,5,6,6,7,8,99,120 $hashtable = ConvertTo-Hashtable -arr $arr Search-Hashed -arr $hashtable -item 5 #8,9,10
Natomiast funkcja przeszukująca tablice haszującą ma 2 linijki implementacji:
function Search-Hashed ([array]$arr, $item, [scriptblock]$hashFunction= $({param($x) return $x.GetHashCode()})) { $hashCode = $hashFunction.InvokeReturnAsIs($item) return $arr[$hashCode] }Zamiast domyślnej funkcji haszującej można stworzyć swoją własną. Mój przykład dla znaków to:
$hashFunction = {param($x) [int][char]$x}A wywołanie wygląda następująco:
$arr = 'A','V','b','b','C' $hashtable = ConvertTo-Hashtable -arr $arr -hashFunction $hashFunction Search-Hashed -arr $hashtable -item 'b' -hashFunction $hashFunction #2,3Równie dobrze mogę zastosować własną funkcję haszującą string:
$hashFunctionString = {param($x) [int[]][char[]]$x-join ''} $hashFunctionString.InvokeReturnAsIs("Hello Arek ") #72101108111326511410110732Oczywiście nie mogę stworzyć tak wielkiej tablicy, ale może coś się wymyśli :)
Brak komentarzy:
Prześlij komentarz