首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C#:TopK:1万个数取前最大的100,堆排序

C#:TopK:1万个数取前最大的100,堆排序

作者头像
立羽
发布2023-08-24 15:36:23
发布2023-08-24 15:36:23
33200
代码可运行
举报
文章被收录于专栏:Unity3d程序开发Unity3d程序开发
运行总次数:0
代码可运行
  1. 把1万个数字的前100个 首先放入数组,构成最小堆

  1. 再循环100到一万之间的。 每次循环判断当前数字是否大于ary[0]
  2. 当大于时,首先把头节点remove,再把当前数字放入ary[0], 在那100个数之内进行最小堆排序
  3. 当循环完循环100到一万后。 最大的前100个数字就出来了。

时间复杂度

第一次构建最小堆时,可以不堆排序,而是把最小值放入到头节点 例如:k为头100,n为1万 时间复杂度:O(k+n*logk) 空间复杂度:O(n)

堆排序

代码语言:javascript
代码运行次数:0
运行
复制
using System;
using System.Collections.Generic;
using System.Text;

namespace DataStructure
{
    public enum HeapType
    {
        MinHeap,
        MaxHeap
    }

    public class BinaryHeap<T> where T : IComparable<T>
    {
        public List<T> items;

        public HeapType HType { get; private set; }

        public T Root
        {
            get { return items[0]; }
        }

        public BinaryHeap(HeapType type)
        {
            items = new List<T>();
            this.HType = type;
        }

        public bool Contains(T data)
        {
            return items.Contains(data);
        }

        
        /// <summary>
        /// 插入尾部,再跟父节点冒泡排序
        /// </summary>
        /// <param name="item"></param>
        public void Push(T item)
        {
            items.Add(item); //先插入list的末尾

            int i = items.Count - 1;

            bool flag = HType == HeapType.MinHeap;

            while (i > 0)  //一直冒泡到头节点,当前节点的父节点idx为(i - 1) / 2
            {
                if ((items[i].CompareTo(items[(i - 1) / 2]) > 0) ^ flag) //异或,相同取0,相异取1;如果是子>父 异或 最小堆(true) == 0,不发生交换
                {
                    T temp = items[i];
                    items[i] = items[(i - 1) / 2];
                    items[(i - 1) / 2] = temp;
                    i = (i - 1) / 2;
                }
                else
                    break;
            }
        }

        /// <summary>
        /// 删除头节点
        /// </summary>
        private void DeleteRoot()
        {
            int i = items.Count - 1;

            items[0] = items[i]; //先把队尾部放入头节点
            items.RemoveAt(i);  //移除队尾

            i = 0;

            bool flag = HType == HeapType.MinHeap;

            while (true)
            {
                int leftInd = 2 * i + 1; //左节点
                int rightInd = 2 * i + 2;//右节点
                int largest = i;

                if (leftInd < items.Count)
                {
                    if ((items[leftInd].CompareTo(items[largest]) > 0) ^ flag) //(左 > 父) 异或(是否最小堆)
                        largest = leftInd;
                }

                if (rightInd < items.Count)
                {
                    if ((items[rightInd].CompareTo(items[largest]) > 0) ^ flag)
                        largest = rightInd;
                }

                if (largest != i) //发生交换,父与左或者右的一个
                {
                    T temp = items[largest];
                    items[largest] = items[i];
                    items[i] = temp;
                    i = largest;
                }
                else //未发生交换,说明排序OK
                    break;
            }
        }

        //弹出头节点
        public T PopRoot()
        {
            T result = items[0];

            DeleteRoot();

            return result;
        }

        public T GetRoot()
        {
            T result = items[0];
            return result;
        }
    }

}

TopK

代码语言:javascript
代码运行次数:0
运行
复制
public class TestTopK : MonoBehaviour
{
    const int m_count = 10;
    const int m_top = 5;
    List<int> m_listOri = new List<int>(m_count);
    // Start is called before the first frame update
    void Start()
    {
        DataInit();

        BinaryHeap<Node> minHeap = new BinaryHeap<Node>(HeapType.MinHeap);
        
        for (int i = 0; i < m_top; i++)
        {
            minHeap.Push(new Node(m_listOri[i]));
        }

        for (int i = m_top; i < m_count; i++)
        {
            int topNum = minHeap.GetRoot().value;

            if (m_listOri[i] > topNum) //这里不能>=,因为是最小堆,只有大于头节点才插入,除头节点外,子节点都是比头节点大
            {
                minHeap.PopRoot();
                minHeap.Push(new Node(m_listOri[i]));
            }
        }
       
        for (int i = m_top-1; i >= 0 ; i--)
        {
            Debug.Log(minHeap.items[i].value);
        }
    }

    void DataInit()
    {

        //for (int i = 0; i < m_count; i++)
        //{
        //    int num = UnityEngine.Random.Range(0, m_count);
        //    m_listOri.Add(num);
        //}

        int[] buf = new int[m_count] { 5, 5, 1, 1, 9, 9, 2, 2, 3, 3 };
        m_listOri.AddRange(buf);
        
    }
}

测试输出

源码

https://github.com/luoyikun/UnityForTest TestTopK场景

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 时间复杂度
  • 堆排序
  • TopK
  • 测试输出
  • 源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档