TopK的实现

在此前,已经介绍了向下调整算法,建堆以及堆排序的实现,这篇文章将实现TopK问题。

前提:从1000个数据中找出10个最小的,这里的实现用到了文件操作,现实中若是基数很大,不能直接在内存中保存,则要借助文件将数据保存,然后再提取数据进行比较。大概步骤如下:

1:生成1000个随机数,做为本次要排序的基数。

2:为了找10个最小的,即提取出10个数来建堆,建大堆(建大堆即这10个元素中最大的元素在堆顶,然后将剩下的元素依次提取,与堆顶比较,若是比堆顶小,则将堆顶替换为该数据,再进行调整,变为大堆,调整后堆顶数据还是新的10个数据中最大的,然后继续提取,比较,调整)。

3:遍历剩下的所有元素。

创建基础数据:

void CreatDate(char* filename, int N)
{
	FILE* fin = fopen(filename, "w");
	if (fin == NULL)
	{
		perror("CreatDate");
	}
	srand(time(NULL));
	int i = 0;
	while (i < N)
	{
		fprintf(fin,"%d\n",rand()%1000);
		i++;
	}
	fclose(fin);
}

这里是创建N个数据,rand()%1000将数据范围限制在0-999,rand()使用前要先调用srand()这样才能使每次生成的数据有随机行,不然每次生成的数据顺序都是一样的。

建堆:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//大堆,找最小
void AdjustDown(int* arr, int parent, int K)
{
	int child = 2 * parent + 1;
	while (child < K)
	{
		if (child + 1 < K && arr[child + 1] > arr[child])
		{
			child = child + 1;
		}
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

TopK实现:

void PrintTopK(char* filename, int K)
{
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("PrintTopK");
	}
	//读取前k个数,
	int* arr = (int*)malloc(sizeof(int) * K);
	if (arr == NULL)
	{
		exit(-1);
	}
	int i = 0;
	for (i = 0; i < K; i++)
	{
		fscanf(fout, "%d\n", &arr[i]);
	}
	//建堆
	for (i = (K-1-1)/2; i >= 0; i--)
	{
		AdjustDown(arr,i,K);
	}
	//遍历剩下的元素,与堆顶元素比较,比堆顶小则替换堆顶,
	int num = 0;
	while (fscanf(fout, "%d\n", &num) != EOF)
	{
		if (arr[0] > num)
		{
			arr[0] = num;
			AdjustDown(arr, 0, K);
		}
	}
	//打印最后的k个数据
	for (i = 0; i < K; i++)
	{
		printf("%d ", arr[i]);
	}
	fclose(fout);
	free(arr);
	arr = NULL;
}

主函数:

int main()
{
	char* filename = "Date.txt";
	int N = 1000;
	int K = 10;
	//CreatDate(filename, N);
	PrintTopK(filename, K);
	return 0;
}

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值