top - k问题

文章目录

  • TOP-K问题
  • 实现
    • 定义堆的结构
    • 造数据
    • 小堆的向上向下调整
    • 建堆并遍历出前K大的数
    • 实现
    • 检验

TOP-K问题

即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大

  1. 用数据集合中前K个元素来建堆
    前k个最大的元素,则建小堆
    前k个最小的元素,则建大堆
  2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

思路:(以找前K个最大元素举例)用前K个元素建一个小堆,然后用后面的值和堆顶比较(小堆堆顶最小),大于堆顶元素就入堆,遍历完所有值后堆里面的值就是前K大的值

实现

定义堆的结构

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

造数据

void CreateData()
{
	//造数据
	int n = 100000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % 100000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}

小堆的向上向下调整

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);

			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && a[child + 1] < a[child])
			++child;

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);

			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

建堆并遍历出前K大的数

void PrintTopK(const char* file, int k)
{
	//读文件
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	//建立一个k个数的小堆

	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc error");
		return;
	}

	//读取前k个数
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
		//向上调整
		AdjustUp(minheap, i);
	}

	//边读边建小堆
	//读取剩余的值,读到x里
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		//如果堆里的元素小于x就继续调整
		if (minheap[0] < x)
		{
			//将x搞到堆顶
			minheap[0] = x;
			//向下调整
			AdjustDown(minheap, k, 0);
		}
	}

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

	free(minheap);
	fclose(fout);
}

实现

int main()
{
	//CreateData();
	PrintTopK("data.txt", 5);

	return 0;
}

结果:
top - k问题_第1张图片
因为每次堆排的时间复杂度是logN遍历一遍的时间复杂度是N,所以TOP-K进行排序的时间复杂度是NlogN.

检验

为了判断找出的K个数是否是最大的K个数,我们可以在文件中改出K个超出最大范围的数,保存后再次运行看是否为改动的几个数

top - k问题_第2张图片

top - k问题_第3张图片

你可能感兴趣的:(数据结构,数据结构,算法)