Блог пользователя kissu_pari_na

Автор kissu_pari_na, история, 7 лет назад, По-английски

Is there any solution that will merge two sets in n=( size_of_se1 + size_of_set2 ) times in c++? If I iterate through both the sets and take the smaller value and insert it in another set, this way I can merge two sets but it will take close to n*logn time as set insert operation takes logn time. Also I can let the set1 unchanged and insert all the elements of set2 in set1 or vice versa but it will also take size_of_set2*log(size_of_set1) or size_of_set1*log(size_of_set2) time. I am searching for a solution if it is actually possible to merge two sets in linear time. I googled it and spend some time to find out any solution regarding to it but failed :( Can anyone help me with your valuable opinion? thanks in advance :)

  • Проголосовать: нравится
  • +30
  • Проголосовать: не нравится

»
7 лет назад, # |
  Проголосовать: нравится +37 Проголосовать: не нравится

According to this and this, this should be linear:

#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9;

int main() {
	set<int> a {1, 3, 7, 10, 13, 20};
	set<int> b {2, 3, 5, 7, 11, 13, 15, 19};
	
	vector<int> v;
	merge(a.begin(), a.end(), b.begin(), b.end(), back_inserter(v));
	
	set<int> m(v.begin(), v.end());
	
	for(const auto &element : m) {
		cout << element << " ";
	}
	cout << endl;
	
	return 0;
}
  • »
    »
    7 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +6 Проголосовать: не нравится

    You can get rid of set<int> m(v.begin(), v.end()); by using:

    set<int> m;
    merge(a.begin(), a.end(), b.begin(), b.end(), inserter(m, m.end()));
    
    • »
      »
      »
      7 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Got it. Thanks :)

    • »
      »
      »
      7 лет назад, # ^ |
      Rev. 14   Проголосовать: нравится +3 Проголосовать: не нравится

      Is this guaranteed to be linear time, though? (Edit: I believe the answer is "probably not linear-time, but it's super tricky". See next paragraph.) fofao_funk's solution is clearly linear time, as inserting N elements into a vector and constructing a set from an ordered vector (see section 23.4.6.2 of the C++11 standard, or section 26.4.6.2 of the C++17 standard) are both linear-time operations.

      I previously thought yours could be implementation-dependent, as suggested by the fact that using set::insert to insert a sorted range is not guaranteed to to take linear time. However, the standard says set::insert(p, t) takes "amortized constant time if t is inserted right before p" (technically this says nothing about duplicate elements, but let's ignore that), so that strongly suggests your solution is guaranteed to be linear time. However, the plot thickens! Here's what the inserter does:

      iter = container->insert(iter, value);
      ++iter;
      

      If it just did a bunch of container->insert(container.end(), value) operations, that would be amortized constant time per the standard. It does not do that, though: It inserts at m.end(), then takes the iterator to just-added element and advances it (thus making it point to m.end() again). This last iterator-advancing operation is probably not guaranteed to be amortized constant time.

      • »
        »
        »
        »
        7 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        I just run the code and check the runtime. But is there any constant time factor, I am not sure? When I ran the code it shows slightly higher time complexity than linear. If I think logically surely it is linear.

    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Sorry but can I ask what is the risk of using set<int> m(v.begin(), v.end()); ?

  • »
    »
    7 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

    It's really very helpful. It is almost linear in time complexity if I am not wrong! Again thanks fofao_funk :)

»
6 лет назад, # |
Rev. 3   Проголосовать: нравится -49 Проголосовать: не нравится

I guess this can be done in O(n) ...plz correct me if I m wrong (assuming both set size to be n)

»
5 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

Why don't you use FHQ_Treap?It is a kind of Treap which can split and merge two BST in $$$O(logn)$$$