[スピーキングアルゴリズムスモールクラス]分割統治法(マージとソートのアイデアに基づく)を使用して、順列の逆数を見つけます(O(n ^ 2)→O(n log n))

ここに画像の説明を挿入

分割統治法で逆序数を求める

事前知識:マージして並べ替えます。
マージソートの正しさを証明しました。マージソートアルゴリズムがわずかに変更されている限り、順列の逆数を見つける時間の複雑さをO(n ^ 2)からO(nlog⁡n)に減らすことができます。
配置PをP_1とP_2の2つの部分にできるだけ均等に分割します。次に、Pの
シーケンス番号τ§=τ(P_1)+τ(P_2)+τ_Merge
明らかに、τ(P_1)とτ(P_2)はそれぞれ、再帰的に解かれるP_1とP_2の範囲のシーケンス番号を表します。そして、τ_Mergeはすべての見逃されたケースをカバーします。つまり、逆順序対(a_i、a_j)を形成する2つの要素a_i、a_j、i <j、a_i> a_jはa_i∈P_1、a_j∈P_2を満たします。
マージとソートのプロセスでは、2つの順序付けられた(昇順の)シーケンスをマージするステップは次のとおり
です。マージするための一時シーケンスtを設定します。
ポインタiとjは、それぞれ2つのサブ配列の先頭を指します。サブシーケンスの範囲は、_beginから_mid、_mid +1から_endです。
比較のために、2つのサブ配列のそれぞれから要素(つまり、ポインターiとjが指す要素)を常に取得し、小さい方の数値を配列tに入れ、対応するポインターをインクリメントします(2つの要素が等しい場合、アドレスはデフォルトで比較されます。下の配列の数値、つまりiが指す数値はtに入れられます。サブシーケンスの1つが取り出されると、サイクルは終了します。
要素がシーケンスtに取り込まれていないサブシーケンスのすべての要素をコピーします。
長さmとnの序数P_1とP_2の2つのシーケンスから取り出された2つの数が、それぞれx_i、y_jであり、下付き文字が序数のシーケンス内の位置を表すとします。各比較でx_i> y_jが見つかり、シーケンスが昇順であることがわかっている場合、
x_k> y_j、k = i、i + 1、...、m、x_k∈P_1、y_j∈P_2
はmを意味します-i +1ペアが逆の順序で見つかります。つまり、τ_Merge= m-i +1です。
コード:

template<class _Ty> size_t merge(_Ty* _begin, _Ty* _mid, _Ty* _end) {
    
    
	const auto l = _end - _begin + 1; size_t tau = 0;
	_Ty* t = new _Ty[l], * i = _begin, * j = _mid + 1, * k = t;
	while (i <= _mid && j <= _end) {
    
    
		if (*i <= *j) {
    
     *k = *i; ++i; ++k; }
		else {
    
     *k = *j; ++j; ++k; tau += _mid - i + 1; }
	}
	while (i <= _mid) {
    
     *k = *i; ++i; ++k; }
	while (j <= _end) {
    
     *k = *j; ++j; ++k; }
	std::copy(t, t + l, _begin);
	delete[] t;
	return tau;
}

template<class _Ty> size_t inversion_count(_Ty* _begin, _Ty* _end) {
    
    
	size_t tau = 0;
	if (_begin < _end) {
    
    
		_Ty* _mid = _begin + (_end - _begin) / 2;
		tau += inversion_count(_begin, _mid);
		tau += inversion_count(_mid + 1, _end);
		tau += merge(_begin, _mid, _end);
	}
	return tau;
}

おすすめ

転載: blog.csdn.net/COFACTOR/article/details/109005737