Thuật toán cho hợp nhất N-way


79

Hợp nhất 2 chiều được nghiên cứu rộng rãi như là một phần của thuật toán Mergesort. Nhưng tôi quan tâm đến việc tìm ra cách tốt nhất mà người ta có thể thực hiện hợp nhất N-way?

Giả sử, tôi có Ncác tệp được sắp xếp mỗi tệp 1 triệu số nguyên. Tôi phải hợp nhất chúng thành 1 tệp duy nhất sẽ có 100 triệu số nguyên được sắp xếp đó.

Xin lưu ý rằng trường hợp sử dụng cho vấn đề này thực sự là sắp xếp bên ngoài dựa trên đĩa. Do đó, trong các tình huống thực tế cũng sẽ có giới hạn về bộ nhớ. Vì vậy, một cách tiếp cận ngây thơ là hợp nhất 2 tệp cùng một lúc (99 lần) sẽ không hoạt động. Giả sử chúng ta chỉ có một cửa sổ trượt nhỏ của bộ nhớ cho mỗi mảng.

Tôi không chắc liệu đã có giải pháp chuẩn hóa nào cho việc hợp nhất N-way này chưa. (Googling không cho tôi biết nhiều) .

Nhưng nếu bạn biết liệu thuật toán hợp nhất n-way có tốt không, vui lòng đăng algo / link.

Độ phức tạp về thời gian: Nếu chúng tôi tăng số lượng tệp ( N) được hợp nhất lên rất nhiều , điều đó sẽ ảnh hưởng đến độ phức tạp về thời gian của thuật toán của bạn như thế nào?

Cảm ơn câu trả lời của bạn.

Tôi chưa từng được hỏi điều này ở bất cứ đâu, nhưng tôi cảm thấy đây có thể là một câu hỏi phỏng vấn thú vị. Do đó được gắn thẻ.


Tại sao việc hợp nhất các tệp theo cặp không hoạt động?

8
Đối với bản ghi, đây được gọi là đường cân bằng hoặc hợp nhất k-way. Các thuật toán đường cân bằng thường có độ phức tạp thời gian O (kn) trong đó k là số tệp và n là tổng số mục, trong khi hợp nhất theo k-chiều thường là O (n log k). Cả hai thuật toán đều có độ phức tạp không gian O (k).

@paul, ok Tôi phải thừa nhận rằng tôi đã sai khi nói rằng việc hợp nhất 2 tệp cùng một lúc sẽ không hoạt động do cân nhắc về dung lượng. Nhưng tôi nghĩ rằng nó sẽ là một thuật toán rất chậm, đó là lý do tại sao nó sẽ không hoạt động.
bit

@Bavarious bạn có thể nói tại sao bạn nghĩ hợp nhất như thế này là O (kn). Đối với tôi, có vẻ như nó là O (n log k) (vì hợp nhất mỗi cặp là O (n) và bạn phải làm điều đó O (log k) lần để giảm xuống một tệp duy nhất). Nó cũng chỉ sử dụng không gian O (1).

@PaulHankin Dòng số dư giữ một mảng chưa được sắp xếp (thay vì một đống) với khóa cuối cùng được đọc từ mỗi tệp đầu vào, do đó k trong cả O (kn) và O (k). Nó là đủ tốt cho k nhỏ.

Câu trả lời:


79

Làm thế nào về ý tưởng sau đây:

  1. Tạo hàng đợi ưu tiên

  2. Lặp lại từng tệp f
    1. xếp hàng cặp (nextNumberIn (f), f) bằng cách sử dụng giá trị đầu tiên làm khóa ưu tiên

  3. Trong khi hàng đợi không trống
    1. đầu dequeue (m, f) của hàng đợi
    2. đầu ra m
    3. nếu e không cạn kiệt
      1. enqueue (nextNumberIn (f), f)

Vì việc thêm các phần tử vào hàng đợi ưu tiên có thể được thực hiện theo thời gian logarit nên mục 2 là O (N × log N) . Vì (hầu như tất cả) các lần lặp của vòng lặp while đều thêm một phần tử nên toàn bộ vòng lặp while là O (M × log N) trong đó M là tổng số các số cần sắp xếp.

Giả sử tất cả các tệp đều có một dãy số không rỗng, chúng ta có M> N và do đó toàn bộ thuật toán sẽ là O (M × log N) .


Rât gọn gang. Tôi đã suy nghĩ về những dòng tương tự, ngoại trừ việc ghép số với tệp không xảy ra với tôi. Cảm ơn. Đang chấp nhận.
bit

1
@aioobe: Sự thận trọng của bạn là gọn gàng nhưng bạn đang thực hiện rất nhiều cuộc gọi đã đọc có thể ảnh hưởng đến hiệu quả. Ví dụ, trong mục 3, đối với mỗi lần lặp while, bạn thực hiện lệnh đọc cho phần tử tiếp theo trong f. Tôi nghĩ sẽ tốt hơn nếu bạn thay đổi điều kiện if thành sau: if f không có trong hàng đợi và f không bị cạn kiệt. Bằng cách này, bạn sẽ chỉ đọc nếu không có phần tử nào của f trong hàng đợi. Hơn nữa, khi bạn thực hiện việc đọc này, bạn có thể đọc một lượng lớn các số trong f cùng một lúc.
Lập trình viên

7
" if f not present in queue ", nó không bao giờ hiện diện sau khi dequeue vì luôn có nhiều nhất một giá trị từ mỗi tệp có trong hàng đợi. Về nhận xét thứ hai của bạn: Đề xuất của bạn không cải thiện độ phức tạp (ngoại trừ việc nó làm cho câu trả lời phức tạp hơn để đọc!) Bên cạnh đó, hãy nhớ rằng đây là mã giả. Nó rất có thể được triển khai với một số trình đọc đệm đọc các phần lớn hơn và lưu chúng vào bộ nhớ đệm.
aioobe

2
@Programmer, tôi nghĩ bạn có một điểm tốt về số lần đọc, nhưng bạn không thực sự phải triển khai "if f not present in queue"; bạn có thể chỉ cần đệm f và sử dụng thuật toán của aioobe, đọc các giá trị của f thông qua bộ đệm.
enobayram

1
@ RestlessC0bra, không, bước hai chèn số đầu tiên vào mỗi tệp. Trong bước 3 (vòng lặp while) một giá trị được xếp lại hàng và giá trị tiếp theo từ tệp đó được xếp vào hàng (trừ khi tệp đó bị cạn). Vẫn chưa rõ?
aioobe

12

Tìm kiếm "Hợp nhất nhiều pha", xem tác phẩm kinh điển - Donald Knuth & EHFriend.

Ngoài ra, bạn có thể muốn xem phần Hợp nhất khối thông minh được đề xuất bởi Seyedafsari & Hasanzadeh, tương tự như các đề xuất trước đó, sử dụng hàng đợi ưu tiên.

Một lý do thú vị khác là Thuật toán Sáp nhập Tại chỗ của Kim & Kutzner.

Tôi cũng giới thiệu bài báo này của Vitter: Thuật toán bộ nhớ ngoài và cấu trúc dữ liệu: xử lý dữ liệu lớn .


2
Liên kết Hợp nhất khối thông minh của bạn không đúng. Đó là một số bài báo về chuỗi cung ứng ở Estonia.
Jeremy Salwen

Jeremy, cảm ơn vì đã chỉ ra. Vào năm 2012, máy chủ waset.org dường như đã ghi đè các tệp này (ban đầu, được xuất bản vào năm 2010) bằng các kỷ yếu hội nghị mới. Tôi không thể tìm thấy bài viết cũ. Nếu ai có nó, xin vui lòng đăng / liên kết.
Grigori Melnik

1
Đây là liên kết mới: waset.org/publications/9638/…
Hengameh

6

Một ý tưởng đơn giản là giữ một hàng đợi ưu tiên của các phạm vi để hợp nhất, được lưu trữ theo cách mà phạm vi có phần tử đầu tiên nhỏ nhất sẽ bị xóa trước khỏi hàng đợi. Sau đó, bạn có thể thực hiện hợp nhất N-way như sau:

  1. Chèn tất cả các phạm vi vào hàng đợi ưu tiên, loại trừ các phạm vi trống.
  2. Trong khi hàng đợi ưu tiên không trống:
    1. Dequeue phần tử nhỏ nhất từ ​​hàng đợi.
    2. Nối phần tử đầu tiên của dải ô này vào chuỗi đầu ra.
    3. Nếu nó không có giá trị nào, hãy chèn phần còn lại của chuỗi vào hàng đợi ưu tiên.

Tính đúng đắn của thuật toán này về cơ bản là sự tổng quát hóa bằng chứng rằng phép hợp nhất 2 chiều hoạt động chính xác - nếu bạn luôn thêm phần tử nhỏ nhất từ ​​bất kỳ phạm vi nào và tất cả các phạm vi được sắp xếp, bạn sẽ có một chuỗi được sắp xếp toàn bộ.

Độ phức tạp thời gian chạy của thuật toán này có thể được tìm thấy như sau. Gọi M là tổng số phần tử trong tất cả các dãy. Nếu chúng ta sử dụng một đống nhị phân, thì chúng ta thực hiện nhiều nhất là chèn O (M) và xóa O (M) khỏi hàng đợi ưu tiên, vì đối với mỗi phần tử được ghi vào chuỗi đầu ra sẽ có một hàng đợi để kéo ra chuỗi nhỏ nhất, theo sau là một enqueue để đưa phần còn lại của chuỗi trở lại hàng đợi. Mỗi bước trong số các bước này thực hiện các phép toán O (lg N), vì việc chèn hoặc xóa khỏi một đống nhị phân có N phần tử trong đó sẽ mất O (lg N) thời gian. Điều này cho ta thời gian chạy thực là O (M lg N), thời gian này phát triển ít hơn tuyến tính với số lượng trình tự đầu vào.

Có thể có một cách để thực hiện việc này nhanh hơn, nhưng đây có vẻ là một giải pháp khá tốt. Việc sử dụng bộ nhớ là O (N) vì chúng ta cần tổng chi phí O (N) cho heap nhị phân. Nếu chúng ta triển khai đống nhị phân bằng cách lưu trữ các con trỏ đến các trình tự thay vì chính các trình tự, thì điều này không phải là quá nhiều vấn đề trừ khi bạn có một số lượng trình tự thực sự vô lý để hợp nhất. Trong trường hợp đó, chỉ cần hợp nhất chúng theo nhóm phù hợp với bộ nhớ, sau đó hợp nhất tất cả các kết quả.

Hi vọng điêu nay co ich!


2

Một cách tiếp cận đơn giản để Hợp nhất k mảng đã sắp xếp (mỗi mảng có độ dài n) yêu cầu thời gian O (nk ^ 2) chứ không phải thời gian O (nk). Như khi bạn hợp nhất 2 mảng đầu tiên mất 2n thời gian, sau đó khi bạn hợp nhất thứ ba với đầu ra, mất 3n thời gian vì bây giờ chúng ta đang hợp nhất hai mảng có độ dài 2n và n. Bây giờ khi chúng ta hợp nhất đầu ra này với kết quả thứ tư, quá trình hợp nhất này yêu cầu 4n thời gian. Do đó, lần hợp nhất cuối cùng (khi chúng ta thêm mảng thứ k vào mảng đã được sắp xếp của mình) yêu cầu k * n thời gian. Do đó tổng thời gian cần thiết là 2n + 3n + 4n + ... k * n là O (nk ^ 2).

Có vẻ như chúng ta có thể làm điều đó trong thời gian O (kn) nhưng không phải như vậy vì mỗi lần mảng mà chúng ta đang hợp nhất lại tăng kích thước.
Mặc dù chúng ta có thể đạt được ràng buộc tốt hơn bằng cách sử dụng chia và chinh phục. Tôi vẫn đang làm việc đó và đăng một giải pháp nếu tôi tìm thấy.


1

Xem http://en.wikipedia.org/wiki/External_sorting . Đây là bước của tôi về hợp nhất k-way dựa trên đống, sử dụng đọc được đệm từ các nguồn để mô phỏng giảm I / O:

public class KWayMerger<T>
{
    private readonly IList<T[]> _sources;
    private readonly int _bufferSize;
    private readonly MinHeap<MergeValue<T>> _mergeHeap;
    private readonly int[] _indices;

    public KWayMerger(IList<T[]> sources, int bufferSize, Comparer<T> comparer = null)
    {
        if (sources == null) throw new ArgumentNullException("sources");

        _sources = sources;
        _bufferSize = bufferSize;

        _mergeHeap = new MinHeap<MergeValue<T>>(
                      new MergeComparer<T>(comparer ?? Comparer<T>.Default));
        _indices = new int[sources.Count];
    }

    public T[] Merge()
    {
        for (int i = 0; i <= _sources.Count - 1; i++)
            AddToMergeHeap(i);

        var merged = new T[_sources.Sum(s => s.Length)];
        int mergeIndex = 0;

        while (_mergeHeap.Count > 0)
        {
            var min = _mergeHeap.ExtractDominating();
            merged[mergeIndex++] = min.Value;
            if (min.Source != -1) //the last item of the source was extracted
                AddToMergeHeap(min.Source);
        }

        return merged;
    }

    private void AddToMergeHeap(int sourceIndex)
    {
        var source = _sources[sourceIndex];
        var start = _indices[sourceIndex];
        var end = Math.Min(start + _bufferSize - 1, source.Length - 1);

        if (start > source.Length - 1)
            return; //we're done with this source

        for (int i = start; i <= end - 1; i++)
            _mergeHeap.Add(new MergeValue<T>(-1, source[i]));   

        //only the last item should trigger the next buffered read
        _mergeHeap.Add(new MergeValue<T>(sourceIndex, source[end]));

        _indices[sourceIndex] += _bufferSize; //we may have added less items, 
        //but if we did we've reached the end of the source so it doesn't matter
    } 
}

internal class MergeValue<T>
{
    public int Source { get; private set; }
    public T Value { get; private set; }

    public MergeValue(int source, T value)
    {
        Value = value;
        Source = source;
    }
}

internal class MergeComparer<T> : IComparer<MergeValue<T>>
{
    public Comparer<T> Comparer { get; private set; }

    public MergeComparer(Comparer<T> comparer)
    {
        if (comparer == null) throw new ArgumentNullException("comparer");
        Comparer = comparer;
    }

    public int Compare(MergeValue<T> x, MergeValue<T> y)
    {
        Debug.Assert(x != null && y != null);
        return Comparer.Compare(x.Value, y.Value);
    }
}

Đây là một trong những cách triển khai có thểMinHeap<T> . Một số bài kiểm tra:

[TestMethod]
public void TestKWaySort()
{
    var rand = new Random();
    for (int i = 0; i < 10; i++)
        AssertKwayMerge(rand);
}

private static void AssertKwayMerge(Random rand)
{
    var sources = new[]
        {
            GenerateRandomCollection(rand, 10, 30, 0, 30).OrderBy(i => i).ToArray(),
            GenerateRandomCollection(rand, 10, 30, 0, 30).OrderBy(i => i).ToArray(),
            GenerateRandomCollection(rand, 10, 30, 0, 30).OrderBy(i => i).ToArray(),
            GenerateRandomCollection(rand, 10, 30, 0, 30).OrderBy(i => i).ToArray(),
        };
    Assert.IsTrue(new KWayMerger<int>(sources, 20).Merge().SequenceEqual(sources.SelectMany(s => s).OrderBy(i => i)));
}

public static IEnumerable<int> GenerateRandomCollection(Random rand, int minLength, int maxLength, int min = 0, int max = int.MaxValue)
{
    return Enumerable.Repeat(0, rand.Next(minLength, maxLength)).Select(i => rand.Next(min, max));
}

Ngôn ngữ mã của bạn là gì? (Xin lỗi, tôi là người mới lập trình; tôi đang tìm kiếm một giải pháp Java).
Hengameh

1
@Hengameh đó là C #. Cú pháp rất giống với Java nên không quá khó để dịch nó.
Ohad Schneider

1

Tôi đã viết đoạn mã kiểu STL này hợp nhất N-way và nghĩ rằng tôi sẽ đăng nó ở đây để giúp ngăn người khác phát minh lại bánh xe. :)

Cảnh báo: nó chỉ được thử nghiệm nhẹ. Kiểm tra trước khi sử dụng. :)

Bạn có thể sử dụng nó như thế này:

#include <vector>

int main()
{
    std::vector<std::vector<int> > v;
    std::vector<std::vector<int>::iterator> vout;
    std::vector<int> v1;
    std::vector<int> v2;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v2.push_back(0);
    v2.push_back(1);
    v2.push_back(2);
    v.push_back(v1);
    v.push_back(v2);
    multiway_merge(v.begin(), v.end(), std::back_inserter(vout), false);
}

Nó cũng cho phép sử dụng các cặp vòng lặp thay vì chính các vùng chứa.

Nếu bạn sử dụng Boost.Range, bạn có thể xóa một số mã bảng soạn sẵn.

Mật mã:

#include <algorithm>
#include <functional>  // std::less
#include <iterator>
#include <queue>  // std::priority_queue
#include <utility>  // std::pair
#include <vector>

template<class OutIt>
struct multiway_merge_value_insert_iterator : public std::iterator<
    std::output_iterator_tag, OutIt, ptrdiff_t
>
{
    OutIt it;
    multiway_merge_value_insert_iterator(OutIt const it = OutIt())
        : it(it) { }

    multiway_merge_value_insert_iterator &operator++(int)
    { return *this; }

    multiway_merge_value_insert_iterator &operator++()
    { return *this; }

    multiway_merge_value_insert_iterator &operator *()
    { return *this; }

    template<class It>
    multiway_merge_value_insert_iterator &operator =(It const i)
    {
        *this->it = *i;
        ++this->it;
        return *this;
    }
};

template<class OutIt>
multiway_merge_value_insert_iterator<OutIt>
    multiway_merge_value_inserter(OutIt const it)
{ return multiway_merge_value_insert_iterator<OutIt>(it); };

template<class Less>
struct multiway_merge_value_less : private Less
{
    multiway_merge_value_less(Less const &less) : Less(less) { }
    template<class It1, class It2>
    bool operator()(
        std::pair<It1, It1> const &b /* inverted */,
        std::pair<It2, It2> const &a) const
    {
        return b.first != b.second && (
            a.first == a.second ||
            this->Less::operator()(*a.first, *b.first));
    }
};

struct multiway_merge_default_less
{
    template<class T>
    bool operator()(T const &a, T const &b) const
    { return std::less<T>()(a, b); }
};

template<class R>
struct multiway_merge_range_iterator
{ typedef typename R::iterator type; };

template<class R>
struct multiway_merge_range_iterator<R const>
{ typedef typename R::const_iterator type; };

template<class It>
struct multiway_merge_range_iterator<std::pair<It, It> >
{ typedef It type; };

template<class R>
typename R::iterator multiway_merge_range_begin(R &r)
{ return r.begin(); }

template<class R>
typename R::iterator multiway_merge_range_end(R &r)
{ return r.end(); }

template<class R>
typename R::const_iterator multiway_merge_range_begin(R const &r)
{ return r.begin(); }

template<class R>
typename R::const_iterator multiway_merge_range_end(R const &r)
{ return r.end(); }

template<class It>
It multiway_merge_range_begin(std::pair<It, It> const &r)
{ return r.first; }

template<class It>
It multiway_merge_range_end(std::pair<It, It> const &r)
{ return r.second; }

template<class It, class OutIt, class Less, class PQ>
OutIt multiway_merge(
    It begin, It const end, OutIt out, Less const &less,
    PQ &pq, bool const distinct = false)
{
    while (begin != end)
    {
        pq.push(typename PQ::value_type(
            multiway_merge_range_begin(*begin),
            multiway_merge_range_end(*begin)));
        ++begin;
    }
    while (!pq.empty())
    {
        typename PQ::value_type top = pq.top();
        pq.pop();
        if (top.first != top.second)
        {
            while (!pq.empty() && pq.top().first == pq.top().second)
            { pq.pop(); }
            if (!distinct ||
                pq.empty() ||
                less(*pq.top().first, *top.first) ||
                less(*top.first, *pq.top().first))
            {
                *out = top.first;
                ++out;
            }

            ++top.first;
            pq.push(top);
        }
    }
    return out;
}

template<class It, class OutIt, class Less>
OutIt multiway_merge(
    It const begin, It const end, OutIt out, Less const &less,
    bool const distinct = false)
{
    typedef typename multiway_merge_range_iterator<
        typename std::iterator_traits<It>::value_type
    >::type SubIt;
    if (std::distance(begin, end) < 16)
    {
        typedef std::vector<std::pair<SubIt, SubIt> > Remaining;
        Remaining remaining;
        remaining.reserve(
            static_cast<size_t>(std::distance(begin, end)));
        for (It i = begin; i != end; ++i)
        {
            if (multiway_merge_range_begin(*i) !=
                multiway_merge_range_end(*i))
            {
                remaining.push_back(std::make_pair(
                    multiway_merge_range_begin(*i),
                    multiway_merge_range_end(*i)));
            }
        }
        while (!remaining.empty())
        {
            typename Remaining::iterator smallest =
                remaining.begin();
            for (typename Remaining::iterator
                i = remaining.begin();
                i != remaining.end();
            )
            {
                if (less(*i->first, *smallest->first))
                {
                    smallest = i;
                    ++i;
                }
                else if (distinct && i != smallest &&
                    !less(
                        *smallest->first,
                        *i->first))
                {
                    i = remaining.erase(i);
                }
                else { ++i; }
            }
            *out = smallest->first;
            ++out;
            ++smallest->first;
            if (smallest->first == smallest->second)
            { smallest = remaining.erase(smallest); }
        }
        return out;
    }
    else
    {
        std::priority_queue<
            std::pair<SubIt, SubIt>,
            std::vector<std::pair<SubIt, SubIt> >,
            multiway_merge_value_less<Less>
        > q((multiway_merge_value_less<Less>(less)));
        return multiway_merge(begin, end, out, less, q, distinct);
    }
}

template<class It, class OutIt>
OutIt multiway_merge(
    It const begin, It const end, OutIt const out,
    bool const distinct = false)
{
    return multiway_merge(
        begin, end, out,
        multiway_merge_default_less(), distinct);
}

1
Here is my implementation using MinHeap...

package merging;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;


public class N_Way_Merge {

int No_of_files=0;
String[] listString;
int[] listIndex;
PrintWriter pw;
private String fileDir = "D:\\XMLParsing_Files\\Extracted_Data";
private File[] fileList;
private BufferedReader[] readers;

public static void main(String[] args) throws IOException {

    N_Way_Merge nwm=new N_Way_Merge();

    long start= System.currentTimeMillis();

    try {

        nwm.createFileList();

        nwm.createReaders();
        nwm.createMinHeap();
    }
    finally {
        nwm.pw.flush();
        nwm.pw.close();
        for (BufferedReader readers : nwm.readers) {

            readers.close();

        }
    }
    long end = System.currentTimeMillis();
    System.out.println("Files merged into a single file.\nTime taken: "+((end-start)/1000)+"secs");
}

public void createFileList() throws IOException {
    //creates a list of sorted files present in a particular directory
    File folder = new File(fileDir);
    fileList = folder.listFiles();
    No_of_files=fileList.length;
    assign();
    System.out.println("No. of files - "+ No_of_files);

}

public void assign() throws IOException
{
    listString = new String[No_of_files];
    listIndex = new int[No_of_files];
    pw = new PrintWriter(new BufferedWriter(new FileWriter("D:\\XMLParsing_Files\\Final.txt", true)));
}

public void createReaders() throws IOException {
    //creates array of BufferedReaders to read the files
    readers = new BufferedReader[No_of_files];

    for(int i=0;i<No_of_files;++i)
    {
        readers[i]=new BufferedReader(new FileReader(fileList[i]));
    }
}

public void createMinHeap() throws IOException {

    for(int i=0;i<No_of_files;i++)
    {
        listString[i]=readers[i].readLine();
        listIndex[i]=i;
    }

    WriteToFile(listString,listIndex);

}

public void WriteToFile(String[] listString,int[] listIndex) throws IOException{

    BuildHeap_forFirstTime(listString, listIndex);
    while(!(listString[0].equals("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz")))
    {
        pw.println(listString[0]);
        listString[0]=readers[listIndex[0]].readLine();

        MinHeapify(listString,listIndex,0);
    }

}
public void BuildHeap_forFirstTime(String[] listString,int[] listIndex){

    for(int i=(No_of_files/2)-1;i>=0;--i)
        MinHeapify(listString,listIndex,i);

}

public void MinHeapify(String[] listString,int[] listIndex,int index){

    int left=index*2 + 1;
    int right=left + 1;
    int smallest=index;
    int HeapSize=No_of_files;
    if(left <= HeapSize-1  && listString[left]!=null &&  (listString[left].compareTo(listString[index])) < 0)
        smallest = left;

    if(right <= HeapSize-1 && listString[right]!=null &&  (listString[right].compareTo(listString[smallest])) < 0)
        smallest=right;



    if(smallest!=index)
    {
        String temp=listString[index];
        listString[index]=listString[smallest];
        listString[smallest]=temp;

        listIndex[smallest]^=listIndex[index];
        listIndex[index]^=listIndex[smallest];
        listIndex[smallest]^=listIndex[index];

        MinHeapify(listString,listIndex,smallest);
    }

}

}


0

Java triển khai thuật toán đống tối thiểu để hợp nhất k mảng được sắp xếp:

public class MergeKSorted {

/**
 * helper object to store min value of each array in a priority queue, 
 * the kth array and the index into kth array
 *
 */
static class PQNode implements Comparable<PQNode>{
    int value;
    int kth = 0;
    int indexKth = 0;

    public PQNode(int value, int kth, int indexKth) {
        this.value = value;
        this.kth = kth;
        this.indexKth = indexKth;
    }
    @Override
    public int compareTo(PQNode o) {
        if(o != null) {
            return Integer.valueOf(value).compareTo(Integer.valueOf(o.value));
        }
        else return 0;
    }

    @Override
    public String toString() {
        return value+" "+kth+" "+indexKth;
    }
}
public static void mergeKSorted(int[][] sortedArrays) {
    int k = sortedArrays.length;
    int resultCtr = 0;
    int totalSize = 0;
    PriorityQueue<PQNode> pq = new PriorityQueue<>();
    for(int i=0; i<k; i++) {
        int[] kthArray = sortedArrays[i];
        totalSize+=kthArray.length;
        if(kthArray.length > 0) {
            PQNode temp = new PQNode(kthArray[0], i, 0);
            pq.add(temp); 
        }
    }
    int[] result = new int[totalSize];
    while(!pq.isEmpty()) {
        PQNode temp = pq.poll();
        int[] kthArray = sortedArrays[temp.kth];
        result[resultCtr] = temp.value;
        resultCtr++;            
        temp.indexKth++;
        if(temp.indexKth < kthArray.length) {
            temp = new PQNode(kthArray[temp.indexKth], temp.kth, temp.indexKth);
            pq.add(temp);
        }

    }
    print(result);
}

public static void print(int[] a) {
    StringBuilder sb = new StringBuilder();
    for(int v : a) {
        sb.append(v).append(" ");
    }
    System.out.println(sb);
}

public static void main(String[] args) {
     int[][] sortedA = {
         {3,4,6,9},
         {4,6,8,9,12},
         {3,4,9},
         {1,4,9}    
     };
     mergeKSorted(sortedA);
}

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.