一种寻路的应用

应用背景

利用长途车进行货物转运的寻路计算。例如从深圳到大连。可以走有很多条长途车的路线。需要根据需求计算出最合适路线。不同的路线的总里程数、总价、需要的时间不一样。客户根据需求进行选择。主要有一些细节:

  1. 全国的长途车车站的数据的更新:

  2. 包括位置、发车班次时间点、车站间的里程数等等。常用的路线有18000多条 


重庆    重庆    重庆万盛客运中心    308    遵义    遵义市长途汽车站
重庆    重庆    重庆万盛客运中心    360    成都    成都北门汽车站
重庆    重庆    重庆渝中长途汽车站    157    武胜    武胜汽车站
重庆    重庆    重庆渝中长途汽车站    340    遵义    遵义市长途汽车站
重庆    重庆    重庆渝中长途汽车站    360    成都    成都北门汽车站
重庆    重庆    重庆渝中长途汽车站    467    巴中    巴中江北客运中心站
重庆    重庆    重庆渝中长途汽车站    502    广元    广元市长途汽车客运站 

  1. 同城转车的处理

  2. 有些城市有多个车站,可以在一个城市里转到另外一个车站,再转运到下一站

  3. 使用发车班次时间表进行总时长的计算

  4. 预留出合理的时间间隔。例如到达某一站是20:30,但是到下一站的车 最晚一班是15:00 点发车。所以只能等第2天的班车。还有的班次可能一周只有2趟车。 有时 到达某一站是15:00  下一站的发车时间也是15:00 这种就只能等下一班,因为赶不上。

代码实现

初始化

班车路线、城市、车站等

constructor TR_Manager.Create;
begin
  _result_path := Tlist<TR_Path>.Create;
  _Dict_Province := TDictionary<Integer, TProvince>.Create();
  _Dict_City := TDictionary<Integer, TCity>.Create();
  _Dict_City_Name := TDictionary<string, TCity>.Create();
  _ProvinceList := Tlist<TProvince>.Create();
  _StationList := Tlist<TStation>.Create();
  _Dict_Station := TDictionary<string, TStation>.Create();
  _StationPathList := Tlist<TStation_Path>.Create();
  _Dict_CityID_Station := TDictionary < Integer, Tlist < TStation >>.Create();
  _Dict_CityID_Xian_Station := TDictionary < Integer, TDictionary < string,
    Tlist<TStation> >>.Create(); // hfg 2016-07-23
  _StationPathNodeList := Tlist<TStation_Path_Node>.Create();
  _Dict_Station_Path_Node := TDictionary<TStation, TStation_Path_Node>.Create();
  _Dict_CityID_Path_Node := TDictionary < Integer, Tlist < TStation_Path_Node
    >>.Create();
  _Node_Tmp := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_2 := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_before_end := Tlist<TStation_Path_Node>.Create();
end;

寻路

StationName_Begin: 起点车站

Station_End: 终点车站

max_step: Integer = 6; 最大转车次数

allow_same_city: boolean = false 是否允许同城转运

function TR_Manager.get_path_quick(StationName_Begin: string;
  Station_End: Tlist<TStation>; max_step: Integer = 6;
  allow_same_city: boolean = false): boolean;
var
  Station: TStation;
  node_root, node, node_next: TStation_Path_Node;
  i, k, step, Node_Tmp_Count, Node_Tmp_2_Count,
    Node_Tmp_before_end_count: Integer;
  path: TR_Path;
  list: Tlist;
  city_station_list: Tlist<TStation_Path_Node>;
begin
  Result := false;
  clear_result_path();
  if Station_End = nil then
    exit;

  if Station_End.Count <= 0 then
    exit;
  if not(_Dict_Station.TryGetValue(StationName_begin, Station)) then
    exit;
  if Station.CityID = Station_End[0].CityID then
  begin
    path := TR_Path.Create;
    path.Mileage := 0;
    path.step := 1;
    path.StationList.Add(Station);
    for i := 0 to Station_End.Count - 1 do
    begin
      if Station_End[i].Name <> Station.Name then
      begin
        path.StationList.Add(Station_End[i]);
        Break;
      end;
    end;
    if path.StationList.Count < 2 then
      path.StationList.Add(Station);
    _result_path.Add(path);
  end;
  if not(_Dict_Station_Path_Node.TryGetValue(Station, node_root)) then
    exit;
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].reset();
  node_root.set_Step(0);
  _Node_Tmp[0] := node_root;
  Node_Tmp_Count := 1;
  Node_Tmp_before_end_count := 0;
  for i := 0 to Station_End.Count - 1 do
  begin
    if _Dict_Station_Path_Node.TryGetValue(Station_End[i], node) then
      node.set_is_before_end();
  end;
  for step := 1 to max_step do
  begin
    Node_Tmp_2_Count := 0;
    for i := 0 to Node_Tmp_Count - 1 do
    begin
      try
        node := _Node_Tmp[i];
        if (node.is_before_end) then
        begin
          _Node_Tmp_before_end[Node_Tmp_before_end_count] := node;
          inc(Node_Tmp_before_end_count);
          if step > 1 then
            Continue;
        end;
        for k := 0 to node.Next_Station.Count - 1 do
        begin
          node_next := node.Next_Station[k].Station_Node_Next;
          if node_next.is_end then
            Continue;
          if not node_next.is_on_path then
          begin
            node_next.path_mileage := node.path_mileage + node.Next_Station
              [k].Mileage;
            node_next.Path_Prior_Station := node;
            node_next.set_Step(step);
            if Node_Tmp_2_Count < _Node_Tmp_2.Count then
              _Node_Tmp_2[Node_Tmp_2_Count] := node_next
            else
              _Node_Tmp_2.Add(node_next);
            inc(Node_Tmp_2_Count);
          end
          else
          begin
            if (node_next.step = step) and (step > 1) then
            begin
              if node.path_mileage + node.Next_Station[k].Mileage < node_next.path_mileage
              then
              begin
                node_next.path_mileage := node.path_mileage + node.Next_Station
                  [k].Mileage;
                node_next.Path_Prior_Station := node;
              end;
            end;
          end;
        end;
        if allow_same_city then
        begin
          if _Dict_CityID_Path_Node.TryGetValue(node.Station.CityID,
            city_station_list) then
          begin
            for k := 0 to city_station_list.Count - 1 do
            begin
              node_next := city_station_list[k];
              if node_next.is_end then
                Continue;
              if not node_next.is_on_path then
              begin
                node_next.path_mileage := node.path_mileage + 0;
                node_next.Path_Prior_Station := node;
                node_next.set_Step(step);
                if Node_Tmp_2_Count < _Node_Tmp_2.Count then
                  _Node_Tmp_2[Node_Tmp_2_Count] := node_next
                else
                  _Node_Tmp_2.Add(node_next);
                inc(Node_Tmp_2_Count);
              end;
            end;
          end;
        end;
      except
        Node_Tmp_2_Count := Node_Tmp_2_Count - 1;
      end;
    end;
    Node_Tmp_Count := 0;
    for i := 0 to Node_Tmp_2_Count - 1 do
    begin
      if _Node_Tmp_2[i].is_on_path then
      begin
        if True then
          if Node_Tmp_Count < _Node_Tmp.Count then
            _Node_Tmp[Node_Tmp_Count] := _Node_Tmp_2[i]
          else
            _Node_Tmp.Add(_Node_Tmp_2[i]);
        inc(Node_Tmp_Count);
      end;
    end;
  end;
  list := Tlist.Create();
  for i := 0 to Node_Tmp_before_end_count - 1 do
  begin
    path := TR_Path.Create;
    node := _Node_Tmp_before_end[i];
    path.Mileage := node.path_mileage + node.to_end_mileage;
    path.StationList.Add(node.end_Node.Station);
    path.StationList.Add(node.Station);
    node_next := node.Path_Prior_Station;
    for step := 1 to max_step + 1 do
    begin
      if node_next = nil then
        Break;
      path.StationList.Add(node_next.Station);
      if node_next.step <= 0 then
        Break;
      node_next := node_next.Path_Prior_Station
    end;
    path.StationList.Reverse();
    list.Add(path);
  end;
  list.Sort(@ComparePath_city);
  for i := 0 to list.Count - 1 do
    _result_path.Add(list[i]);
  FreeAndNil(list);
  Result := _result_path.Count > 0;
end;

操作说明

1、登陆时选择“宝安汽车站”

  1. 发布一条到北京的信息

  1. 在“深圳”里可以看到刚增加的信息

  1. 切换到“湖北武汉”,也可以看到这条信息

  1. 切换到“湖北武汉”,也可以看到这条信息

全部代码

unit U_city_manager;

interface

uses
  System.SysUtils, System.Types, System.Classes, Generics.Collections;

type
  TCounty = class
  private
    _Name: string;
    _CityID: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property Name: string read _Name write _Name;
    property CityID: Integer read _CityID write _CityID;
  end;

  TProvince = class;

  TCity = class
  private
    _ID: Integer;
    _Name: string;
    _Code: Integer;
    _TelCode: Integer;
    _CountyList: Tlist<TCounty>;
    Province: TProvince;
    procedure clear_CountyList();
  public

    constructor Create;
    destructor Destroy; override;
    property CountyList: Tlist<TCounty> read _CountyList;
    property ID: Integer read _ID write _ID;
    property Name: string read _Name write _Name;
    property Code: Integer read _Code write _Code;
    property TelCode: Integer read _TelCode write _TelCode;
  end;

  TProvince = class
  private
    _ID: Integer;
    _Name: string;
    _CardCode: string;
    _CityList: Tlist<TCity>;
    procedure clear_CityList();
  public
    constructor Create;
    destructor Destroy; override;
    property CityList: Tlist<TCity> read _CityList;
    property ID: Integer read _ID write _ID;
    property Name: string read _Name write _Name;
    property CardCode: string read _CardCode write _CardCode;
  end;

  TStation = class
  private
    _ProvinceName: string;
    _CityID: Integer;
    _CityName: string;
    _Name: string;
    _xian: string; // hfg 2016-07-23
    _address_id: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property ProvinceName: string read _ProvinceName write _ProvinceName;
    property CityID: Integer read _CityID write _CityID;
    property CityName: string read _CityName write _CityName;
    property Name: string read _Name write _Name;
    property xian: string read _xian write _xian; // hfg 2016-07-23
    property address_id: Integer read _address_id write _address_id;

  end;

  TStation_Path = class
  private
    _Station_Begin: TStation;
    _Station_End: TStation;
    _Mileage: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property Station_Begin: TStation read _Station_Begin write _Station_Begin;
    property Station_End: TStation read _Station_End write _Station_End;
    property Mileage: Integer read _Mileage write _Mileage;
  end;

  TStation_Path_Node = class;

  TStation_Next = class
  private
    _Station_Node_Next: TStation_Path_Node;
    _Mileage: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property Station_Node_Next: TStation_Path_Node read _Station_Node_Next
      write _Station_Node_Next;
    property Mileage: Integer read _Mileage write _Mileage;
  end;

  TStation_Path_Node = class
  private
    _Station: TStation;
    _Next_Station: Tlist<TStation_Next>;
    _Prior_Station: Tlist<TStation_Next>;
    _is_on_path: boolean;
    _is_end: boolean;
    _step: Integer;
    _Path_Prior_Station: TStation_Path_Node;
    _path_mileage: Integer;
    _is_before_end: boolean;
    _end_Node: TStation_Path_Node;
    _to_end_mileage: Integer;
    procedure clear_Next_Station();
    procedure clear_Prior_Station();
  public
    constructor Create;
    destructor Destroy; override;
    procedure add_next(next_node: TStation_Path_Node; Mileage: Integer);
    procedure add_Prior(p_node: TStation_Path_Node; Mileage: Integer);
    property Station: TStation read _Station write _Station;
    property Next_Station: Tlist<TStation_Next> read _Next_Station
      write _Next_Station;
    property is_on_path: boolean read _is_on_path;
    property is_end: boolean read _is_end;
    property step: Integer read _step;
    property path_mileage: Integer read _path_mileage write _path_mileage;
    property Path_Prior_Station: TStation_Path_Node read _Path_Prior_Station
      write _Path_Prior_Station;
    property is_before_end: boolean read _is_before_end;
    property to_end_mileage: Integer read _to_end_mileage write _to_end_mileage;
    property end_Node: TStation_Path_Node read _end_Node;

    procedure reset();
    procedure set_Step(v: Integer);
    procedure set_is_before_end();
  end;

  TR_Path = class
  public
    step: Integer;
    Mileage: Integer;
    StationList: Tlist<TStation>;
  public
    constructor Create;
    destructor Destroy; override;
    function get_txt(): string;
    function get_txt_with_city(): string;
  end;

  TR_Manager = class
  private
    _ProvinceList: Tlist<TProvince>;
    _Dict_Province: TDictionary<Integer, TProvince>;
    _Dict_City: TDictionary<Integer, TCity>;
    _Dict_City_Name: TDictionary<string, TCity>;
    _StationList: Tlist<TStation>;
    _Dict_Station: TDictionary<string, TStation>;
    _Dict_CityID_Station: TDictionary<Integer, Tlist<TStation>>;
    _Dict_CityID_Xian_Station
      : TDictionary<Integer, TDictionary<string, Tlist<TStation>>>;
    // hfg 2016-07-23
    _StationPathList: Tlist<TStation_Path>;
    _StationPathNodeList: Tlist<TStation_Path_Node>;
    _Dict_Station_Path_Node: TDictionary<TStation, TStation_Path_Node>;
    _Dict_CityID_Path_Node: TDictionary<Integer, Tlist<TStation_Path_Node>>;
    _Node_Tmp: Tlist<TStation_Path_Node>;
    _Node_Tmp_2: Tlist<TStation_Path_Node>;
    _Node_Tmp_before_end: Tlist<TStation_Path_Node>;
    _result_path: Tlist<TR_Path>;
    procedure clear_result_path();
    procedure clear_ProvinceList();
    procedure clear_StationList();
    procedure clear_StationPathList();
    procedure clear_StationPathNodeList();
    procedure clear_Dict_CityID_Xian_Station(); // hfg 2016-07-23
    procedure make_StationPathNodeList();
  public
    constructor Create;
    destructor Destroy; override;
    property ProvinceList: Tlist<TProvince> read _ProvinceList;
    property result_path: Tlist<TR_Path> read _result_path;
    procedure load_Province(fn: string);
    procedure load_Province_sl(sl: TStringList);
    procedure load_City(fn: string);
    procedure load_City_sl(sl: TStringList);
    procedure load_County(fn: string);
    procedure load_Path(fn: string);
    procedure load_Path_new(fn: string);
    procedure load_Path_new_sl(sl: TStringList); // 2016-10-03
    procedure load_xian(fn: string); // hfg 2016-07-23
    function get_Province_by_id(ID: Integer): TProvince;
    function get_City_by_id(ID: Integer): TCity;
    function get_City_by_name(ProvinceName, city_name: string): TCity;
    function get_City_by_full_name(full_city_name: string): TCity;
    function get_or_add_Station(ProvinceName, CityName, Name: string): TStation;
    function get_or_add_Station_new(city_id, Name, xian: string): TStation;
    procedure get_station_by_city_id(city_id: Integer;
      var list: Tlist<TStation>);
    procedure get_station_by_city_id_xian(city_id: Integer; xian: string;
      var list: Tlist<TStation>); // hfg 2016-07-23
    function get_path_quick(StationName_begin: string;
      Station_End: Tlist<TStation>; max_step: Integer = 6;
      allow_same_city: boolean = false): boolean;

    function get_path_quick_ex(Station_Begin: Tlist<TStation>;
      Station_End: Tlist<TStation>; max_step: Integer = 6;
      allow_same_city: boolean = false): boolean; // 2016-10-01
    function get_StationList: Tlist<TStation>;
    procedure save_Station(fn: string);
    property StationPathList: Tlist<TStation_Path> read _StationPathList;
  end;

implementation

uses u_address_def;

function get_Province_ID_from_City_Code(v: Integer): Integer;
begin
  Result := v div 100;
end;

function ComparePath_city(Item1, Item2: TR_Path): Integer;
begin
  Result := Item1.StationList.Count - Item2.StationList.Count;
  if Result = 0 then
    Result := Item1.Mileage - Item2.Mileage;

end;

{ TR_Manager }
procedure TR_Manager.clear_Dict_CityID_Xian_Station; // hfg 2016-07-23
var
  pair: TPair<Integer, TDictionary<string, Tlist<TStation>>>;
  pair2: TPair<string, Tlist<TStation>>;
begin
  for pair in _Dict_CityID_Xian_Station do
  begin
    for pair2 in pair.Value do
    begin
      pair2.Value.Free
    end;
    pair.Value.Free;
  end;
  _Dict_CityID_Xian_Station.Clear();
end;

procedure TR_Manager.clear_ProvinceList;
var
  i: Integer;
begin
  for i := 0 to _ProvinceList.Count - 1 do
    _ProvinceList[i].Free;
  _ProvinceList.Clear();
  _Dict_Province.Clear();
  _Dict_City.Clear();
  _Dict_City_Name.Clear();
end;

procedure TR_Manager.clear_result_path;
var
  i: Integer;
begin
  for i := 0 to _result_path.Count - 1 do
    _result_path[i].Free;
  _result_path.Clear();
end;

procedure TR_Manager.clear_StationList;
var
  i: Integer;
  pair: TPair<Integer, Tlist<TStation>>;
begin
  _Dict_Station.Clear();
  for i := 0 to _StationList.Count - 1 do
    _StationList[i].Free;
  _StationList.Clear();
  for pair in _Dict_CityID_Station do
  begin
    pair.Value.Free;
  end;
  _Dict_CityID_Station.Clear();
end;

procedure TR_Manager.clear_StationPathList;
var
  i: Integer;
begin
  for i := 0 to _StationPathList.Count - 1 do
    _StationPathList[i].Free;
  _StationPathList.Clear();
end;

procedure TR_Manager.clear_StationPathNodeList;
var
  i: Integer;
  pair: TPair<Integer, Tlist<TStation_Path_Node>>;
begin
  _Dict_Station_Path_Node.Clear();
  for pair in _Dict_CityID_Path_Node do
  begin
    pair.Value.Free;
  end;
  _Dict_CityID_Path_Node.Clear();
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].Free;
  _StationPathNodeList.Clear();
end;

constructor TR_Manager.Create;
begin
  _result_path := Tlist<TR_Path>.Create;
  _Dict_Province := TDictionary<Integer, TProvince>.Create();
  _Dict_City := TDictionary<Integer, TCity>.Create();
  _Dict_City_Name := TDictionary<string, TCity>.Create();
  _ProvinceList := Tlist<TProvince>.Create();
  _StationList := Tlist<TStation>.Create();
  _Dict_Station := TDictionary<string, TStation>.Create();
  _StationPathList := Tlist<TStation_Path>.Create();
  _Dict_CityID_Station := TDictionary < Integer, Tlist < TStation >>.Create();
  _Dict_CityID_Xian_Station := TDictionary < Integer, TDictionary < string,
    Tlist<TStation> >>.Create(); // hfg 2016-07-23
  _StationPathNodeList := Tlist<TStation_Path_Node>.Create();
  _Dict_Station_Path_Node := TDictionary<TStation, TStation_Path_Node>.Create();
  _Dict_CityID_Path_Node := TDictionary < Integer, Tlist < TStation_Path_Node
    >>.Create();
  _Node_Tmp := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_2 := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_before_end := Tlist<TStation_Path_Node>.Create();
end;

destructor TR_Manager.Destroy;
begin
  clear_result_path();
  FreeAndNil(_result_path);
  clear_ProvinceList();
  FreeAndNil(_ProvinceList);
  FreeAndNil(_Dict_Province);
  FreeAndNil(_Dict_City);
  FreeAndNil(_Dict_City_Name);
  clear_StationList();
  FreeAndNil(_StationList);
  FreeAndNil(_Dict_Station);
  clear_StationPathList();
  FreeAndNil(_StationPathList);
  clear_StationPathNodeList();
  FreeAndNil(_StationPathNodeList);
  FreeAndNil(_Node_Tmp);
  FreeAndNil(_Node_Tmp_2);
  FreeAndNil(_Node_Tmp_before_end);
  clear_Dict_CityID_Xian_Station(); // hfg 2016-07-23
  FreeAndNil(_Dict_CityID_Xian_Station); // hfg 2016-07-23
  inherited;
end;

function TR_Manager.get_City_by_full_name(full_city_name: string): TCity;
begin
  if not _Dict_City_Name.TryGetValue(full_city_name, Result) then
    Result := nil;
end;

function TR_Manager.get_City_by_id(ID: Integer): TCity;
begin
  if not _Dict_City.TryGetValue(ID, Result) then
    Result := nil;
end;

function TR_Manager.get_City_by_name(ProvinceName, city_name: string): TCity;
begin
  if not _Dict_City_Name.TryGetValue(ProvinceName + city_name, Result) then
    Result := nil;
end;

function TR_Manager.get_or_add_Station(ProvinceName, CityName, Name: string)
  : TStation;
var
  city: TCity;
  Station: TStation;
  CityID: Integer;
  l: Tlist<TStation>;
begin
  Result := nil;
  if _Dict_Station.TryGetValue(Name, Result) then
    exit;
  if _Dict_City_Name.TryGetValue(ProvinceName + CityName, city) then
    CityID := city.ID
  else
  begin
    CityID := 9999999;
    exit;
  end;
  Station := TStation.Create;
  Station.ProvinceName := ProvinceName;
  Station.CityID := CityID;
  Station.CityName := CityName;
  Station.Name := Name;
  _StationList.Add(Station);
  _Dict_Station.AddOrSetValue(Station.Name, Station);
  if (not _Dict_CityID_Station.TryGetValue(CityID, l)) then
  begin
    l := Tlist<TStation>.Create();
    _Dict_CityID_Station.AddOrSetValue(CityID, l);
  end;
  l.Add(Station);
  Result := Station;
end;

function TR_Manager.get_or_add_Station_new(city_id, Name, xian: string)
  : TStation;
var
  city: TCity;
  Station: TStation;
  CityID: Integer;
  l: Tlist<TStation>;
begin
  Result := nil;
  if _Dict_Station.TryGetValue(Name, Result) then
    exit;
  CityID := strtointdef(city_id, 9999999);
  city := get_City_by_id(CityID);
  if city = nil then
    exit;
  Station := TStation.Create;
  Station.ProvinceName := city.Province._Name;
  Station.CityID := CityID;
  Station.CityName := city.Name;
  Station.Name := Name;
  Station.xian := xian;
  Station.address_id := get_city_xian_id(CityID, xian);
  _StationList.Add(Station);
  _Dict_Station.AddOrSetValue(Station.Name, Station);
  if (not _Dict_CityID_Station.TryGetValue(CityID, l)) then
  begin
    l := Tlist<TStation>.Create();
    _Dict_CityID_Station.AddOrSetValue(CityID, l);
  end;
  l.Add(Station);
  Result := Station;
end;

function TR_Manager.get_path_quick(StationName_begin: string;
  Station_End: Tlist<TStation>; max_step: Integer = 6;
  allow_same_city: boolean = false): boolean;
var
  Station: TStation;
  node_root, node, node_next: TStation_Path_Node;
  i, k, step, Node_Tmp_Count, Node_Tmp_2_Count,
    Node_Tmp_before_end_count: Integer;
  path: TR_Path;
  list: Tlist;
  city_station_list: Tlist<TStation_Path_Node>;
begin
  Result := false;
  clear_result_path();
  if Station_End = nil then
    exit;

  if Station_End.Count <= 0 then
    exit;
  if not(_Dict_Station.TryGetValue(StationName_begin, Station)) then
    exit;
  if Station.CityID = Station_End[0].CityID then
  begin
    path := TR_Path.Create;
    path.Mileage := 0;
    path.step := 1;
    path.StationList.Add(Station);
    for i := 0 to Station_End.Count - 1 do
    begin
      if Station_End[i].Name <> Station.Name then
      begin
        path.StationList.Add(Station_End[i]);
        Break;
      end;
    end;
    if path.StationList.Count < 2 then
      path.StationList.Add(Station);
    _result_path.Add(path);
  end;
  if not(_Dict_Station_Path_Node.TryGetValue(Station, node_root)) then
    exit;
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].reset();
  node_root.set_Step(0);
  _Node_Tmp[0] := node_root;
  Node_Tmp_Count := 1;
  Node_Tmp_before_end_count := 0;
  for i := 0 to Station_End.Count - 1 do
  begin
    if _Dict_Station_Path_Node.TryGetValue(Station_End[i], node) then
      node.set_is_before_end();
  end;
  for step := 1 to max_step do
  begin
    Node_Tmp_2_Count := 0;
    for i := 0 to Node_Tmp_Count - 1 do
    begin
      try
        node := _Node_Tmp[i];
        if (node.is_before_end) then
        begin
          _Node_Tmp_before_end[Node_Tmp_before_end_count] := node;
          inc(Node_Tmp_before_end_count);
          if step > 1 then
            Continue;
        end;
        for k := 0 to node.Next_Station.Count - 1 do
        begin
          node_next := node.Next_Station[k].Station_Node_Next;
          if node_next.is_end then
            Continue;
          if not node_next.is_on_path then
          begin
            node_next.path_mileage := node.path_mileage + node.Next_Station
              [k].Mileage;
            node_next.Path_Prior_Station := node;
            node_next.set_Step(step);
            if Node_Tmp_2_Count < _Node_Tmp_2.Count then
              _Node_Tmp_2[Node_Tmp_2_Count] := node_next
            else
              _Node_Tmp_2.Add(node_next);
            inc(Node_Tmp_2_Count);
          end
          else
          begin
            if (node_next.step = step) and (step > 1) then
            begin
              if node.path_mileage + node.Next_Station[k].Mileage < node_next.path_mileage
              then
              begin
                node_next.path_mileage := node.path_mileage + node.Next_Station
                  [k].Mileage;
                node_next.Path_Prior_Station := node;
              end;
            end;
          end;
        end;
        if allow_same_city then
        begin
          if _Dict_CityID_Path_Node.TryGetValue(node.Station.CityID,
            city_station_list) then
          begin
            for k := 0 to city_station_list.Count - 1 do
            begin
              node_next := city_station_list[k];
              if node_next.is_end then
                Continue;
              if not node_next.is_on_path then
              begin
                node_next.path_mileage := node.path_mileage + 0;
                node_next.Path_Prior_Station := node;
                node_next.set_Step(step);
                if Node_Tmp_2_Count < _Node_Tmp_2.Count then
                  _Node_Tmp_2[Node_Tmp_2_Count] := node_next
                else
                  _Node_Tmp_2.Add(node_next);
                inc(Node_Tmp_2_Count);
              end;
            end;
          end;
        end;
      except
        Node_Tmp_2_Count := Node_Tmp_2_Count - 1;
      end;
    end;
    Node_Tmp_Count := 0;
    for i := 0 to Node_Tmp_2_Count - 1 do
    begin
      if _Node_Tmp_2[i].is_on_path then
      begin
        if True then
          if Node_Tmp_Count < _Node_Tmp.Count then
            _Node_Tmp[Node_Tmp_Count] := _Node_Tmp_2[i]
          else
            _Node_Tmp.Add(_Node_Tmp_2[i]);
        inc(Node_Tmp_Count);
      end;
    end;
  end;
  list := Tlist.Create();
  for i := 0 to Node_Tmp_before_end_count - 1 do
  begin
    path := TR_Path.Create;
    node := _Node_Tmp_before_end[i];
    path.Mileage := node.path_mileage + node.to_end_mileage;
    path.StationList.Add(node.end_Node.Station);
    path.StationList.Add(node.Station);
    node_next := node.Path_Prior_Station;
    for step := 1 to max_step + 1 do
    begin
      if node_next = nil then
        Break;
      path.StationList.Add(node_next.Station);
      if node_next.step <= 0 then
        Break;
      node_next := node_next.Path_Prior_Station
    end;
    path.StationList.Reverse();
    list.Add(path);
  end;
  list.Sort(@ComparePath_city);
  for i := 0 to list.Count - 1 do
    _result_path.Add(list[i]);
  FreeAndNil(list);
  Result := _result_path.Count > 0;
end;

function TR_Manager.get_path_quick_ex(Station_Begin,
  Station_End: Tlist<TStation>; max_step: Integer;
  allow_same_city: boolean): boolean;
var
  Station: TStation;
  node_root, node, node_next: TStation_Path_Node;
  m, i, k, step, Node_Tmp_Count, Node_Tmp_2_Count,
    Node_Tmp_before_end_count: Integer;
  path: TR_Path;
  list: Tlist;
  city_station_list: Tlist<TStation_Path_Node>;
begin
  Result := false;
  clear_result_path();
  if Station_Begin = nil then
    exit;
  if Station_Begin.Count <= 0 then
    exit;
  if Station_End = nil then
    exit;
  if Station_End.Count <= 0 then
    exit;
  for m := 0 to Station_Begin.Count - 1 do
  begin
    Station := Station_Begin[m];
    if Station.CityID = Station_End[0].CityID then
    begin
      path := TR_Path.Create;
      path.Mileage := 0;
      path.step := 1;
      path.StationList.Add(Station);
      for i := 0 to Station_End.Count - 1 do
      begin
        if Station_End[i].Name <> Station.Name then
        begin
          path.StationList.Add(Station_End[i]);
          Break;
        end;
      end;
      if path.StationList.Count < 2 then
        path.StationList.Add(Station);
      _result_path.Add(path);
    end;
  end;
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].reset();

  Node_Tmp_Count := 0;
  for m := 0 to Station_Begin.Count - 1 do
  begin
    Station := Station_Begin[m];
    if (_Dict_Station_Path_Node.TryGetValue(Station, node_root)) then
    begin
      _Node_Tmp[Node_Tmp_Count] := node_root;
      node_root.set_Step(0);
      Node_Tmp_Count := Node_Tmp_Count + 1;
    end;
  end;
  if Node_Tmp_Count = 0 then
    exit;
  Node_Tmp_before_end_count := 0;
  for i := 0 to Station_End.Count - 1 do
  begin
    if _Dict_Station_Path_Node.TryGetValue(Station_End[i], node) then
      node.set_is_before_end();
  end;
  for step := 1 to max_step do
  begin
    Node_Tmp_2_Count := 0;
    for i := 0 to Node_Tmp_Count - 1 do
    begin
      try
        node := _Node_Tmp[i];
        if (node.is_before_end) then
        begin
          _Node_Tmp_before_end[Node_Tmp_before_end_count] := node;
          inc(Node_Tmp_before_end_count);
          if step > 1 then
            Continue;
        end;
        for k := 0 to node.Next_Station.Count - 1 do
        begin
          node_next := node.Next_Station[k].Station_Node_Next;
          if node_next.is_end then
            Continue;
          if not node_next.is_on_path then
          begin
            node_next.path_mileage := node.path_mileage + node.Next_Station
              [k].Mileage;
            node_next.Path_Prior_Station := node;
            node_next.set_Step(step);
            if Node_Tmp_2_Count < _Node_Tmp_2.Count then
              _Node_Tmp_2[Node_Tmp_2_Count] := node_next
            else
              _Node_Tmp_2.Add(node_next);
            inc(Node_Tmp_2_Count);
          end
          else
          begin
            if (node_next.step = step) and (step > 1) then
            begin
              if node.path_mileage + node.Next_Station[k].Mileage < node_next.path_mileage
              then
              begin
                node_next.path_mileage := node.path_mileage + node.Next_Station
                  [k].Mileage;
                node_next.Path_Prior_Station := node;
              end;
            end;
          end;
        end;
        if allow_same_city then
        begin
          if _Dict_CityID_Path_Node.TryGetValue(node.Station.CityID,
            city_station_list) then
          begin
            for k := 0 to city_station_list.Count - 1 do
            begin
              node_next := city_station_list[k];
              if node_next.is_end then
                Continue;
              if not node_next.is_on_path then
              begin
                node_next.path_mileage := node.path_mileage + 0;
                node_next.Path_Prior_Station := node;
                node_next.set_Step(step);
                if Node_Tmp_2_Count < _Node_Tmp_2.Count then
                  _Node_Tmp_2[Node_Tmp_2_Count] := node_next
                else
                  _Node_Tmp_2.Add(node_next);
                inc(Node_Tmp_2_Count);
              end;
            end;
          end;
        end;
      except
        Node_Tmp_2_Count := Node_Tmp_2_Count - 1;
      end;
    end;
    Node_Tmp_Count := 0;
    for i := 0 to Node_Tmp_2_Count - 1 do
    begin
      if _Node_Tmp_2[i].is_on_path then
      begin
        if True then
          if Node_Tmp_Count < _Node_Tmp.Count then
            _Node_Tmp[Node_Tmp_Count] := _Node_Tmp_2[i]
          else
            _Node_Tmp.Add(_Node_Tmp_2[i]);
        inc(Node_Tmp_Count);
      end;
    end;
  end;
  list := Tlist.Create();
  for i := 0 to Node_Tmp_before_end_count - 1 do
  begin
    path := TR_Path.Create;
    node := _Node_Tmp_before_end[i];
    path.Mileage := node.path_mileage + node.to_end_mileage;
    path.StationList.Add(node.end_Node.Station);
    path.StationList.Add(node.Station);
    node_next := node.Path_Prior_Station;
    for step := 1 to max_step + 1 do
    begin
      if node_next = nil then
        Break;
      path.StationList.Add(node_next.Station);
      if node_next.step <= 0 then
        Break;
      node_next := node_next.Path_Prior_Station
    end;
    path.StationList.Reverse();
    list.Add(path);
  end;
  list.Sort(@ComparePath_city);
  for i := 0 to list.Count - 1 do
    _result_path.Add(list[i]);
  FreeAndNil(list);
  Result := _result_path.Count > 0;

end;

function TR_Manager.get_Province_by_id(ID: Integer): TProvince;
begin
  if not _Dict_Province.TryGetValue(ID, Result) then
    Result := nil;
end;

function TR_Manager.get_StationList: Tlist<TStation>;
begin
  Result := _StationList;
end;

procedure TR_Manager.get_station_by_city_id(city_id: Integer;
  var list: Tlist<TStation>);
begin
  if not(_Dict_CityID_Station.TryGetValue(city_id, list)) then
    list := nil;
end;

procedure TR_Manager.get_station_by_city_id_xian(city_id: Integer; xian: string;
  var list: Tlist<TStation>); // hfg 2016-07-23
var
  dict: TDictionary<string, Tlist<TStation>>;
begin
  if not _Dict_CityID_Xian_Station.TryGetValue(city_id, dict) then
  begin
    list := nil;
    exit;
  end;
  if not dict.TryGetValue(xian, list) then
  begin
    list := nil;
    exit;
  end;
end;

procedure TR_Manager.load_City(fn: string);
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  load_City_sl(sl);
  FreeAndNil(sl);
end;

procedure TR_Manager.load_City_sl(sl: TStringList);
var
  i, pid: Integer;
  ss: TArray<String>;
  c: TCity;
  p: TProvince;
begin
  _Dict_City.Clear();
  _Dict_City_Name.Clear();
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 3 then
    begin
      c := TCity.Create;
      c.ID := strtointdef(ss[0], 0);
      c.Name := ss[1];
      if length(ss) = 4 then
      begin
        c.Code := strtointdef(ss[2], 0);
        c.TelCode := strtointdef(ss[3], 0);
        pid := get_Province_ID_from_City_Code(c.Code);
      end
      else
      begin
        pid := strtointdef(ss[2], 0);
      end;
      p := get_Province_by_id(pid);
      if p <> nil then
      begin
        p.CityList.Add(c);
        _Dict_City.AddOrSetValue(c.ID, c);
        _Dict_City_Name.AddOrSetValue(p.Name + c.Name, c);
      end;
      c.Province := p;
    end;
    SetLength(ss, 0);
  end;
end;

procedure TR_Manager.load_County(fn: string);
var
  i, pid: Integer;
  sl: TStringList;
  ss: TArray<String>;
  city: TCity;
  county: TCounty;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 2 then
    begin
      county := TCounty.Create;
      county.CityID := strtointdef(ss[0], 0);
      county.Name := ss[1];
      city := get_City_by_id(pid);
      if city <> nil then
      begin
        city.CountyList.Add(county);
      end;
    end;
    SetLength(ss, 0);
  end;
  FreeAndNil(sl);
end;

procedure TR_Manager.load_Path(fn: string);
var
  i, m: Integer;
  sl: TStringList;
  ss: TArray<String>;
  s_begin, s_end: TStation;
  sp: TStation_Path;
begin
  clear_StationList;
  clear_StationPathList;
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 5 then
    begin
      get_or_add_Station(ss[0], ss[1], ss[2]);
    end;
    SetLength(ss, 0);
  end;
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 5 then
    begin
      if (_Dict_Station.TryGetValue(ss[2], s_begin)) and
        (_Dict_Station.TryGetValue(ss[5], s_end)) then
      begin
        m := Round(strtointdef(ss[3], 0));
        if m > 0 then
        begin
          sp := TStation_Path.Create;
          sp.Station_Begin := s_begin;
          sp.Station_End := s_end;
          sp.Mileage := m;
          _StationPathList.Add(sp);
        end
        else
        begin

        end;
      end
      else
      begin

      end;
    end;
    SetLength(ss, 0);
  end;
  FreeAndNil(sl);
  make_StationPathNodeList();
end;

procedure TR_Manager.load_Path_new(fn: string);
var
  sl: TStringList;
begin
  // 2016-10-03
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  load_Path_new_sl(sl);
  FreeAndNil(sl);
end;

procedure TR_Manager.load_Path_new_sl(sl: TStringList);
var
  i, m: Integer;
  ss: TArray<String>;
  s_begin, s_end: TStation;
  sp: TStation_Path;
begin
  // 2016-10-03
  clear_StationList;
  clear_StationPathList;
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 6 then
    begin
      get_or_add_Station_new(ss[0], ss[1], ss[2]);
    end;
    SetLength(ss, 0);
  end;

  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 5 then
    begin
      if (_Dict_Station.TryGetValue(ss[1], s_begin)) and
        (_Dict_Station.TryGetValue(ss[5], s_end)) then
      begin
        m := Round(strtointdef(ss[3], 0));
        if m > 0 then
        begin
          sp := TStation_Path.Create;
          sp.Station_Begin := s_begin;
          sp.Station_End := s_end;
          sp.Mileage := m;
          _StationPathList.Add(sp);
        end
        else
        begin

        end;
      end
      else
      begin

      end;
    end;
    SetLength(ss, 0);
  end;
  make_StationPathNodeList();
end;

procedure TR_Manager.load_Province(fn: string);
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  load_Province_sl(sl);
  FreeAndNil(sl);
end;

procedure TR_Manager.load_Province_sl(sl: TStringList);
var
  i: Integer;
  ss: TArray<String>;
  p: TProvince;
begin
  clear_ProvinceList();
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 2 then
    begin
      p := TProvince.Create;
      p.ID := strtointdef(ss[0], 0);
      p.Name := ss[1];
      if length(ss) >= 3 then
        p.CardCode := ss[2];
      _ProvinceList.Add(p);
      _Dict_Province.AddOrSetValue(p.ID, p);
    end;
    SetLength(ss, 0);
  end;
end;

procedure TR_Manager.load_xian(fn: string); // hfg 2016-07-23
var
  i: Integer;
  sl: TStringList;
  ss: TArray<String>;
  Station: TStation;
  dict: TDictionary<string, Tlist<TStation>>;
  list: Tlist<TStation>;
  pair: TPair<string, TStation>;
  procedure set_xian(v: string);
  begin
    if Station.xian = '' then
      Station.xian := v;
  end;

begin
  clear_Dict_CityID_Xian_Station();
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) = 2 then
    begin
      if _Dict_Station.TryGetValue(ss[0], Station) then
      begin
        set_xian(ss[1]);
      end;
    end;
    SetLength(ss, 0);
  end;
  for pair in _Dict_Station do
  begin
    Station := pair.Value;
    if Station.xian <> '' then
    begin
      if not _Dict_CityID_Xian_Station.TryGetValue(Station.CityID, dict) then
      begin
        dict := TDictionary < string, Tlist < TStation >> .Create();
        _Dict_CityID_Xian_Station.AddOrSetValue(Station.CityID, dict);
      end;
      if not dict.TryGetValue(Station.xian, list) then
      begin
        list := Tlist<TStation>.Create();
        dict.AddOrSetValue(Station.xian, list);
      end;
      list.Add(Station);
    end;
  end;
  FreeAndNil(sl);
end;

procedure TR_Manager.make_StationPathNodeList;
var
  i, cid: Integer;
  p, p2: TStation_Path_Node;
  c_list: Tlist<TStation_Path_Node>;
begin
  _Node_Tmp.Clear();
  clear_StationPathNodeList();
  for i := 0 to _StationList.Count - 1 do
  begin
    p := TStation_Path_Node.Create;
    p.Station := _StationList[i];
    _Dict_Station_Path_Node.AddOrSetValue(p.Station, p);
    _StationPathNodeList.Add(p);
    _Node_Tmp.Add(nil);
    _Node_Tmp_2.Add(nil);
    _Node_Tmp_before_end.Add(nil);
    cid := _StationList[i].CityID;
    if not _Dict_CityID_Path_Node.TryGetValue(cid, c_list) then
    begin
      c_list := Tlist<TStation_Path_Node>.Create;
      _Dict_CityID_Path_Node.AddOrSetValue(cid, c_list);
    end;
    c_list.Add(p);
  end;
  for i := 0 to _StationPathList.Count - 1 do
  begin
    if (_Dict_Station_Path_Node.TryGetValue(_StationPathList[i].Station_Begin,
      p)) and (_Dict_Station_Path_Node.TryGetValue(_StationPathList[i]
      .Station_End, p2)) then
    begin
      p.add_next(p2, _StationPathList[i].Mileage);
      p2.add_Prior(p, _StationPathList[i].Mileage);
    end;
  end;

end;

procedure TR_Manager.save_Station(fn: string);
var
  i: Integer;
  sl: TStringList;
  s: string;
  Station: TStation;
begin
  sl := TStringList.Create;
  for i := 0 to _StationList.Count - 1 do
  begin
    Station := _StationList[i];
    if i = 0 then
      s := 'select ' + Station.CityID.ToString() + ' as  CityID,' +
        QuotedStr(Station.Name) + ' as station'
    else
      s := 'union select ' + Station.CityID.ToString() + ',' +
        QuotedStr(Station.Name);
    sl.Add(s);
  end;
  sl.SaveToFile(fn);
end;

{ TProvince }

procedure TProvince.clear_CityList;
var
  i: Integer;
begin
  for i := 0 to _CityList.Count - 1 do
    _CityList[i].Free;
  _CityList.Clear();
end;

constructor TProvince.Create;
begin
  _CityList := Tlist<TCity>.Create();
end;

destructor TProvince.Destroy;
begin
  clear_CityList();
  FreeAndNil(_CityList);
  inherited;
end;

{ TCity }

procedure TCity.clear_CountyList;
var
  i: Integer;
begin
  for i := 0 to _CountyList.Count - 1 do
    _CountyList[i].Free;
  _CountyList.Clear();
end;

constructor TCity.Create;
begin
  _CountyList := Tlist<TCounty>.Create();
end;

destructor TCity.Destroy;
begin
  clear_CountyList();
  FreeAndNil(_CountyList);
  inherited;
end;

{ TCounty }

constructor TCounty.Create;
begin
  //
end;

destructor TCounty.Destroy;
begin

  inherited;
end;

{ TStation }

constructor TStation.Create;
begin
  //
end;

destructor TStation.Destroy;
begin

  inherited;
end;

{ TStation_Path }

constructor TStation_Path.Create;
begin
  //
end;

destructor TStation_Path.Destroy;
begin

  inherited;
end;

{ TStation_Path_Node }

procedure TStation_Path_Node.add_next(next_node: TStation_Path_Node;
  Mileage: Integer);
var
  n: TStation_Next;
begin
  n := TStation_Next.Create;
  n.Station_Node_Next := next_node;
  n.Mileage := Mileage;
  _Next_Station.Add(n);
end;

procedure TStation_Path_Node.add_Prior(p_node: TStation_Path_Node;
  Mileage: Integer);
var
  n: TStation_Next;
begin
  n := TStation_Next.Create;
  n.Station_Node_Next := p_node;
  n.Mileage := Mileage;
  _Prior_Station.Add(n);
end;

procedure TStation_Path_Node.clear_Next_Station;
var
  i: Integer;
begin
  for i := 0 to _Next_Station.Count - 1 do
    _Next_Station[i].Free;
  _Next_Station.Clear;
end;

procedure TStation_Path_Node.clear_Prior_Station;
var
  i: Integer;
begin
  for i := 0 to _Prior_Station.Count - 1 do
    _Prior_Station[i].Free;
  _Prior_Station.Clear;
end;

constructor TStation_Path_Node.Create;
begin
  _path_mileage := 0;
  _is_on_path := false;
  _step := -1;
  _Next_Station := Tlist<TStation_Next>.Create();
  _Prior_Station := Tlist<TStation_Next>.Create();
end;

destructor TStation_Path_Node.Destroy;
begin
  clear_Next_Station();
  FreeAndNil(_Next_Station);
  clear_Prior_Station();
  FreeAndNil(_Prior_Station);
  inherited;
end;

procedure TStation_Path_Node.reset;
begin
  _is_on_path := false;
  _is_end := false;
  _step := -1;
  _is_before_end := false;
  _path_mileage := 0;
  _Path_Prior_Station := nil;
end;

procedure TStation_Path_Node.set_is_before_end;
var
  i: Integer;
begin
  _is_end := True;
  for i := 0 to _Prior_Station.Count - 1 do
  begin
    if (_Prior_Station[i].Station_Node_Next.is_before_end) then
      if _Prior_Station[i].Station_Node_Next._to_end_mileage < _Prior_Station[i]
        ._Mileage then
        Continue;

    _Prior_Station[i].Station_Node_Next._is_before_end := True;
    _Prior_Station[i].Station_Node_Next._end_Node := self;
    _Prior_Station[i].Station_Node_Next._to_end_mileage :=
      _Prior_Station[i]._Mileage;
  end;
end;

procedure TStation_Path_Node.set_Step(v: Integer);
begin
  _step := v;
  _is_on_path := True;
end;

{ TStation_Next }

constructor TStation_Next.Create;
begin
  //
end;

destructor TStation_Next.Destroy;
begin

  inherited;
end;

{ TR_Path }

constructor TR_Path.Create;
begin
  StationList := Tlist<TStation>.Create();
end;

destructor TR_Path.Destroy;
begin
  FreeAndNil(StationList);
  inherited;
end;

function TR_Path.get_txt: string;
var
  i: Integer;
begin
  Result := '';
  for i := 0 to StationList.Count - 1 do
  begin
    if i > 0 then
      Result := Result + ' -> ';
    Result := Result + StationList[i].Name;
  end;
  Result := Result + ' (' + IntToStr(Mileage) + ')'
end;

function TR_Path.get_txt_with_city: string;
var
  i: Integer;
begin
  Result := '';
  for i := 0 to StationList.Count - 1 do
  begin
    if i > 0 then
      Result := Result + '>';
    Result := Result + StationList[i].CityID.ToString() + '|' +
      StationList[i].Name;
  end;
  Result := Result + ':' + IntToStr(Mileage)
end;

end.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943356.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STL格式转换为GLTF格式

STL与GLTF格式简介 STL格式 STL&#xff08;Stereo Lithography&#xff09;文件是一种广泛使用的3D打印文件格式&#xff0c;由3D Systems公司开发。它主要用于存储三维物体的几何信息&#xff0c;常用于立体光刻等3D打印技术。STL文件通常只包含物体的表面几何形状&#xf…

DevOps实战:用Kubernetes和Argo打造自动化CI/CD流程(1)

DevOps实战&#xff1a;用Kubernetes和Argo打造自动化CI/CD流程&#xff08;1&#xff09; 架构 架构图 本设计方案的目标是在一台阿里云ECS服务器上搭建一个轻量级的Kubernetes服务k3s节点&#xff0c;并基于Argo搭建一套完整的DevOps CI/CD服务平台&#xff0c;包括Argo CD…

数据结构经典算法总复习(下卷)

第五章:树和二叉树 先序遍历二叉树的非递归算法。 void PreOrderTraverse(BiTree T, void (*Visit)(TElemType)) {//表示用于查找的函数的指针Stack S; BiTree p T;InitStack(S);//S模拟工作栈while (p || !StackEmpty(S)) {//S为空且下一个结点为空&#xff0c;意味着结束遍…

前端知识补充—CSS

CSS介绍 什么是CSS CSS(Cascading Style Sheet)&#xff0c;层叠样式表, ⽤于控制⻚⾯的样式 CSS 能够对⽹⻚中元素位置的排版进⾏像素级精确控制, 实现美化⻚⾯的效果. 能够做到⻚⾯的样式和结构分离 基本语法规范 选择器 {⼀条/N条声明} 1&#xff09;选择器决定针对谁修改…

Spring Security 6 系列之九 - 集成JWT

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级为6.3.0&#xff0c;关键是其风…

【Go】context标准库

文章目录 1. 概述1.1 什么是 Context1.2 设计原理1.3 使用场景1.4 Context 分类核心:Context接口2. 源码解读4个实现emptyCtxTODO 和 BackgroundcancelCtxWithCancelcancelCtx.propagateCancel 构建父子关联parentCancelCtx 获取父上下文中的内嵌cancelCtxcanceltimerCtxWithT…

Windows和Linux安全配置和加固

一.A模块基础设施设置/安全加固 A-1.登录加固 1.密码策略 a.最小密码长度不少于8个字符&#xff0c;将密码长度最小值的属性配置界面截图。 练习用的WindowsServer2008,系统左下角开始 > 管理工具 > 本地安全策略 > 账户策略 > 密码策略 > 密码最小长度&#…

webrtc-internals调试工具

Google 的 Chrome&#xff08;87 或更高版本&#xff09;WebRTC 内部工具是一套内置于 Chrome 浏览器中的调试工具; webrtc-internals 能够查看有关视频和音频轨道、使用的编解码器以及流的一般质量的详细信息。这些知识对于解决音频和视频质量差的问题非常有帮助。 webrtc-int…

MT6765核心板_MTK6765安卓核心板规格参数_联发科MTK模块开发

MTK6765安卓核心板是基于联发科高效八核处理器平台开发的一款强大硬件解决方案。这款核心板的核心是采用12纳米工艺打造的MTK6765 CPU&#xff0c;具备四个主频高达2.3GHz的CORTEX-A53核心和四个主频为1.8GHz的CORTEX-A53核心&#xff0c;提供了卓越的处理性能。用户可以根据需…

Linux Shell 脚本编程基础知识篇—shell 运算命令详解

ℹ️大家好&#xff0c;我是练小杰&#xff0c;本文继续Linux shell脚本编程的基础知识内容&#xff0c;接着讲算术运算命令的详细操作~~ 复习&#xff1a;【shell简介以及基本操作】 更多Linux 相关内容请点击&#x1f449;“Linux专栏”~ 文章目录 let运算命令的用法let 的高…

Nginx单向链表 ngx_list_t

目录 基本概述 数据结构 接口描述 具体实现 ngx_list_create ngx_list_init ngx_list_push 使用案例 整理自 nginx 1.9.2 源码 和 《深入理解 Nginx&#xff1a;模块开发与架构解析》 基本概述 Nginx 中的 ngx_list_t 是一个单向链表容器&#xff0c;链表中的每一个节…

KVM虚拟机管理脚本

思路&#xff1a; 在/opt/kvm下创建一个磁盘文件&#xff0c;做差异镜像&#xff0c;创建一个虚拟机配置文件&#xff0c;做虚拟机模版 [rootnode01 ~]# ls /opt/kvm/ vm_base.qcow2 vm_base.xml创建虚拟机的步骤&#xff1a;首先创建虚拟机的差异镜像&#xff0c;然后复制虚…

芯片Tapeout power signoff 之IR Drop Redhawk Ploc文件格式及其意义

数字IC后端工程师在芯片流程最后阶段都会使用redhawk或voltus进行设计的IR Drop功耗signoff分析。必须确保静态&#xff0c;动态ir drop都符合signoff标准。 在做redhawk ir drop分析前&#xff0c;我们需要提供一个redhawk ploc供电点坐标。 数字IC设计后端实现前期预防IR D…

流批一体向量化计算引擎 Flex 在蚂蚁的探索和实践

编者按&#xff1a;Flex是蚂蚁数据部自研的一款流批一体的向量化引擎&#xff0c;Flex是Fink和Velox的全称&#xff0c;也是Flexible的前缀&#xff0c;被赋予了灵活可插拔的寓意。本文将重点从向量化技术背景、Flex架构方案和未来规划三个方面展开论述。 作者介绍&#xff1a;…

Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集I-FGSSM介绍I-FGSSM代码实现I-FGSSM算法实现攻击效果 代码汇总ifgssm.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器&#xff1a; Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch…

全面Kafka监控方案:从配置到指标

文章目录 1.1.监控配置1.2.监控工具1.3.性能指标系统相关指标GC相关指标JVM相关指标Topic相关指标Broker相关指标 1.4.性能指标说明1.5.重要指标说明 1.1.监控配置 开启JMX服务端口&#xff1a;kafka基本分为broker、producer、consumer三个子项&#xff0c;每一项的启动都需要…

HTML制作一个普通的背景换肤案例2024版

一&#xff0c;完整的代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>换肤</t…

《计算机组成及汇编语言原理》阅读笔记:p86-p115

《计算机组成及汇编语言原理》学习第 6 天&#xff0c;p86-p115 总结&#xff0c;总计 20 页。 一、技术总结 1.if statement 2.loop 在许多编程语言中&#xff0c;有类种循环&#xff1a;一种是在程序开头检测条件(test the condition),另一种是在程序末尾检测条件。 3.C…

CSS(三)盒子模型

目录 Content Padding Border Margin 盒子模型计算方式 使用 box-sizing 属性控制盒子模型的计算 所有的HTML元素都可以看作像下图这样一个矩形盒子&#xff1a; 这个模型包括了四个区域&#xff1a;content&#xff08;内容区域&#xff09;、padding&#xff08;内边距…

MySQL外键类型与应用场景总结:优缺点一目了然

前言&#xff1a; MySQL的外键简介&#xff1a;在 MySQL 中&#xff0c;外键 (Foreign Key) 用于建立和强制表之间的关联&#xff0c;确保数据的一致性和完整性。外键的作用主要是限制和维护引用完整性 (Referential Integrity)。 主要体现在引用操作发生变化时的处理方式&…