背景描述
如下表所示,有多條我國各省市下面區名,不難發現,它們都是混亂列出的,并沒有一定的規則;一個區是由(省,市,區)這個三維坐標才能唯一確定。在工作中可能會遇到不少這種三維坐標的模型,這里只是用這種大家最為熟悉的行政區的示例來闡述,如何讓三維坐標的模型以樹形結構展示,這是本文所討論的主題。
| 省 | 市 | 區 |
|---|---|---|
| 陜西省 | 西安市 | 未央區 |
| 江蘇省 | 南京市 | 鼓樓區 |
| 廣東省 | 廣州市 | 天河區 |
| 四川省 | 成都市 | 武侯區 |
| 江蘇省 | 南京市 | 秦淮區 |
| 江蘇省 | 蘇州市 | 姑蘇區 |
| 陜西省 | 西安市 | 雁塔區 |
| 廣東省 | 廣州市 | 越秀區 |
| 四川省 | 成都市 | 錦江區 |
| 廣東省 | 深圳市 | 南山區 |
| 陜西省 | 西安市 | 碑林區 |
| 四川省 | 綿陽市 | 游仙區 |
解決思路
此問題的解決思路并不難想到,可以大致分為兩步:
- 數據排序
- 有序數據樹形展示
數據排序
三維坐標(x, y, z)按樹形展示,就是按x,y,z的層級展示,那么就要對x,y,z坐標排序,這里定義一種(x, y, z)的序關系,如下所述:
- x坐標越小,排序越靠前;
- 若x坐標相等,再比較y坐標,y坐標越小越靠前;
- 若y坐標相等,再比較z坐標,z坐標越小越靠前。
- 若z坐標也相等,則按出現的先后順序排序。
例如(1,2,1)是要排在(2,1,1)前面的,因為前者的x坐標小于后者的x坐標。
回到行政區的示例中,我們可以使用漢語拼音首字母序來定義行政區排序,即:首字母排序越靠前,行政區越靠前,那么我們可以很容易將上面雜亂的行政區排好序,如下:
| 省 | 市 | 區 |
|---|---|---|
| 江蘇省 | 南京市 | 鼓樓區 |
| 江蘇省 | 南京市 | 秦淮區 |
| 江蘇省 | 蘇州市 | 姑蘇區 |
| 廣東省 | 廣州市 | 天河區 |
| 廣東省 | 廣州市 | 越秀區 |
| 廣東省 | 深圳市 | 南山區 |
| 四川省 | 成都市 | 錦江區 |
| 四川省 | 成都市 | 武侯區 |
| 四川省 | 綿陽市 | 游仙區 |
| 陜西省 | 西安市 | 碑林區 |
| 陜西省 | 西安市 | 未央區 |
| 陜西省 | 西安市 | 雁塔區 |
有序數據樹形展示
當排序結束后,其實我們肉眼已經可以很容易看出來這個樹形結構了,如下圖所示,但是如何用程序實現這一過程呢?
- 江蘇省
- 南京市
- 鼓樓區
- 秦淮區
- 蘇州市
- 姑蘇區
- 南京市
- 廣東省
- 廣州市
- 天河區
- 越秀區
- 深圳市
- 南山區
- 廣州市
- 四川省
- 成都市
- 錦江區
- 武侯區
- 綿陽市
- 游仙區
- 成都市
- 陜西省
- 西安市
- 碑林區
- 未央區
- 雁塔區
- 西安市
首先,定義行政區示例中一些主要的數據結構,如下:
List<Province> provinceList;
public class Record {
private String provinceName;
private String cityName;
private String districtName;
}
public class Province {
private String provinceName;
private List<City> cityList;
}
public class City {
private String cityName;
private List<District> districtList;
}
public class District {
private String districtName;
}
然后,通過對于有序三維數據進行一次遍歷,即可得到樹形結構的展示結果。
int currentProvinceIndex = -1;
int currentCityIndex = -1;
Set<String> provinceNameSet = new HashSet<>;
Set<String> cityNameSet = new HashSet<>;
Set<String> districtNameSet = new HashSet<>;
List<Province> resultList = new ArrayList();
for (Record record : recordList) {
if (!provinceNameSet.contains(record.getProvinceName())) {
currentProvinceIndex++;
provinceNameSet.add(record.getProvinceName());
Province province = new Province();
List<City> cityList = new ArrayList();
province.setProvinceName(record.getProvinceName());
province.setCityList(cityList);
resultList.add(province);
currentCityIndex = -1;
cityNameSet.clear();
}
if (!cityNameSet.contains(record.getCityName())) {
currentCityIndex++;
cityNameSet.add(record.getCityName());
City city = new City();
List<District> districtList = new ArrayList();
city.setDistrictList(districtList);
resultList.get(currentProvinceIndex).getCityList().add(city);
districtNameSet.clear();
}
if (!districtNameSet.contains(record.getDistrictName())) {
resultList.get(currentProvinceIndex).getCityList()
.get(currentCityIndex).getDistrictList.add(record.getDistrictName());
}
}
本文只是為了更為形象和生動的描繪,選取了行政區這個例子,實際上對于所有三維坐標樹形展示的問題,都可以參考本文的思路,根據具體問題,定義好數據結構以及它們之間的大小關系,然后遍歷一次即可得到樹形的展示結果。