C语言堆结构处理TopK问题详解

目录
  • 问题
  • 分析
  • 代码实现

问题

在一百万个数据中,求出最大的k个数字,怎么效率高。

1. 将一百万个数据排序,承接上一篇的堆排序,时间复杂度为O(N * LogN)。但是显然这并不是最优解。

2. 一百万个数据放入一个数组中,将其视为一个完全二叉树,并用向下调整算法将其调整为一个大堆/小堆,然后Top/Popk次,即可求出前K个最大/最小的数字,时间复杂度为:O(N + K*LogN)

3. 用正确的堆处理TopK算法: 先假设求最大的K个数字,则建立大小为K的小根堆,然后在一百万-k个数据中,逐个遍历,若某个数据比小根堆的堆顶元素大,则替换掉堆顶元素,然后向下调整,使得这个堆重新变回一个小根堆。 时间复杂度为:O(K + (N-k)*LogK)

其实相较于2,3并没有时间上的很大提升,但是3在空间复杂度上有了巨大提升,2的空间为O(N),3为O(K)。 折中思考,3方法是求数据量较大的数据集合中前K个最大值/最小值的最佳方法

分析

求K个最大值,建小堆,是因为,若遍历途中遇到了那K个数中的某一个,他一定比堆顶元素大,然后替换进去之后,向下调整,可以使得这个数字置于这个小根堆的底部。从而达到目的。

代码实现

void AdjustUp(int* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			swap(a[parent], a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(int* a,int size, int parent) // size 是总大小,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;
		}
	}
}
void Print_Heap_Topk(int* a, int n, int k)
{
	int* KMaxHeap = new int[k];   // 最大堆存最小的K个数
	for (int i = 0; i < k; ++i)
	{
		KMaxHeap[i] = a[i];
	}
	for (int i = (k - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(KMaxHeap, k, i);
	}
	for (int i = k; i < n; ++i)
	{
		if (a[i] < KMaxHeap[0])
			KMaxHeap[0] = a[i];
		AdjustDown(KMaxHeap, k, 0);
	}
	for (int i = 0; i < k; ++i)
	{
		cout << KMaxHeap[i] << " ";
	}
	cout << endl;
}
void test_topk()
{
	int n = 10000;
	int* a = new int[n];
	srand(time(0));
	for (int i = 0; i < n; ++i)
		a[i] = rand() % 1000000;
	a[5] = 1000000 + 1;
	a[1231] = 1000000 + 2;
	a[531] = 1000000 + 3;
	a[5121] = 1000000 + 4;
	a[120] = 1000000 + 5;
	a[99] = 1000000 + 6;
	a[0] = 1000000 + 7;
	a[76] = 1000000 + 8;
	a[423] = 1000000 + 9;
	a[3144] = 1000000 + 10;
	a[333] = -100;
	a[999] = -200;
	a[777] = -500;
	a[888] = -800;
	a[111] = -1000;
	a[798] = -1;
	a[1111] = -250;
	a[2222] = -350;
	a[3333] = -450;
	a[4444] = -550;
	Print_Heap_Topk(a, n, 10);
}
int main()
{
	test_topk();
	return 0;
}

到此这篇关于C语言堆结构处理TopK问题详解的文章就介绍到这了,更多相关C语言TopK问题内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言 如何用堆解决Topk问题

    目录 前言 TopK问题 解题方法 代码实现与讲解 运行结果 函数解读 PrintTopK 解读 TestTopK 解读 前言 本篇将详细讲解如何利用小根堆的方法解决TopK问题,这么多数据要处理, 该算法时间复度居然只需 TopK问题 TopK问题介绍:在N个数中找出最大的前K个 (比如在1000个数中找出最大的前10个) 解题方法 方法1:先排降序,前N个就是最大的.  时间复杂度:   方法2:N个数依次插入大堆,HeapPop K次,每次取堆顶的数据,即为前K个. 时间复杂度: 假设N非

  • C语言堆结构处理TopK问题详解

    目录 问题 分析 代码实现 问题 在一百万个数据中,求出最大的k个数字,怎么效率高. 1. 将一百万个数据排序,承接上一篇的堆排序,时间复杂度为O(N * LogN).但是显然这并不是最优解. 2. 一百万个数据放入一个数组中,将其视为一个完全二叉树,并用向下调整算法将其调整为一个大堆/小堆,然后Top/Popk次,即可求出前K个最大/最小的数字,时间复杂度为:O(N + K*LogN) 3. 用正确的堆处理TopK算法: 先假设求最大的K个数字,则建立大小为K的小根堆,然后在一百万-k个数据中

  • C语言中结构体变量私有化详解

    背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据结构.结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问. 问题描述 C语言结构体定义中的变量默认是公有(Public)属性,如果实现成员变量的

  • C语言数据结构二叉树之堆的实现和堆排序详解

    目录 一.本章重点 二.堆 2.1堆的介绍 2.2堆的接口实现 三.堆排序 一.本章重点 堆的介绍 堆的接口实现 堆排序 二.堆 2.1堆的介绍 一般来说,堆在物理结构上是连续的数组结构,在逻辑结构上是一颗完全二叉树. 但要满足 每个父亲节点的值都得大于孩子节点的值,这样的堆称为大堆. 每个父亲节点的值都得小于孩子节点的值,这样的堆称为小堆. 那么以下就是一个小堆. 百度百科: 堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆. 若将和此次序列对应的一维数

  • Go语言基础语法之结构体及方法详解

    结构体类型可以用来保存不同类型的数据,也可以通过方法的形式来声明它的行为.本文将介绍go语言中的结构体和方法,以及"继承"的实现方法. 结构体类型 结构体类型(struct)在go语言中具有重要地位,它是实现go语言面向对象编程的重要工具.go语言中没有类的概念,可以使用结构体实现类似的功能,传统的OOP(Object-Oriented Programming)思想中的继承在go中可以通过嵌入字段的方式实现. 结构体的声明与定义: // 使用关键字 type 和 struct 定义名字

  • C语言结构体指针引用详解

    目录 指向结构体变量的指针 指向结构体数组的指针 结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针. 指向结构体变量的指针 前面我们通过"结构体变量名.成员名"的方式引用结构体变量中的成员,除了这种方法之外还可以使用指针. 前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址.如果定义一个指针变量 p 指向这个地址的话,p 就可以指向结构体变量 student1 中的任意一个成员. 那么,这个指针变量定义成

  • C语言结构体内存对齐详解

    目录 实例一: 分析:存储结构图如下 实例二: 分析:存储结构如下 实例三: 分析:存储结构如下 实例四: 分析:存储结构图如下 总结 1.结构体内存对齐是指当我们创建一个结构体变量时,会向内存申请所需的空间,用来存储结构体成员的内容.我们可以将其理解为结构体成员会按照特定的规则来存储数据内容. 2.结构体的对齐规则 (1)第一个成员在相比于结构体变量存储起始位置偏移量为0的地址处. (2)从第二个成员开始,在其自身对齐数的整数倍开始存储(对齐数=编译器默认对齐数和成员字节大小的最小值,VS编译

  • Go语言同步等待组sync.WaitGroup结构体对象方法详解

    目录 sync.WaitGroup结构体对象 WaitGroup的结构体 Add()方法 Done()方法 Wait()方法 Add().Done().Wait()三者对比 sync.WaitGroup使用示例 sync.WaitGroup结构体对象 在Go语言中,sync.WaitGroup结构体对象用于等待一组线程的结束:WaitGroup是go并发中最常用的工具,我们可以通过WaitGroup来表达这一组协程的任务是否完成,以决定是否继续往下走,或者取任务结果: WaitGroup的结构体

  • Go语言学习教程之结构体的示例详解

    目录 前言 可导出的标识符 嵌入字段 提升 标签 结构体与JSON相互转换 结构体转JSON JSON转结构体 练习代码步骤 前言 结构体是一个序列,包含一些被命名的元素,这些被命名的元素称为字段(field),每个字段有一个名字和一个类型. 结构体用得比较多的地方是声明与数据库交互时需要用到的Model类型,以及与JSON数据进行相互转换.(当然,项目中任何需要多种数据结构组合在一起使用的地方,都可以选择用结构体) 代码段1:声明一个待办事项的Model类型: type Todo struct

  • C语言顺序表的基本结构与实现思路详解

    目录 一.顺序表的概念与结构 1.线性表的解释 2.顺序表概念解释 二.顺序表的思路及代码实现详解 1.静态顺序表的实现 2.动态顺序表思路及代码实现 2.1 动态顺序表的整体思路 2.2 定义结构体的实现 2.3 初始化结构体 2.4 结构体打印 2.5 检查数组容量 2.6 头插 2.7 尾插 2.8 头删 2.9 尾删 2.10 任意删除 2.11 任意插入 2.12 空间释放 三.顺序表代码整合 SeqList.h SeqList.c test.c 一.顺序表的概念与结构 1.线性表的解

  • C/C++ 中堆和栈及静态数据区详解

    C/C++ 中堆和栈及静态数据区详解   五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区.下面分别来介绍: 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等. 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收. 自由存储区,就是那些由malloc等分

随机推荐