クイックソートおよびマージソートアルゴリズムのテンプレートとアプリケーション

クイックソートおよびマージソートアルゴリズムのテンプレートとアプリケーション

1. クイックソート

基本的なアイデア:シーケンスを 2 つの部分に分割し、左半分のすべての数値が右半分のすべての数値以下であるか、それ以上であることを確認し、左部分と右部分を再帰的に処理します。

具体的な手順:ここでq、 は配列、lは配列の左端の添字、rは配列の右端の添字です。

  • カットオフポイントを決定しますq[(l+r)>>1]。つまり、q[(l+r)/2]
  • ダブルポインタを使用して左と右の間隔を調整し、左の間隔のデータが右の間隔のデータ以下になるように(昇順)、または左の間隔のデータが右の間隔以上になるようにします。正しい間隔のデータ (降順)
  • 左右の区間の再帰処理[l,j][j+1,r]

アルゴリズムの例:

#include<iostream>
using namespace std;

const int N = 1e6 + 10;
int q[N];

void quick_sort(int* q, int l, int r)//快排模板
{
    
    
	if (l >= r) return;//必须 >=
	int x = q[l + r >> 1], i = l - 1, j = r + 1;
	while (i < j)
	{
    
    
		while (q[++i] < x);
		while (q[--j] > x);
		if (i < j) swap(q[i], q[j]);
	}
	quick_sort(q, l, j);
	quick_sort(q, j + 1, r);
}

int main()
{
    
    
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i) cin >> q[i];
	quick_sort(q, 0, n - 1);
	for (int i = 0; i < n; ++i) cout << q[i] << " ";
}

2. クイック選択

はじめに:クイック選択アルゴリズムは、クイック ソートに基づく時間計算量 O(n) のアルゴリズムであり、その機能はシーケンス内で k 番目に小さい数値を見つけることです。

ステップ:

  • 一般に、これはクイック ソート アルゴリズムに似ています。
  • 違いは、k が左半分の間隔の長さ以下の場合、左半分を再帰的に処理することです。
  • それ以外の場合は、右半分を再帰的に処理します。

アルゴリズムの例:

const int N = 100010;
int q[N];

int quick_sort(int l, int r, int k)
{
    
    
	if (l == r) return q[l]; //可以以==,也可以>=
	int x = q[l + r >> 1], i = l - 1, j = r + 1;
	while (i < j) {
    
    
		while (q[++i] < x);
		while (q[--j] > x);
		if (i < j) swap(q[i], q[j]);
	}
	int sl = j - l + 1;//sl为左区间元素的个数
	if (k <= sl) return quick_sort(l, j, k);
	return quick_sort(j + 1, r, k - sl);
}

int main()
{
    
    
	int n, k;
	cin >> n >> k;
	for (int i = 0; i < n; ++i) cin >> q[i];
	cout << quick_sort(0, n - 1, k) <<endl;
}

3. マージソート

中心的なアイデア: 2 つの順序付けられた同一のシーケンスを 1 つの順序付けられたシーケンスにマージする

具体的な手順:

  • カットオフポイントを決定し、間隔を[l,r]に分割します。[l,mid][mid+1,r]
  • 左右の区間の再帰処理[l,mid][mid+1,r]
  • Merge、2 つの並べ替えられた範囲を 1 つの並べ替えられた範囲にマージします

アルゴリズムの例:

const int N = 1e6 + 10;
int q[N], t[N];

void merge_sort(int* q, int l, int r)//归并排序模板
{
    
    
	if (l >= r) return;
	int mid = l + r >> 1;
	merge_sort(q, l, mid);
	merge_sort(q, mid + 1, r);
	int k = 0, i = l, j = mid + 1;
	while (i <= mid && j <= r)
	{
    
    
		if (q[i] <= q[j]) t[k++] = q[i++];
		else t[k++] = q[j++];
	}
	while (i <= mid) t[k++] = q[i++];
	while (j <= r) t[k++] = q[j++];
	for (int i = l, j = 0; i <= r; ++i, ++j) q[i] = t[j];
}

int main()
{
    
    
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i) cin >> q[i];
	merge_sort(q, 0, n - 1);
	for (int i = 0; i < n; ++i) cout << q[i] << " ";
}

4番目、逆順ペアの数

逆ペアの定義: 2 つの数値、前者が後者より大きい場合、これら 2 つの数値は逆ペアと呼ばれます。

簡単な説明:シーケンス内の逆のペアの数を見つけます。

アルゴリズムの例:

typedef long long ll;//结果可能大于int的范围,函数返回值用long long类型
const int N = 100010;
int q[N], t[N];

ll merge_sort(int l, int r)
{
    
    
	if (l >= r) return 0;
	int mid = l + r >> 1;
	ll ret = merge_sort(l, mid) + merge_sort(mid + 1, r);
	int k = 0, i = l, j = mid + 1;
	while (i <= mid && j <= r) {
    
    
		if (q[i] <= q[j]) t[k++] = q[i++];
		else {
    
    
			t[k++] = q[j++];
			ret += mid - i + 1;
		}
	}
	while (i <= mid) t[k++] = q[i++];
	while (j <= r) t[k++] = q[j++];
	for (int i = l, j = 0; i <= r; ++i, ++j) q[i] = t[j];
	return ret;
}
int main()
{
    
    
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i) cin >> q[i];
	cout << merge_sort(0, n - 1) << endl;
}

おすすめ

転載: blog.csdn.net/qq_52324409/article/details/122480940