python算法——java版堆排序,最小堆排序topN

input为数组,k为求的top值

	// 初始化建堆的时间复杂度为O(n),排序重建堆的时间复杂度为nlog(n),所以总的时间复杂度为O(n+nlogn)=O(nlogn)
	public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
		ArrayList<Integer> it = new ArrayList();
		// 临界判断
		if (k <= 0) {
			return it;
		}
		if (input.length == 0) {
			return it;
		}
		if (input.length < k) {
			return it;
		}
		if (input.length == 1) {
			it.add(input[0]);
			return it;
		}
		buildMinHeap(input);
		System.out.println("---第一次过后---" + new Gson().toJson(input));
		// 每次位置交换定位
		int place = input.length - 1;
		// 交换记录暂存
		int save = 0;
		// 交换下沉
		for (int i = 0; i < k; i++) {
			place = input.length - 1 - i;
			int start = 0;
			// 交换树顶和末节点,已排序位置左移
			while (start <= place) {
				//求出左右位置
				int left = (start << 1) + 1;
				int right = (start << 1) + 2;
				if (left > place) {
					break;
				}
				// 有双节点
				if (right <= place) {
					//符合该位置规则,直接返回
					if (input[start] <= input[left] && input[start] <= input[right]) {
						break;
					} else {
						boolean smallL = false;
						if (input[left] <= input[right]) {
							smallL = true;
						}
						// 和最小的节点交换
						if (smallL) {
							change(input, left, start);
							start = left;
						} else {
							change(input, right, start);
							start = right;
						}
					}
				}
				// 只剩下左节点
				else {
					if (input[left] < input[start]) {
						change(input, left, start);
					}
					break;
				}
			}
			// 移除顶结点
			save = input[0];
			input[0] = input[input.length - 1 - i];
			input[input.length - 1 - i] = save;
			it.add(save);
		}
		System.out.println(new Gson().toJson(input));
		return it;
	}

	public void change(int[] input,int i,int j) {
		int c = input[i];
		input[i] = input[j];
		input[j] = c;
	}
	
	// build
	public void buildMinHeap(int[] input) {

		// 每次位置交换定位
		int place = input.length - 1;
		// 交换记录暂存
		int save = 0;
		// 构建最小堆
		while (place > 0) {
			// 判断奇数,偶数,奇数左指数,偶右指数,左树开始下次跳一格,右树开始,跳两格,后面都以右结点开始
			boolean dou = false;
			if (place % 2 == 0) {
				dou = true;
			}
			// 找出父节点位置,偶数左移减一,奇数左移
			// 交换位置,调整指针,因为排列完全二叉树,定位位置是奇数,必定无右节点(只会在最开始出现单一节点)
			// 父节点位置
			int placeroot = 0;
			if (!dou) {
				placeroot = place >> 1;
				// 奇数只与父节点比较
				if (input[place] < input[placeroot]) {
					save = input[place];
					input[place] = input[placeroot];
					input[placeroot] = save;
				}
				place--;
			} else {
				placeroot = (place >> 1) - 1;
				// 偶数必有左兄弟节点,两子节点都与父节点比较
				if (input[place] < input[placeroot]) {
					save = input[place];
					input[place] = input[placeroot];
					input[placeroot] = save;
				}
				if (input[place - 1] < input[placeroot]) {
					save = input[place - 1];
					input[place - 1] = input[placeroot];
					input[placeroot] = save;
				}
				// 跳两格
				place -= 2;
			}
		}
	}

初始化建堆只需要对二叉树的非叶子节点调用adjusthead()函数,由下至上,由右至左选取非叶子节点来调用adjusthead()函数。那么倒数第二层的最右边的非叶子节点就是最后一个非叶子结点。
  假设高度为k,则从倒数第二层右边的节点开始,这一层的节点都要执行子节点比较然后交换(如果顺序是对的就不用交换);倒数第三层呢,则会选择其子节点进行比较和交换,如果没交换就可以不用再执行下去了。如果交换了,那么又要选择一支子树进行比较和交换;高层也是这样逐渐递归。
  那么总的时间计算为:s = 2^( i - 1 ) * ( k - i );其中 i 表示第几层,2^( i - 1) 表示该层上有多少个元素,( k - i) 表示子树上要下调比较的次数。
  S = 2^(k-2) * 1 + 2(k-3)2……+2(k-2)+2(0)*(k-1) ===> 因为叶子层不用交换,所以i从 k-1 开始到 1;
  S = 2^k -k -1;又因为k为完全二叉树的深度,而log(n) =k,把此式带入;
  得到:S = n - log(n) -1,所以时间复杂度为:O(n)

### 使用堆排序解决Top-K问题 #### Top-K问题概述 Top-K问题是计算机科学领域中常见的一个问题,其目标是从给定的数据集中找到最大的K个元素或最小的K个元素。该问题可以通过多种算法实现,而堆排序是一种高效的解决方案[^1]。 #### 堆排序的核心原理 堆排序基于二叉堆结构,分为大根堆和小根堆两种形式。大根堆的特点是父节点大于等于子节点;小根堆则是父节点小于等于子节点。在解决问题时,通常会根据需求构建相应类型的堆。例如,在寻找前K个最大值时,可以使用小根堆来维护当前已知的最大K个数值[^2]。 #### 实现过程详解 以下是利用堆排序解决Top-K问题的具体方法: 1. **初始化阶段** 首先选取输入数组中的前K个元素构成初始的小根堆。这一步骤的时间复杂度为O(K),因为只需要对固定数量的元素进行建堆操作。 2. **遍历剩余元素并更新堆** 对于剩下的N-K个元素逐一处理:如果某个元素比当前堆顶(即堆中小的那个数)还要大,则将其替换掉堆顶位置上的旧值,并重新调整整个堆保持性质不变。此步每次执行需花费log K时间完成一次插入/删除动作,总共要重复(N-K)次因此总耗时约为 O((N−K)* log K)[^3]。 3. **最终结果提取** 经过上述两轮迭代之后得到的就是所需的top k项集合了。由于这些项目已经被存储在一个有效的优先队列里边所以可以直接读取出来作为答案返回即可。 下面给出一段Python本代码展示如何应用这一思路去获取列表arr里的最高分成绩排名情况: ```python import heapq def find_top_k(nums, k): min_heap = nums[:k] heapq.heapify(min_heap) for num in nums[k:]: if num > min_heap[0]: heapq.heappushpop(min_heap, num) return sorted(min_heap , reverse=True) if __name__ == "__main__": arr = [7, 10, 4, 3, 20, 15] top_three_scores = find_top_k(arr, 3) print(top_three_scores) ``` 以上程序片段展示了怎样借助内置库`heapq`快速搭建起一个小顶堆用于筛选出指定长度内的最优解候选者们. #### 总结说明 综上所述可以看出采用堆这种数据结构确实能够很好地应对大规模数据下的top-k查询请求场景下效率表现优异的同时也具备良好的可扩展性和灵活性特点值得深入研究学习掌握这项技能对于提升个人技术水平有着重要意义.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值