Write a bash script to do a binary search. Read student names and grades from a file into an array. Prompt the user for a student name. Find the name in the array and display the grade. The data in the file is below:
Ann:A
Bob:C
Cindy:B
Dean:F
Emily:A
Frank:C
Ginger:D
Hal:B
Ivy:A
Justin:F
Karen:D
I have done the following but I am stuck on what to do next
#!/bin/bash
echo "please enter students Name: "
read student
echo "$student + $Grade"
((i=0))
while read students[$i] ; do
((i++))
done < students.dat
first=0
last=$(students[@])
((mid=0))
Name=`echo ${students[$mid]} | cut -d: -f1`
Grade=`echo ${students[$mid]} | cut -d: -f2`
echo $Name
echo $Grade
A binary search needs the max and min boundaries of the search. Starting at zero is great, but your last variable is a little off. Try: last=$(($#students[@]} - 1))
the - 1 will put your array at the correct size (arrays start at zero and go to one less of their size.)
After that try the following pseudo code:
while (last is <= first)
middle = midway point between first and last
// make sure that your comparing just the names "Ann",
// not your whole string "Ann:A"
if (students[middle] == student)
exit loop
else if (students[middle] < student)
first = middle + 1
else if (students[middle] > student)
last = middle - 1
I'm not great at bash scripting, so I won't try and fix (if it even needs fixing) most of your syntax. The pseudo code should get you most of the way there if you figure out the syntax.
I think it's best to use a generic binary search function then to code your own for your particular case.
Binary search function in bash
# Returns the largest i for which `command i` succeeds (exits with a null exit code)
function dichotomic_search {
min=$1
max=$2
command=$3
while [ $min -lt $max ]; do
# Compute the mean between min and max, rounded up to the superior unit
current=`expr '(' "$min" + "$max" + 1 ')' / 2`
if $command $current
then min=$current
else max=`expr $current - 1`
fi
done
echo $min
}
It calls the function given as its last argument repetitively using binary search to find the last value for which it returns true. More explanations on Github
Binary search through a bash array
In your case, you would use it like that:
#!/usr/bin/env bash
source dichotomic.sh
arr=(Ann:C Bob:A Cindy:B Dean:E Emily:A Karen:A Zob:A)
function is_smaller {
element=$(echo ${arr[$2]} | cut -f1 -d :)
if [[ "$element" > "$1" ]]
then false
else true
fi
}
read target
highest_index=`expr ${#arr[@]} - 1`
index=$(dichotomic_search 0 $highest_index "is_smaller $target")
echo "${arr[$index]}"
This solution assumes that you are looking for the first successful execution of a command, rather than an element in an array.
lo=1
hi=100
while [ $(expr $hi - $lo) -ne 1 ]; do
mid=$(expr $lo + '(' $hi - $lo ')' / 2)
# Your command here
test 44 -gt $mid
if [ $? -eq 0 ]; then lo=$mid; else hi=$mid; fi
done
echo "$lo"
This always print the first value for which the execution of your command succeeds, unlike @lovasoa solution that is off by one in about half of the configurations. You can validate that by using seq 1 100 | while read o; do SCRIPT; done
where SCRIPT
is the above algorithm with test $o -gt $mid
as the tested command.
来源:https://stackoverflow.com/questions/17666007/bash-script-binary-search