2

タスクスケジューラに似たものを書いています。私には2つのタスクのセットがあり、いくつかは固定されており(開始と終了の日時が与えられています)、いくつかは固定されていません(開始日時と期間が与えられています)。

非固定タスクは固定タスクの影響を受けるため、非固定タスクが固定タスクとオーバーラップする場合、非固定タスクはオーバーラップの量だけその期間を延長します。

最初の項目が開始日で、2番目の項目がその固定タスクのIDであるタプルのリストから始めます。たとえば、次のようになります。

[(2012-04-30, 1), (2012-05-01, 5), (2012-05-04, 2)]

次に、固定されていないタスクの、ユーザーによって順序付けられた別のリストがあります。アイデアは、このリストをループし、そのループ内で最初のリストをループして、このタスクと重複する可能性のあるタスクを見つけ、固定されていないタスクをどれだけ拡張するかを判断できるようにすることです。 。

これが私があなたの助けを求めているところです。この非固定タスクの計算された開始時間と終了時間がわかったので、残りの非固定タスクに影響を与えるように、それを「固定」と見なす必要があります。

このタスクを固定タスクの最初のリストに追加して再度並べ替えることができますが、これは、タスクを追加するたびにリストを並べ替えることを意味します。

最初のリストをループして、このタスクを挿入するポイントを見つけて、そこに挿入できます。ただし、その場所がリストの早い段階にある場合は、他のすべてのアイテムを1つの場所に移動するために時間がかかります。そして、その場所がリストの後半にある場合、正しい場所に到達するために多くの要素をループする必要があります。

ですから、私はこれらのオプションのどちらを使用しても売られていません。ここでの本当の質問は、リストに物を追加している間、リストをソートしておくための最良の方法は何ですか?それとも、これらすべてを行うためのはるかに優れた方法がありますか?

4

4 に答える 4

3

これは、bisectを使用した例と、部分的にソートされたリストのソートを使用した場合の比較です。二分法の解決策は明らかに勝ちます:

import bisect
import random
import timeit


def bisect_solution(size=10000):
    lst = []
    for n in xrange(size):
        value = random.randint(1, 1000000)
        bisect.insort_left(lst, value)
    return lst


# Cut out of the bisect module to be used in bisect_solution2()
def insort_left(a, x, lo=0, hi=None):
    """Insert item x in list a, and keep it sorted assuming a is sorted.

    If x is already in a, insert it to the left of the leftmost x.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if a[mid] < x: lo = mid+1
        else: hi = mid
    a.insert(lo, x)


def bisect_solution2(size=10000):
    lst = []
    for n in xrange(size):
        value = random.randint(1, 1000000)
        insort_left(lst, value)
    return lst


def sort_solution(size=10000):
    lst = []
    for n in xrange(size):
        value = random.randint(1, 1000000)
        lst.append(value)
        lst.sort()
    return lst


t = timeit.timeit('bisect_solution()', 'from __main__ import bisect_solution', number = 10)
print "bisect_solution: ", t

t = timeit.timeit('bisect_solution2()', 'from __main__ import bisect_solution2', number = 10)
print "bisect_solution2: ", t

t = timeit.timeit('sort_solution()', 'from __main__ import sort_solution', number = 10)
print "sort_solution: ", t

bisect_solution2()はbisect_solution()とほぼ同じですが、モジュールからコードがコピーされている点が異なります。他の誰かがなぜもっと時間がかかるのか説明する必要があります:)

bisect_solution2()は、タプルを比較できるようにcmp()関数用に変更されます。

それは私のコンピュータで次の結果を示しています:

bisect_solution:  0.637892403587
bisect_solution2:  0.988893038133
sort_solution:  15.3521410901

これは、日付が文字列であるタプルに採用されたバイセクトソリューションです。

import random
import timeit


def random_date_tuple():
    s1 = '{0}-{1:02}-{2:02}'.format(random.randint(2000, 2050),
                                    random.randint(1, 12),
                                    random.randint(1, 31))
    e2 = random.randint(1,50)
    return (s1, e2)


def my_cmp(a, b):
    result = cmp(a[0], b[0])   # comparing the date part of the tuple
    if result == 0:
        return cmp(a[1], b[1]) # comparint the other part of the tuple
    return result


def my_insort_left(a, x, cmp=my_cmp, lo=0, hi=None):
    """The bisect.insort_left() modified for comparison of tuples."""

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if cmp(a[mid], x) < 0: 
            lo = mid+1
        else: 
            hi = mid
    a.insert(lo, x)


def bisect_solution3(size=1000):
    lst = []
    for n in xrange(size):
        value = random_date_tuple()
        my_insort_left(lst, value)
    return lst


def sort_solution(size=1000):
    lst = []
    for n in xrange(size):
        value = random_date_tuple()
        lst.append(value)
        lst.sort(cmp=my_cmp)
    return lst


t = timeit.timeit('bisect_solution3()', 'from __main__ import bisect_solution3', number = 10)
print "bisect_solution3: ", t

t = timeit.timeit('sort_solution()', 'from __main__ import sort_solution', number = 10)
print "sort_solution: ", t

print bisect_solution3()[:10]

ソートソリューションが非常に遅いため、リストサイズが以前の10分の1になっていることに注意してください。それは印刷します:

bisect_solution3:  0.223602245968
sort_solution:  3.69388944301
[('2000-02-01', 20), ('2000-02-13', 48), ('2000-03-11', 25), ('2000-03-13', 43),
 ('2000-03-26', 48), ('2000-05-04', 17), ('2000-06-06', 23), ('2000-06-12', 31),
 ('2000-06-15', 15), ('2000-07-07', 50)]
于 2012-04-24T15:33:53.633 に答える
1

ここでの本当の質問は、リストに物を追加している間、リストをソートしておくための最良の方法は何ですか?

挿入ソートは行く方法です。しかし、あなたはすでにこれを知っているのでそれを気に入らないかもしれません。次にできることはこれです、

  1. 追加中は並べ替えないでください。
  2. アイテムを取得したら、それを並べ替えてキャッシュします。次回要求されたときに前のキャッシュから表示します。
  3. 新しいアイテムが追加されたら、キャッシュを無効にします。

私はPythonプログラマーではありませんが、PHPクラスでいくつかのアイデアを提供できます。

class SortedList(){
    public $list = array();
    private $cached_list;

    public function add($item){
        array_push($this->list, $item);
        $this->sorted = false;
    }
    public function get(){
        if($this->sorted==true){
            return $this->cached_list;
        }

        // sort the array;

        // copying the list to cached list and sort it
        $this->cached_list = $this->list;
        sort($this->cached_list);

        // set the flag
        $this->sorted = true;
        return $this->cached_list
    }

}
于 2012-04-24T14:19:53.300 に答える
1

最初のリストをループして、このタスクを挿入するポイントを見つけて、そこに挿入できます。ただし、その場所がリストの早い段階にある場合は、他のすべてのアイテムを1つの場所に移動するために時間がかかります。そして、その場所がリストの後半にある場合、正しい場所に到達するために多くの要素をループする必要があります。

ソートされたリストに何かを挿入するための適切な場所を見つけることは、バイナリ検索を使用してO(log n)で行うことができます。挿入は引き続きO(n)になります。

O(log n)での挿入と検索を可能にするBツリーのようなより複雑なデータ構造があります。これこれを見てください。

于 2012-04-24T14:31:29.923 に答える
0

ヒープキューはあなたの友達です。ウィキペディアから:

ヒープで一般的に実行される操作は次のとおりです。

  • create-heap:空のヒープを作成します
  • find-max:最大ヒープの最大アイテムを検索します
  • delete-max:最大ヒープのルートノードを削除します
  • 増加キー:最大ヒープ内のキーを更新します
  • 挿入:ヒープに新しいキーを追加します
  • マージ:2つのヒープを結合して、両方のすべての要素を含む有効な新しいヒープを形成します。

組み込みのPythonヒープキュー実装があります。ヒープは、1)最大要素を削除し、2)ヒープの順序を維持するために新しい要素を挿入するために最適化されています。

于 2012-04-24T14:28:40.683 に答える