测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace HeapSort
{
class Program
{
static void Main(string[] args)
{
var arr = new int[] { 10, 7, 5 ,1,2,5}; List<int> src = new List<int>(arr);
HeapSort<int> heapSort = new HeapSort<int>((a, b) => { return a - b; }, src); heapSort.TryAddNumber(6); heapSort.TryAddNumber(7); heapSort.TryAddNumber(8); heapSort.TryAddNumber(9); heapSort.TryAddNumber(10);
Console.WriteLine(string.Join(",", heapSort.MinHeapsortToDescend().ConvertAll((t) => t.ToString()).ToArray())); Console.ReadLine();
}
}
}

算法实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace HeapSort
{
/// <summary>
/// 使用最小堆算法计算 TopN,参考 http://blog.csdn.net/morewindows/article/details/6709644
/// 最小堆性质:"父结点的键值总是小于或等于任何一个子节点的键值"
/// </summary>
/// <typeparam name="T"></typeparam>
class HeapSort<T>
{
Comparison<T> comparison;
List<T> minHeapList;
public HeapSort(Comparison<T> _comparison, List<T> list)
{
comparison = _comparison;
MakeMinHeap(list);
}
/* 这里只是将最小堆用于计算TopN,因此不需要添加节点
// 新加入i结点 其父结点为(i - 1) / 2
void MinHeapFixup(int i)
{
int parent; var temp = minHeapList[i];
parent = (i - 1) / 2; //父结点
while (parent >= 0 && i != 0)
{
//if (list[parent] <= temp)
if (comparison(minHeapList[parent], temp) <= 0)
break; minHeapList[i] = minHeapList[parent]; //把较大的子结点往下移动,替换它的子结点
i = parent;
parent = (i - 1) / 2;
}
minHeapList[i] = temp;
}
//在最小堆中加入新的数据nNum
void MinHeapAddNumber(int n, T nNum)
{
minHeapList[n] = nNum;
MinHeapFixup(n);
}*/
// 从i节点开始调整,n为节点总数 从0开始计算 i节点的子节点为 2*i+1, 2*i+2
void MinHeapFixdown(int i, int n)
{
int leftChild; var temp = minHeapList[i];
leftChild = 2 * i + 1;
while (leftChild < n)
{
//if (leftChild + 1 < n && a[leftChild + 1] < a[leftChild]) //在左右孩子中找最小的
if (leftChild + 1 < n && comparison(minHeapList[leftChild + 1], minHeapList[leftChild]) < 0) //在左右孩子中找最小的
leftChild++; //if (a[leftChild] >= temp)
if (comparison(minHeapList[leftChild], temp) >= 0)
break; minHeapList[i] = minHeapList[leftChild]; //把较小的子结点往上移动,替换它的父结点
i = leftChild;
leftChild = 2 * i + 1;
}
minHeapList[i] = temp;
}
/* 在TopN中不需要这样做
//在最小堆中删除数
void MinHeapDeleteNumber(int n)
{
Swap(0, n - 1);
MinHeapFixdown(0, n - 1);
}
*/
/// <summary>
/// 尝试添加节点,如果小于等于最小根,不处理
/// </summary>
/// <param name="item"></param>
public void TryAddNumber(T item)
{
if (comparison(minHeapList[0], item) >= 0)//如果小于等于最小根,不处理
{
return;
}
minHeapList[0] = item;//直接覆盖根节点,然后向下比较,以确保最小堆性质:"父结点的键值总是小于或等于任何一个子节点的键值"
MinHeapFixdown(0, minHeapList.Count);
}
/// <summary>
/// 排序建立最小堆
/// </summary>
void MakeMinHeap(List<T> list)
{
minHeapList = list;
for (int i = list.Count / 2 - 1; i >= 0; i--)
MinHeapFixdown(i, list.Count);
}
void Swap(int index1, int index2)
{
var temp = minHeapList[index1];
minHeapList[index1] = minHeapList[index2];
minHeapList[index2] = temp;
}
/// <summary>
/// 排序,在插入未完成之前,千万不要调用排序,这会破坏最小堆的性质
/// </summary>
public List<T> MinHeapsortToDescend()
{
for (int i = minHeapList.Count - 1; i >= 1; i--)
{
Swap(i, 0);
MinHeapFixdown(0, i);
}
return minHeapList;
}
}
}

.net下使用最小堆实现TopN算法的更多相关文章

  1. 使用最小堆优化Dijkstra算法

    OJ5.2很简单,使用priority_queue实现了最小堆竟然都过了OJ……每次遇到relax的问题时都简单粗暴地重新push进一个节点…… 然而正确的实现应该是下面这样的吧,关键在于swap堆中 ...

  2. Python3实现最小堆建堆算法

    今天看Python CookBook中关于“求list中最大(最小)的N个元素”的内容,介绍了直接使用python的heapq模块的nlargest和nsmallest函数的解决方式,记得学习数据结构 ...

  3. libevent中最小堆实现算法解析

    libevent,一个非常好的c的网络库,最近开始学习并分析下,做个记录.源码选用的1.4版本.因为感觉这版的代码比较精简,也没有太多宏定义,个人感觉适合学习原理. 从哪里开始呢,我选择从一些最简单的 ...

  4. [算法]体积不小于V的情况下的最小价值(0-1背包)

    题目 0-1背包问题,问要求体积不小于V的情况下的最小价值是多少. 相关 转移方程很容易想,初始化的处理还不够熟练,可能还可以更简明. 使用一维dp数组. 代码 import java.util.Sc ...

  5. My集合框架第五弹 最小堆

    二叉堆(以最小堆为例),其具有结构性质和堆序性质结构性质: 堆是一棵完全的二叉树,一颗高为h的完全二叉树有2^h到2^h-1个节点,高度为log N            而且该结构可以很容易的使用数 ...

  6. Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

    前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的re ...

  7. 多线程外排序解决大数据排序问题2(最小堆并行k路归并)

    转自:AIfred 事实证明外排序的效率主要依赖于磁盘,归并阶段采用K路归并可以显著减少IO量,最小堆并行k路归并,效率倍增. 二路归并的思路会导致非常多冗余的磁盘访问,两组两组合并确定的是当前的相对 ...

  8. C语言实现哈夫曼编码(最小堆,二叉树)

    // 文件中有通过QT实现的界面#include <stdio.h> #include <stdlib.h> #include <string.h> typedef ...

  9. PHP面试:说下什么是堆和堆排序?

    堆是什么? 堆是基于树抽象数据类型的一种特殊的数据结构,用于许多算法和数据结构中.一个常见的例子就是优先队列,还有排序算法之一的堆排序.这篇文章我们将讨论堆的属性.不同类型的堆以及堆的常见操作.另外我 ...

随机推荐

  1. 清空表中数据 id从1开始

    删除表的记录以后,如何使新记录的编号仍然从1开始有两种方法: 方法1: truncate table 你的表名 --这样不但将数据删除,而且可以重新置位identity属性的字段. 方法2: dele ...

  2. 10-多写一个@Autowired导致程序崩了

    再是javaweb实验六中,是让我们改代码,让它跑起来,结果我少注释了一个,导致一直报错,检查许久没有找到,最后通过代码替换逐步查找,才发现问题.

  3. 关于session报错问题。

    刚开始一直报500错误,页面不提示,也没想着去查看日志文件.好几天了,一看日志,发现是这个问题.问了一下,是session的问题. 2017/07/25 16:57:49 [error] 2300#0 ...

  4. gdb 调试带参数程序

    在gdb中,运行程序使用r或是run命令. 程序的运行,你有可能需要设置下面四方面的事. 1.程序运行参数. set args 可指定运行时参数.(如:set args 10 20 30 40 50) ...

  5. Response.Redirect原理图解

  6. 2018.08.21 NOIP模拟 xorand(01trie)

    xorand 描述 有q次操作,每次操作是以下两种: 1. 加入一个数到集合中 2. 查询,查询当前数字与集合中的数字的最大异或值,最大and值,最大or值 输入 第一行1个正整数Q表示操作次数 接下 ...

  7. js数组合并(一个数组添加到另一个数组里面)方法

    js定义两个数组. var arrA=[1,2,3]; var arrB=[4,5,6]; 要实现[1,2,3,4,5,6],如果直接arrA.push(arrB); 则arrB只会作为了arrA的一 ...

  8. C++之类和对象的使用(二)

    析构函数 析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一系列清理工作,使这部分内存可以被程序分配给新对象使用.对象生命周期结束,程序就自动执行析构函数来完成这些工作. 析构函数是一种 ...

  9. struts 拦截器

    my-default.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts ...

  10. Apache Struts 2 Documentation Core Developers Guide

    http://struts.apache.org/docs/core-developers-guide.html