在c ++中合并8个排序列表,我应该使用哪种算法

时间:2009-05-20 04:49:18

标签: c++ sorting stl merge

我有8个排序列表,我需要合并到1个排序列表中。我不知道这样做的最好方法。我在考虑以下几点:

void merge_lists_inplace(list<int>& l1, const list<int>& l2)
{
    list<int>::iterator end_it = l1.end();
    --end_it;
    copy(l2.begin(), l2.end(), back_inserter(l1));
    ++end_it;
    inplace_merge(l1.begin(), end_it, l1.end());
}

list<int> merge_8_lists(list<int>[8] lists)
{
    merge_lists_inplace(lists[0], lists[1]);
    merge_lists_inplace(lists[2], lists[3]);
    merge_lists_inplace(lists[4], lists[5]);
    merge_lists_inplace(lists[6], lists[7]);

    merge_lists_inplace(lists[0], lists[2]);
    merge_lists_inplace(lists[4], lists[6]);

    merge_lists_inplace(lists[0], lists[4]);

    return lists[0];
}

但是最后担心排序会不会更好?

list<int> merge_8_lists(list<int>[8] lists)
{
    for (int i = 1; i < 8; ++i)
        copy(lists[i].begin(), lists[i].end(), back_inserter(lists[0]));        
    lists[0].sort();
    return lists[0];
}

附注:我并不关心列表是否被修改。

6 个答案:

答案 0 :(得分:15)

合并排序的合并阶段的简单扩展可以在O(n lg m)时间内执行此操作(其中n =项目总数,m =列表数量),使用priority queue(例如,a { {3}})。伪代码:

Let P = a priority queue of the sorted lists, sorted by the smallest element in each list
Let O = an empty output list
While P is not empty:
  Let L = remove the minimum element from P
  Remove the first element from L and add it to O
  If L is not empty, add L to P

C ++中一个简单的(未经测试的)具体实现:

#include <list>
#include <set>

template<typename T>
struct cmp_list {
    bool operator()(const std::list<T> *a, const std::list<T> *b) const {
        return a->front() < b->front();
    }
};

template<typename T>
void merge_sorted_lists(std::list<T> &output, std::list<std::list<T> > &input)
{
    // Use a std::set as our priority queue. This has the same complexity analysis as
    // a heap, but has a higher constant factor.
    // Implementing a min-heap is left as an exercise for the reader,
    // as is a non-mutating version
    std::set<std::list<T> *, cmp_list<T> > pq;

    for ( typename std::list<std::list<T> >::iterator it = input.begin();
            it != input.end(); it++)
    {
        if (it->empty())
            continue;
        pq.insert(&*it);
    }

    while (!pq.empty()) {
        std::list<T> *p = *pq.begin();
        pq.erase(pq.begin());

        output.push_back(p->front());
        p->pop_front();

        if (!p->empty())
            pq.insert(p);
    }
}

答案 1 :(得分:2)

您可以尝试一次将合并排序应用于每个列表:

http://en.wikipedia.org/wiki/Merge_sort

这有合并排序的算法。基本上你会使用列表1和2并合并排序。然后你将获取新的组合列表并使用列表3进行排序,这将一直持续到你有一个完全排序的列表。

编辑:

实际上,因为您的列表已经排序,所以只需要合并排序的最后部分。我会迭代地将列表组合成更大和更大的部分,同时对每个更大的列表进行排序,直到你有完整的列表,这实际上是合并排序在完成其分而治之的方法后所做的。

答案 2 :(得分:2)

如果不考虑性能,我会最后对列表进行排序。代码更具可读性,更短,并且不太可能被未来重新访问代码的人搞砸。

答案 3 :(得分:1)

这是一种标准(虽然是8路)合并排序。

基本上你“打开”八个排序列表然后开始处理它们,每次提取最低值,如:

# Open all lists.

open newlist for write
for i = 1 to 8:
    open list(i) for read
end for

# Process forever (break inside loop).

while true:
    # Indicate that there's no lowest value.

    smallidx = -1

    # Find lowest value input list.

    for i = 1 to 8:
        # Ignore lists that are empty.

        if not list(i).empty:
            # Choose this input list if it's the first or smaller
            #  than the current smallest.

            if smallidx = 1:
                smallidx = i
                smallval = list(i).peek()
            else:
                if list(i).peek() < smallval:
                    smallidx = i
                    smallval = list(i).peek()
                end if
            end if
        end if
    end for

    # No values left means stop processing.

    if smallidx = -1:
        exit while
    end if

    # Transfer smallest value then continue.

    smallval = list(smallidx).get()
    newlist.put(smallval)
end while

答案 4 :(得分:0)

你想要a merge sort。您的列表已经拆分,但不是一直到最小的级别。你可能想这样做:

unsorted_list = concatenate(list[0], list[1], list[2], ... , list[7]);
sorted_list = merge_sort(unsorted_list);

这不应该是消耗时间/内存的操作,因为连接应该从列表中的最后一个节点添加到下一个列表的第一个元素的链接。

答案 5 :(得分:0)

基本上你正在做多路合并的一部分,除了你的东西已经排序了......

http://lcm.csa.iisc.ernet.in/dsa/node211.html

找到每个数组中的最低值(几乎用作堆栈)并将其放在输出中直到所有堆栈都为空...