(ID1, ID2, timestamp)
他のIDの前にどのIDをソートするかを決定するタプルの配列である「ソートマップ」に基づいてIDのリストをソートしようとしています。ルールは次のとおりです。
ID1
の前にソートする必要がありますID2
。- タイムスタンプを使用して、古いタイムスタンプを上回る新しいタイムスタンプとの関係を断ち切ることができます。たとえば、指定された並べ替えキーは
(C, A, 1/1/1900), (C, B, 1/1/2000)
、B
の前に並べ替えられますA
。 - サイクルが存在する可能性があります
(A, B, 1/1/1950), (B, C, 1/1/1980), (C, A, 1/1/1900)
。タイムスタンプを使用してサイクルを中断できます。サイクル内のタイムスタンプが古いレコードは、サイクルがなくなるまでソートマップから削除されます。 - IDが並べ替えマップに存在しない場合、並べ替えマップに存在するIDの後に並べ替えられます
例:並べ替えマップ(C, A, 1/1/1900), (C, B, 1/1/2000)
と並べ替えるリスト(A, B, C, D)
を指定すると、並べ替えられた出力はになります(C, B, A, D)
。
これらのルールをアルゴリズムに変えることに困惑しています。これが私がこれまでに持っているものです:
データベースから最新のソートマップを取得します。IDの一意のペアごとに最大で1つのレコードを取得します。
ソートマップからサイクルを削除します。どのように?または、ステップ4の一部としてサイクルを単に無視する方が簡単ですか?
最適なパフォーマンスを得るために、メモリ内の並べ替えマップを変換します。たとえば、特定のIDを含むすべての並べ替えマップの行をすばやく見つけることができるように、並べ替えマップ内の一意のIDをキーとするハッシュテーブルを作成します。
ID1
任意の2つのIDとID2
パラメーターを受け入れるカスタム比較関数を使用して、汎用のバイナリソートライブラリを使用してIDの配列をソートします。比較関数:a。手順3のハッシュテーブルを含む
ID1
または使用しているすべての並べ替えマップエントリを検索します。ID2
b。
ID1
との両方を含むレコードがすでにID2
ソートマップにある場合は、停止します。どちらが最初であるかがわかります。c。ソートマップにID1もID2も見つからない場合、それは同点です。決定論的に任意の結果を返します(たとえば、IDが低い方が勝ちます)。
d。一方のIDがソートマップに含まれているが、もう一方が含まれていない場合は、停止します。見つかったものを最初にソートする必要があります。
e。ここに到達すると、両方のIDが並べ替えマップにありますが、並べ替えマップで直接比較できるものはありません。それで?
並べ替えマップの最大サイズは2万行未満であり、並べ替えられるIDの最大数は30未満であるため、パフォーマンスは大きな問題ではありません。
アイデアがありますか?
FWIWでは、.NETを使用List<T>.Sort(Comparison<T>)
してC#で並べ替えを行いますが、基盤となるアルゴリズムは明らかに言語やプラットフォームに依存しません。
興味がある場合は、このアルゴリズムの実際の必要性を次に示します。
当社は、担当する合計100〜150の場所の領域から毎日約20の場所を訪れる配達ドライバー向けのモバイルアプリを構築しています。毎日の場所のリストは、各場所の在庫に基づいて動的に割り当てられます。在庫が少ない場所では新しい在庫が配信されますが、在庫がまだ十分ある場所にはアクセスされません。
ドライバーは任意の順序で場所を自由に訪問できますが、通常は毎日同様のルートを使用します(たとえば、朝の交通量が少ない場合は町の南部の場所を訪問し、交通量が多い場合は町の北部の場所を訪問します)。南)。
最も効率的な運転ルートを自動的に決定するサードパーティのルーティングソフトウェアを使用しないことを選択しました。代わりに、ルーティングソフトウェアは「建物の積み込みドックは通常、午前7時までしか無料ではない」、「配達領収書に署名する必要がある人は早めに出発する」などの制約があるため、ドライバーにルートを選択させる方がよいことがわかりました。配達スケジュールに大きな影響を与える「金曜日」。
とにかく、ドライバーの過去の選択を使用して、ドライバーが前回同じ場所を訪れたのと同じ順序で毎日の旅程を並べ替えたいと思います。これにより、ドライバーは、異常な場合を除いて、スケジュールを手動で再調整することなく、自分の好みに合わせて毎日うまく整理された旅程を得ることができます。これにより、ドライバーは1日1〜2分節約でき、時間の経過とともに合計されます。
各履歴旅程は実際にはこのようなリスト(ID1、ID2、ID3、...、IDN、タイムスタンプ)ですが、過去の何百ものスケジュールを保存する代わりに、各Nマシンの履歴旅程を分解する方が簡単だと思いました。マシンのペアに。これは、新しい順序では常に古いものが並べ替えマップから追い出されるため、最大でN*N-1タプルを格納する必要があることを意味します。これが悪い単純化である場合は、私に知らせてください。;-)