「ヒープソート」と「Top-k」

目次

編集

序文:

「ヒープソート」について:

ステップ 1: 杭を構築する

ステップ 2: 並べ替え

「トップK問題」

Top-k の質問について:


序文:

前回のブログでは、「ヒープ」の予備的な概念がすでにありました。その後、「ヒープ」を使用して日常生活の問題を解決できます。この記事では、よく使用される 2 つのアプリケーション シナリオをそれぞれ示します。 」と「Top-k 問題」。前回のブログは「ヒープ」のシミュレーション実装 - CSDN ブログです。

 

「ヒープソート」について:

#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>

void swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void AdjustDown(int* arr, int sz, int parent)
{
	int child = parent * 2 + 1;
	while (child < sz)
	{
		if (child + 1 < sz && arr[child] < arr[child + 1])
		{
			child++;
		}

		if (arr[child] > arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

void AdjustUp(int* arr, int sz, int child)
{
	while (child > 0)
	{
		int parent = (child - 1) / 2;
		if (arr[parent] < arr[child])
		{
			swap(&arr[parent], &arr[child]);
		}
		child = parent;
	}
}

int main()
{
	int arr[] = { 2, 6, 9, 3, 1, 7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = (sz - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, sz, i);
	}//向下调整算法
	

	//for (int i = 1; i<sz; i++)
	//{
	//	AdjustUp(arr, sz, i);
	//}//向上调整算法

	int end = sz - 1;
	while (end > 0)
	{
		swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
		--end;
	}
	return 0;
}

ステップ 1: 杭を構築する

「ヒープ」を使用すると、特定の順序が狂った配列のソートが容易になります。まず、ソート操作のために大きなヒープを選択する必要があります。

ヒープを構築するために小さなヒープを使用することを選択してみてはいかがでしょうか?

以前のブログの「ヒープ」の説明によると、ヒープが小さいとは、先頭の要素が最も小さい要素であり、他のノードの数が最初の要素よりも少ないことを意味するため、小さいヒープであれば、最小の数はすでに存在します。最初の要素。次に小さい要素を見つけたい場合は、残りの要素の間にヒープを構築し、このサイクルを繰り返して並べ替えを完了する必要があります。これには時間がかかり、並べ替えには役立ちません。

そこで、大規模なヒープを使用してヒープを構築することを選択し、大規模なヒープを実現した後、最初と最後の要素を交換し、残りの n-1 個の要素を下方調整法を使用して調整してから交換します。ソートを実現できます。

    int arr[] = { 2, 6, 9, 3, 1, 7 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (int i = 1; i<sz; i++)
	{
	   AdjustUp(arr, sz, i);
	}

図に示すように配列を上方向に調整してヒープを構築します。

 

ステップ 2: 並べ替え

 まず、最初と最後の要素を交換します。

最後の要素を除くすべての要素を下方に調整して、大きな山に続けます

 

 

 

 

上記の手順を繰り返します

最終的なヒープは次のとおりです。

 

これでヒープソートは完了です。

 

「トップK問題」

Top-k の質問について:

これは、データの組み合わせから最初の K 個の最大の要素または最小の要素を見つけることですが、一般にデータ量は比較的多くなります

例: トップ 10 のプロフェッショナル、フォーチュン 500、リッチ リスト、ゲームのトップ 100 のアクティブ プレーヤーなど。n データ内の最初の K 個の最大要素を見つける例を見て説明しましょう: (n=10000 と仮定) (k=10 と仮定)

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
const char* file = "data.txt";
void swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void AdjustDown(int* arr, int sz, int parent)
{
	int child = 2 * parent + 1;
	while (child < sz)
	{
		if (child + 1 < sz && arr[child + 1] < arr[child])
		{
			child++;
		}

		if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

void CreateFile()
{
	//创建随机数的种子
	srand((unsigned int)time(NULL));
	FILE* Fin = fopen(file, "w");
	if (Fin == NULL)
	{
		perror("Fopen error");
		exit(-1);
	}

	int n = 10000000;
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % n;
		fprintf(Fin, "%d\n", x);
	}

	fclose(Fin);
	Fin = NULL;
}

void Print()
{
	FILE* Fout = fopen(file, "r");
	if (Fout == NULL)
	{
		perror("Fout error");
		exit(-1);
	}

	//取前k个数进小堆
	int* minheap = (int*)malloc(sizeof(int) * 5);
	if (minheap == NULL)
	{
		perror("minheap -> malloc");
		return;
	}


	for (int i = 0; i < 5; i++)
	{
		fscanf(Fout, "%d", &minheap[i]);
	}

	for (int i = (5-1-1)/2; i >=0; --i)
	{
		AdjustDown(minheap, 5, i);
	}

	//读取数据
	int x = 0;
	while (fscanf(Fout, "%d", &x) != EOF)
	{
		if (minheap[0] < x)
		{
			minheap[0] = x;
		}
		AdjustDown(minheap, 5, 0);
	}

	for (int i = 0; i < 5; i++)
	{
		printf("%d ", minheap[i]);
	}

	fclose(Fout);
	Fout = NULL;
}

int main()
{
	//CreateFile();
	Print();
	return 0;
}

まず、10000000 個の乱数を作成し、次にその数値を変更し、ランダムに 5 つの数値を選択して、次のように変更します。

10000001、10000002、10000003、10000004、10000005

別の小さな山を構築します。これは小さな山でなければならないことに注意してください。

大きなヒープを構築する場合、最初にデータを検索して 10000005 が見つかった場合、その数値はヒープの先頭にある必要があります。次に小さい数値が見つかると、ヒープに入ることができないため、小さなヒープを使用します。 !

 次に、データの最初の 5 要素を小さなヒープに置きます。

次に、残りの 9999995 個の数値を調べて比較し、それらの数値がヒープの最上位の要素より大きい場合は、直接置き換えます。

置換後、再度下方に調整し、データ全体を走査した後、ヒープを挿入します。

 10000001、10000002、10000003、10000004、10000005

おすすめ

転載: blog.csdn.net/weixin_72917087/article/details/135478100