• .net下使用最小堆实现TopN算法


    测试代码:

    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;
            }
        }
    }
    
    
  • 相关阅读:
    如何创建一个自定义和定制Windows窗体事件“跳转列表吗
    动画应用程序的主窗体
    Splasher v1.32 -启动屏幕实现
    颜色需要
    选项卡对话框类
    捕捉屏幕的各种方法
    列表生成方式
    关于日志监控中,关键字段如果还有.该如何处理
    oracle的一些状态查询
    rpm
  • 原文地址:https://www.cnblogs.com/yczz/p/3865963.html
Copyright © 2020-2023  润新知