How to fix the result of Binary Search Algorithm(appearing missing result)

爷,独闯天下 提交于 2020-05-17 05:46:27

问题


I have a problem about getting the result of Binary Search Algorithm as getting missing values. The program wants you to enter city name and shows the results of entering city names aftering reading each line in file and assigning each variable to City Object. But there is a problem in the result part.

There are 3 city names called "Moscow" in the list and it shows 2 results after entering city name "Moscow".

How can I fix the issue. I also shared my code snippets as shown below.

Here is my City object

public class City implements Serializable, Comparable<City>{

    private Integer cityWeight;
    private String cityName;
    private String countryName;
    ...

    @Override
    public int compareTo(City o) {
        // TODO Auto-generated method stub
         City city = (City) o;
         int compareage=city.getCityWeight();
         if(compareage < 1) {
             return getCityWeight()-compareage;
         }else {
             return compareage-getCityWeight();
         }

    }
}

Here is my cities.txt

93827
      10381222  Moscow, Russia
      23800 Moscow, Idaho, United States
      2026  Moscow, Pennsylvania, United States

Here is my process of reading part.

try(BufferedReader br = new BufferedReader(new FileReader(fileLocation))) {

            line = br.readLine();

            while (( line = br.readLine()) != null) {
                String[] cityIdInformation =  line.split("  ");
                String cityId = cityIdInformation[0];

                String[] cityNameCountryInformation = cityIdInformation[1].split(", ");

                String cityName = cityNameCountryInformation[0];
                String cityCountry = "";
                if(cityNameCountryInformation.length == 2) {
                    cityCountry = cityNameCountryInformation[1];
                }else {
                    cityCountry = cityNameCountryInformation[2];
                }

                cityId = cityId.trim();
                cityName = cityName.trim();
                cityCountry = cityCountry.trim();

                City city = new City();
                city.setCityWeight(Integer.parseInt(cityId));
                city.setCityName(cityName);
                city.setCountryName(cityCountry);

                cities.add(city);
            }


        }

Here is my Main part.

private static void enterSearchValue() {

        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter the word of character which I want to search : ");
        String charWord = scanner.nextLine();

        System.out.println("%cities.txt");
        System.out.println("Search " + charWord);

        if(charWord.length() > 3) {
            ProcessMethod.binarySearchProcess(cities, charWord);
        }

    }

The function shows the results of array's location and adds its location to Arraylist and shows result

public static void binarySearchProcess(ArrayList<City> cities, String charWord) {
        System.out.println("binarySearchProcess is working ");
        Integer[] indexArray = BinarySearch.binarySearch(cities, charWord);

        for (int i = 0; i < indexArray.length; i++) {
            System.out.print(indexArray[i] + " ");
        }
        System.out.println();
        ShowResult.getValuesFromIndexArray(cities, indexArray);
    }

public static void getValuesFromIndexArray(ArrayList<City> cities, Integer[] indexArray) {
        ArrayList<City> resultCities = new ArrayList<>();
        for (Integer index :indexArray) {
            resultCities.add(cities.get(index));
        }

        showSearchCityValues(resultCities);
    }

    public static void showSearchCityValues(ArrayList<City> cities) {
        System.out.println("----------------------------------------");
        for(City city: cities) {
            System.out.println("City Weight : " + city.getCityWeight() + 
                               " | City Name : " + city.getCityName() +
                               " | City Country : " + city.getCountryName()
                              );
        }
        System.out.println("----------------------------------------");
        System.out.println("The result of Search Size : " + cities.size());
    }

Here is my binary search algorithm.

public static Integer[] binarySearch(List<City> cities, Comparable key) {
        List<Integer> arrList = new ArrayList<Integer>();
        int lo = 0, hi = cities.size() - 1, mid;
        cities.sort((str1, str2) -> str1.getCityName().compareTo(str2.getCityName()));

        while (lo <= hi) {
            mid = lo + (hi - lo) / 2;
            int cmp = key.compareTo(cities.get(mid).getCityName());
            if (cmp == 0) {
                arrList.add(mid);
                lo = mid + 1;
            } else if (cmp < 0)
                hi = mid - 1;
            else
                lo = mid + 1;
        }
        return arrList.stream().toArray(Integer[]::new);
    }

Here is the outpuut.

Enter the word of character which I want to search : Moscow
%cities.txt
Search Moscow
binarySearchProcess is working 
1 2 
----------------------------------------
City Weight : 23800 | City Name : Moscow | City Country : United States
City Weight : 2026 | City Name : Moscow | City Country : United States
----------------------------------------
The result of Search Size : 2

回答1:


Since you're solving it without recursion I guess you want to avoid it, then you need to create 2 helper methods to find the lower and upper indexes and change your binarySearch method a little:

public static Integer[] binarySearch(List<City> cities, Comparable key) {
    List<Integer> arrList = new ArrayList<Integer>();
    int lo = 0, hi = cities.size() - 1, mid;
    cities.sort((str1, str2) -> str1.getCityName().compareTo(str2.getCityName()));

    while (lo <= hi) {
        mid = lo + (hi - lo) / 2;
        int cmp = key.compareTo(cities.get(mid).getCityName());
        if (cmp == 0) {
            int lowerBoundary = lowerIndex(cities, key, lo, mid);
            int upperBoundary = upperIndex(cities, key, mid, hi);
            for(int i = lowerBoundary; i <= upperBoundary; i++) {
                arrList.add(i);
            }
            break;
        } else if (cmp < 0)
            hi = mid - 1;
        else
            lo = mid + 1;
    }
    return arrList.stream().toArray(Integer[]::new);
}

public static int lowerIndex(List<City> cities, Comparable key, int lo, int hi) {
    int mid;
    int lastMatch = hi;
    while (lo <= hi) {
        mid = lo + (hi - lo) / 2;
        int cmp = key.compareTo(cities.get(mid).getCityName());
        if (cmp == 0) {
            lastMatch = mid;
            hi = mid - 1;
        } else if (cmp < 0) {
            lo = mid + 1;
        } else {
            break;
        }
    }

    return lastMatch;
}

public static int upperIndex(List<City> cities, Comparable key, int lo, int hi) {
    int mid;
    int lastMatch = lo;
    while (lo <= hi) {
        mid = lo + (hi - lo) / 2;
        int cmp = key.compareTo(cities.get(mid).getCityName());
        if (cmp == 0) {
            lastMatch = mid;
            lo = mid + 1;
        } else if (cmp < 0) {
            hi = mid - 1;
        } else {
            break;
        }
    }

    return lastMatch;
}

Although this is too much code and a recursive solution would be more elegant.




回答2:


Your binary search algorithm does not support duplicates . In

int cmp = key.compareTo(cities.get(mid).getCityName());
if (cmp == 0) {
   arrList.add(mid);
   lo = mid + 1;
}

you do not look at values before index mid. As you can have duplicates in your list these values might also equal your search term. You can try to follow Finding multiple entries with binary search to find a solution.

You could use a recursive solution, e.g.

private static void binarySearchHelper(
      List<City> cities,
      String key,
      List<Integer> arrList,
      int lo,
      int hi
  ) {
    if (lo <= hi) {
      int mid = lo + (hi - lo) / 2;
      int cmp = key.compareTo(cities.get(mid).getCityName());
      if (cmp == 0) {
        arrList.add(mid);
        binarySearchHelper(cities, key, arrList, lo + (mid - lo) / 2, mid - 1);
        binarySearchHelper(cities, key, arrList, mid + 1, mid + (hi - mid + 1) / 2);
      } else if (cmp < 0) {
        binarySearchHelper(cities, key, arrList, lo, mid - 1);
      } else {
        binarySearchHelper(cities, key, arrList, mid + 1, hi);
      }
    }
  }

and call binarySearchHelper(cities, key, arrList, lo, hi); in your binarySearch method after sorting the array.



来源:https://stackoverflow.com/questions/61558712/how-to-fix-the-result-of-binary-search-algorithmappearing-missing-result

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!