1

I wrote a shell script for binary search of integers. It's accepting space separated integer array, but when the code proceeds and we input the element to be searched, the code doesn't proceed further. It is either stuck or it is accepting more inputs, both of which is undesired.

Here's the code:

#!/bin/bash

declare -a arr
echo "Enter space separated sorted integers:"
read -ra arr

declare -i search
echo -n "Enter the element to be searched for: "
read -r search

index=-1
beg=0
mid=0
last=${#arr[@]}
last=$((last - 1))

while [ $beg -le $last ]; do
    mid=$((beg / 2 + end / 2))
    if [ $mid -eq "$search" ]; then
        index=$mid
        break
    elif [ $mid -gt "$search" ]; then
        end=$((mid - 1))
    elif [ $mid -lt "$search" ]; then
        beg=$((mid + 1))
    fi
done

if [ $index -ne -1 ]; then
    echo "Element found at $index"
else
    echo "Element not found"
fi
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 4
    I would add some echo statements to the loop to watch how the values of `beg`, `mid`, and `end` change. – chepner Oct 09 '20 at 17:28
  • 2
    it would help if you updated the question to include the array/search values that are causing you problems – markp-fuso Oct 09 '20 at 17:30
  • @chepner Nice Idea, but I think, control flow isn't reaching loop – infinitEplus Oct 09 '20 at 17:31
  • 1
    I'd look at the line `mid=$((beg / 2 + end / 2))` in particular. I'm not sure what `end` is and you probably mean `$beg` not `beg` – EdmCoff Oct 09 '20 at 17:31
  • 2
    consider expanding on your comment `stuck or it is accepting more inputs`; `stuck` where/when? how many inputs is it asking for (what are the associated prompts)? – markp-fuso Oct 09 '20 at 17:33
  • 1
    `end` is uninitialized. –  Oct 09 '20 at 17:33
  • 2
    you've also got a couple major flaws in the overall design: 1) what happens if the user inputs a list of numbers that are **not** in sorted order? and the **bigger issue** 2) all of your tests are against (effectively) the indexes of the array ... at no point are you actually comparing the `search` value against array values/elements, ie, there are no references to `${arr[]}`, so (for example) you'll never find the number `25` in an array consisting of `(10 15 20 25 30)` because `beg/end/last/index` will be range bound between `0` and `4` – markp-fuso Oct 09 '20 at 17:39
  • @EdmCoff My bad, `end` is actually `last`, but nevermind, I found the issue – infinitEplus Oct 09 '20 at 17:40
  • @markp-fuso Thank you. I was being dumb, never compared the actual values! – infinitEplus Oct 09 '20 at 17:42

1 Answers1

2

Ok, so here are the errors I found in my code:

  1. using end instead of last (Thanks to John Kugelman, EdmCoff, markp-fuso)
  2. Never actually comparing Array values as in Array[index] (Thanks to markp-fuso)
  3. sometimes, mid=$((beg / 2 + last / 2)) won't behave as mid=(beg + last)/2. Sometimes when beg, last=5, beg/2 + last/2 will evaluate in 4 instead of 5.
  4. Last but not least, using echo in debugging always helps, (Thanks to chepner )

So final working code looks like:

#!/bin/bash

declare -a arr
echo "Enter space separated sorted integers:"
read -ra arr

declare -i search
echo -n "Enter the element to be searched for: "
read -r search

index=-1
beg=0
mid=0
last=${#arr[@]}
last=$((last - 1))

while [ $beg -le $last ]; do
    echo -e "\nbeg=$beg\nmid=$mid\nlast=$last\n"
    mid=$((beg + last))
    mid=$((mid/2))
    if [ "${arr[$mid]}" -eq "$search" ]; then
        index=$mid
        break
    elif [ "${arr[$mid]}" -gt "$search" ]; then
        last=$((mid - 1))
    elif [ "${arr[$mid]}" -lt "$search" ]; then
        beg=$((mid + 1))
    fi
done

if [ $index -ne -1 ]; then
    echo "Element found at $((index+1))"
else
    echo "Element not found"
fi

  • 1
    consider sorting the array (ie, don't assume the user will input an already-sorted array); run a google search on 'bash sort array' to get quite a few hits, eg, [this](https://stackoverflow.com/q/7442417) – markp-fuso Oct 09 '20 at 18:33
  • 1
    Glad you got it sorted. Whynot include a sample run with input and output? Good luck. – shellter Oct 09 '20 at 18:37
  • 1
    re: the comment about `mid=$((beg / 2 + last / 2))` misbehaving: can't tell from your comments and code if you figured out why this doesn't always return the desired value so fwiw ... bash division returns an integer so: `(1/2) + (1/2)` == `0 + 0` == `0`, while `(1+1)/2` == `2/2` == `1` ("Duh, Mark!" ?); your new code addresses this as would `mid=$(( (beg+last)/2 ))` – markp-fuso Oct 09 '20 at 18:58
  • Sure, forgot to mention integer division. I'll update it ASAP, with sample input and outputs too – infinitEplus Oct 10 '20 at 03:17