问题
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